【发布时间】:2020-07-22 14:53:48
【问题描述】:
我有一个模型,用户,其中主要的唯一字段是电子邮件。我有一个单独的组织模型,它允许用户通过多对多映射映射到组织。
如果用户有现有的电子邮件但没有组织关联,我希望序列化程序允许创建用户(组织来自发出请求的用户,因此不在有效负载中)。
标准的 ModelSerializer 包括对 to_internal_value() 中的字段的检查。因此,我试图像这样覆盖它:
def to_internal_value(self, data):
"""
Dict of native values <- Dict of primitive datatypes.
"""
fields = self._writable_fields
for field in fields:
validate_method = getattr(self, 'validate_' + field.field_name, None)
primitive_value = field.get_value(data)
try:
if validate_method == self.validate_email:
if User.objects.filter(email=primitive_value).exists():
if not self.active_organization.members.filter(email=primitive_value).exists():
continue
else:
validated_value = field.run_validation(primitive_value)
if validate_method is not None:
validated_value = validate_method(validated_value)
except ValidationError as exc:
errors[field.field_name] = exc.detail
except DjangoValidationError as exc:
errors[field.field_name] = get_error_detail(exc)
except SkipField:
pass
else:
set_value(ret, field.source_attrs, validated_value)
return super().to_internal_value(data)
这可行,但是如果对象在用户和组织中已有记录,则返回的错误不能正确映射为字典。例如,验证错误显示如下:
[ErrorDetail(string='User with this Email already exists.', code='unique')]
而不是它应该显示的内容:
{'email': [ErrorDetail(string='User with this Email already exists.', code='unique')]}
我通过覆盖该方法并尝试了我的自定义调用代码与原始代码进行了测试,它复制了上述发现:
def to_internal_value(self, data):
"""
Dict of native values <- Dict of primitive datatypes.
"""
try:
print('trying custom')
for field in self._writable_fields:
if field.field_name == 'email':
print(field.run_validation)
validated_value = field.run_validation(field.get_value(data))
except Exception as e:
print('error custom')
print(str(e))
try:
print('Trying original')
value = super().to_internal_value(data)
except Exception as e:
print('Exception - original')
print(str(e))
输出:
trying custom
<bound method CharField.run_validation of EmailField(max_length=254, validators=[<UniqueValidator(queryset=User.objects.all())>])>
error custom
[ErrorDetail(string='User with this Email already exists.', code='unique')]
Trying original
Exception - original
{'email': [ErrorDetail(string='User with this Email already exists.', code='unique')]}
谁能帮我理解为什么会这样?我真的不知道这是怎么发生的。
【问题讨论】:
-
你想如何使用已经存在的电子邮件创建用户?如果您的用户模型上有电子邮件 unique=True,那是不可能的。
-
这就是我尝试这个的原因。基本上我检查这个 to_internal_value() 调用中是否已经存在用户。如果他们确实 && 他们存在于组织中,我想返回正常的失败消息。如果它们仅作为电子邮件而不是组织存在,则数据将被馈送到 create() 方法,在该方法中我不创建电子邮件而是将它们添加到组织中:Organization.members.add(User.objects.get(email=电子邮件))。奇怪的是,当我覆盖 to_internal_value 方法时,错误不会作为以“电子邮件”为键的字典返回。
-
下半天我会帮你的。基本上尝试在序列化程序中使用 validate_email 方法(您可以在其中验证电子邮件,不要覆盖 to_internal_value 方法!),并尝试使用 self.context['request'].user (in serializer) .. 获得活跃的组织。
标签: python-3.x django django-rest-framework