I want to update records that are related with foreign Keys or related by any means. I know how to update single model records but I am not able to do the same in case of related models.
My Models :
class UserProfile(models.Model):
user = models.OneToOneField(User)
subject = models.ManyToManyField('Subjects')
phone = models.CharField(max_length=20)
address = models.TextField()
def __unicode__(self):
return self.user.username
class Subjects(models.Model):
name = models.CharField(max_length=100)
code = models.IntegerField()
def __unicode__(self):
return self.name
My serializers :
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = (
'id',
'first_name',
'username',
'email',
'is_active',
)
class SubjectSerializer(serializers.ModelSerializer):
class Meta:
model = Subjects
fields = (
'name',
'code',
)
class UserProfileSerializer(serializers.ModelSerializer):
user = UserSerializer()
subject = SubjectSerializer(many=True)
class Meta:
model = UserProfile
fields = (
'user',
'subject',
'phone',
'address',
)
Views :
class UserProfileList(viewsets.ModelViewSet):
serializer_class = UserProfileSerializer
queryset = UserProfile.objects.all()
urls
router.register(r'api/user/profile', UserProfileList)
I can see the first record as /api/user/profile/1/
But when I'll try to update record from Browsable Rest Api it gives me the error user with same username already exist.
Edit :
I want to update UserProfile
Model using UserProfileSerializer
. Simple create new records , Update existing one and delete.
You do have a constraint the username that makes it impossible to create again.
You need to remove it by altering validators UserSerializer.username
.
Make sure you don't remove others constraints by printing the serializer:
>>> print(UserSerializer())
>>> UserSerializer():
id = IntegerField(label='ID', read_only=True)
first_name = CharField(allow_blank=True, max_length=30, required=False)
username = CharField(help_text='Required. 30 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=30, validators=[<django.core.validators.RegexValidator object>, <UniqueValidator(queryset=User.objects.all())>])
email = EmailField(allow_blank=True, label='Email address', max_length=254, required=False)
is_active = BooleanField(help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', label='Active', required=False)
As you can notice, we do have a UniqueValidator
on the username as well as a RegexValidator
You'll need to alter the class:
from django.core import validators
from django.utils.translation import ugettext_lazy as _
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = (
'id',
'first_name',
'username',
'email',
'is_active',
)
extra_kwargs = {
'username': {
'validators': [
validators.RegexValidator(
r'^[\w.@+-]+$',
_('Enter a valid username. This value may contain only '
'letters, numbers ' 'and @/./+/-/_ characters.')
),]
}
}
Note that the validator here is taken out of the Django definition of that field (https://github.com/django/django/blob/master/django/contrib/auth/models.py#L309)
Now if you print again the serializer you should see that the unique constraint is removed:
>>> print(UserSerializer())
>>> UserSerializer():
id = IntegerField(label='ID', read_only=True)
first_name = CharField(allow_blank=True, max_length=30, required=False)
username = CharField(help_text='Required. 30 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=30, validators=[<django.core.validators.RegexValidator object>])
email = EmailField(allow_blank=True, label='Email address', max_length=254, required=False)
is_active = BooleanField(help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', label='Active', required=False)