Django REST Framework - 使用 FK 将对象更新为具有唯一字段的模型
Django REST Framework - Update object with FK to a model with unique field
我有以下型号:
# models.py
class NPSUser(AbstractBaseUser, TimeStampedModel):
email = models.EmailField(unique=True)
first_name = models.CharField(max_length=40, blank=True)
last_name = models.CharField(max_length=40, blank=True)
class Account(models.Model):
user = models.OneToOneField(NPSUser, related_name='%(class)s_role', primary_key=True)
class Meta:
abstract = True
class Director(Account):
tenant = models.OneToOneField(Tenant, related_name='director')
使用相应的序列化程序:
# serializers.py
class NPSUserSerializer(serializers.ModelSerializer):
password = serializers.CharField(write_only=True, required=False)
confirm_password = serializers.CharField(write_only=True, required=False)
class Meta:
model = NPSUser
fields = ('id', 'email', 'created', 'modified', 'first_name',
'last_name', 'password', 'confirm_password', 'director_role',
'manager_role', 'employee_role', 'projectmanager_role',
'collector_role')
read_only_fields = ('id', 'created', 'modified', 'director_role',
'manager_role', 'employee_role', 'projectmanager_role',
'collector_role')
def create(self, validated_data):
return NPSUser.objects.create(**validated_data)
def update(self, instance, validated_attrs):
instance.email = validated_attrs.get('email', instance.email)
instance.first_name = validated_attrs.get('first_name', instance.first_name)
instance.last_name = validated_attrs.get('last_name', instance.last_name)
instance.save()
# password validation here...
return instance
class DirectorSerializer(serializers.ModelSerializer):
user = NPSUserSerializer()
class Meta:
model = Director
def create(self, validated_data):
user_data = validated_data.pop('user')
user = NPSUser(**user_data)
user.set_password(user_data['password'])
user.save()
director = Director.objects.create(user=user, **validated_data)
return director
我在 views.py 中使用 viewset.ModelViewSet
并且如果我已经在数据库中有一个名为 'John' 和 'email@gmail.com' 电子邮件的用户,并且我发出了 PUT 请求通过其 Director 关系更新 NPSUser,如下所示:PUT /api/v1/directors/1/ {id: 1, tenant: 1, user: {id: 1, first_name: 'Jane', last_name: 'King', email: 'email@gmail.com'}}
服务器返回以下错误:{"user":{"email":["This field must be unique."]}}
,这意味着 serializer.is_valid()
未通过。
正确的问题是: 如何使用序列化程序从另一个与 NPSUser 具有关系字段的对象更新具有 unique=True
字段的 NPSUser 对象Django REST 框架?
我刚刚遇到了同样的问题。我的解决方案是以这种方式超载电子邮件字段:
email = serializers.EmailField(unique=False)
我实现了自己的验证逻辑,以避免在定义 def validate(self, data)
方法的序列化程序中出现重复的电子邮件。在这种验证方法中,我检查数据字典中是否有 id,如果有,我会验证电子邮件是否相同或是否已更改。我的代码是这样的。
class ClientUserCreateUpdateSerializer(serializers.ModelSerializer):
id = serializers.IntegerField(required=False)
email = serializers.EmailField(required=False)
def validate(self, data):
client_user_id = int(data.get('id', -1))
is_update = client_user_id > 0
if not is_update:
if not 'email' in data:
raise serializers.ValidationError({'email': [_('This field is required')]})
elif ClientUser.objects.filter(is_active=True, email=data['email']).exists():
raise serializers.ValidationError({'email': [_('The e-mail address \"%(email)s\" is already being used') % {'email': data.get('email')}]})
elif 'email' in data and ClientUser.objects.get(id=data['id']).email != data['email']:
if ClientUser.objects.filter(is_active=True, email=data['email']).exists():
raise serializers.ValidationError({'email': [_('The e-mail address \"%(email)s\" is already being used') % {'email': data.get('email')}]})
return data
class Meta:
model = ClientUser
fields = ('id', 'first_name', 'last_name', 'email')
希望对您有所帮助。
我有以下型号:
# models.py
class NPSUser(AbstractBaseUser, TimeStampedModel):
email = models.EmailField(unique=True)
first_name = models.CharField(max_length=40, blank=True)
last_name = models.CharField(max_length=40, blank=True)
class Account(models.Model):
user = models.OneToOneField(NPSUser, related_name='%(class)s_role', primary_key=True)
class Meta:
abstract = True
class Director(Account):
tenant = models.OneToOneField(Tenant, related_name='director')
使用相应的序列化程序:
# serializers.py
class NPSUserSerializer(serializers.ModelSerializer):
password = serializers.CharField(write_only=True, required=False)
confirm_password = serializers.CharField(write_only=True, required=False)
class Meta:
model = NPSUser
fields = ('id', 'email', 'created', 'modified', 'first_name',
'last_name', 'password', 'confirm_password', 'director_role',
'manager_role', 'employee_role', 'projectmanager_role',
'collector_role')
read_only_fields = ('id', 'created', 'modified', 'director_role',
'manager_role', 'employee_role', 'projectmanager_role',
'collector_role')
def create(self, validated_data):
return NPSUser.objects.create(**validated_data)
def update(self, instance, validated_attrs):
instance.email = validated_attrs.get('email', instance.email)
instance.first_name = validated_attrs.get('first_name', instance.first_name)
instance.last_name = validated_attrs.get('last_name', instance.last_name)
instance.save()
# password validation here...
return instance
class DirectorSerializer(serializers.ModelSerializer):
user = NPSUserSerializer()
class Meta:
model = Director
def create(self, validated_data):
user_data = validated_data.pop('user')
user = NPSUser(**user_data)
user.set_password(user_data['password'])
user.save()
director = Director.objects.create(user=user, **validated_data)
return director
我在 views.py 中使用 viewset.ModelViewSet
并且如果我已经在数据库中有一个名为 'John' 和 'email@gmail.com' 电子邮件的用户,并且我发出了 PUT 请求通过其 Director 关系更新 NPSUser,如下所示:PUT /api/v1/directors/1/ {id: 1, tenant: 1, user: {id: 1, first_name: 'Jane', last_name: 'King', email: 'email@gmail.com'}}
服务器返回以下错误:{"user":{"email":["This field must be unique."]}}
,这意味着 serializer.is_valid()
未通过。
正确的问题是: 如何使用序列化程序从另一个与 NPSUser 具有关系字段的对象更新具有 unique=True
字段的 NPSUser 对象Django REST 框架?
我刚刚遇到了同样的问题。我的解决方案是以这种方式超载电子邮件字段:
email = serializers.EmailField(unique=False)
我实现了自己的验证逻辑,以避免在定义 def validate(self, data)
方法的序列化程序中出现重复的电子邮件。在这种验证方法中,我检查数据字典中是否有 id,如果有,我会验证电子邮件是否相同或是否已更改。我的代码是这样的。
class ClientUserCreateUpdateSerializer(serializers.ModelSerializer):
id = serializers.IntegerField(required=False)
email = serializers.EmailField(required=False)
def validate(self, data):
client_user_id = int(data.get('id', -1))
is_update = client_user_id > 0
if not is_update:
if not 'email' in data:
raise serializers.ValidationError({'email': [_('This field is required')]})
elif ClientUser.objects.filter(is_active=True, email=data['email']).exists():
raise serializers.ValidationError({'email': [_('The e-mail address \"%(email)s\" is already being used') % {'email': data.get('email')}]})
elif 'email' in data and ClientUser.objects.get(id=data['id']).email != data['email']:
if ClientUser.objects.filter(is_active=True, email=data['email']).exists():
raise serializers.ValidationError({'email': [_('The e-mail address \"%(email)s\" is already being used') % {'email': data.get('email')}]})
return data
class Meta:
model = ClientUser
fields = ('id', 'first_name', 'last_name', 'email')
希望对您有所帮助。