Python 3.x Django Rest框架-到\u内部\u值错误不一致
我有一个模型,User,其中主要的唯一字段是email。我有一个单独的组织模型,允许用户通过多对多映射映射到组织 我希望序列化程序允许用户创建,如果他们有一个现有的电子邮件,但没有组织关联(组织是从用户提出请求,所以不在有效负载) 标准ModelSerializer包含对to_internal_value()中字段的检查。因此,我试图这样覆盖它:Python 3.x Django Rest框架-到\u内部\u值错误不一致,python-3.x,django,django-rest-framework,Python 3.x,Django,Django Rest Framework,我有一个模型,User,其中主要的唯一字段是email。我有一个单独的组织模型,允许用户通过多对多映射映射到组织 我希望序列化程序允许用户创建,如果他们有一个现有的电子邮件,但没有组织关联(组织是从用户提出请求,所以不在有效负载) 标准ModelSerializer包含对to_internal_value()中字段的检查。因此,我试图这样覆盖它: def to_internal_value(self, data): """ D
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)
输出:
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')]}
尝试自定义
错误自定义
[ErrorDetail(string='User with this Email已存在',code='unique')]
尝试原创
例外-原件
{'email':[ErrorDetail(string='User with this email已经存在',code='unique')]}
有人能帮我理解为什么会这样吗?我真的很想知道这是怎么发生的。我无法弄清楚为什么当我从底层ModelSerializer复制代码而不是调用super()时,
到内部值(self,data)
生成的错误会发生变化。然而,我确实找到了一种黑客的解决方法
因为我事先去掉了所有其他相关的信息(嵌套序列化程序),所以我真的很担心电子邮件。因此,我遍历了两次_writable_字段:第一次查找不在组织中的现有电子邮件。如果这些条件为真,我将返回一个dictionary并继续执行create()方法。如果他们失败了,我叫超级。到目前为止,这似乎是可行的。这是我的简化课程
def to_internal_value(self, data):
"""
Dict of native values <- Dict of primitive datatypes.
"""
try:
for field in self._writable_fields:
if field.field_name == 'email':
primitive_value = field.get_value(data)
validator = EmailValidator()
validator(primitive_value)
if User.objects.filter(email=primitive_value).exists():
if not self.active_organization.members.filter(email=primitive_value).exists():
self.email_already_exists = True
return {'email': primitive_value}
except:
pass
return super().to_internal_value(data)
def到_内部_值(自身,数据):
"""
本机值的Dict您希望如何创建已存在电子邮件的用户?如果您的用户模型上有email unique=True,则不可能。这就是我尝试此操作的原因。基本上,我检查用户是否已存在于此to_internal_value()中call.If they do&&它们存在于组织中,我希望返回正常的失败消息。如果它们仅作为电子邮件而不是组织存在,则数据将被提供给create()方法,在该方法中,我不创建电子邮件,而是将它们添加到组织中:organization.members.add(User.objects.get(email=email))。奇怪的是,当我重写to_internal_value方法时,错误不会作为以“email”为键的字典返回。我会在接下来的半天里帮助你。基本上尝试在serializer中使用validate_email方法(在这里你可以验证email,不要重写to_internal_value方法!),并尝试使用self context['request'].user(在序列化程序中)…以获取活动组织。
def to_internal_value(self, data):
"""
Dict of native values <- Dict of primitive datatypes.
"""
try:
for field in self._writable_fields:
if field.field_name == 'email':
primitive_value = field.get_value(data)
validator = EmailValidator()
validator(primitive_value)
if User.objects.filter(email=primitive_value).exists():
if not self.active_organization.members.filter(email=primitive_value).exists():
self.email_already_exists = True
return {'email': primitive_value}
except:
pass
return super().to_internal_value(data)
class AdminUsersSerializer(serializers.ModelSerializer):
"""User serializer for the admin user view"""
groups = GenericGroupSerializer(source='group_set', many=True, required=False)
permission_sets = GenericPermissionSetSerializer(source='permissionset_set', many=True, required=False)
active_organization = None
email_already_exists = False
class Meta:
model = User
fields = ['pk', 'email', 'groups', 'permission_sets'] # , 'permissions']
def set_active_organization(self, organization):
self.active_organization = organization
def create(self, validated_data):
if not self.email_already_exists:
user = User.objects.create(
email=validated_data['email']
)
user.set_password(None)
user.save()
else:
user = User.objects.get(email=validated_data['email'])
return user
def to_internal_value(self, data):
"""
Dict of native values <- Dict of primitive datatypes.
"""
try:
for field in self._writable_fields:
if field.field_name == 'email':
primitive_value = field.get_value(data)
validator = EmailValidator()
validator(primitive_value)
if User.objects.filter(email=primitive_value).exists():
if not self.active_organization.members.filter(email=primitive_value).exists():
self.email_already_exists = True
return {'email': primitive_value}
except:
pass
return super().to_internal_value(data)
class AdminUsersViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = AdminUsersSerializer
permission_classes = [account_permissions.IsAdminRequired]
http_method_names = ['get', 'post']
active_organization = None
def create(self, request, *args, **kwargs):
self.active_organization = self.request.user.activeorganization.organization
groups = None
permission_sets = None
serializer = self.get_serializer(data=request.data)
serializer.set_active_organization(self.active_organization)
if 'groups' in serializer.initial_data:
if serializer.initial_data.get('groups'):
groups = serializer.initial_data.pop('groups')
else:
serializer.initial_data.pop('groups')
if 'permission_sets' in serializer.initial_data:
if serializer.initial_data.get('permission_sets'):
permission_sets = serializer.initial_data.pop('permission_sets')
else:
serializer.initial_data.pop('permission_sets')
# Normal method functions
serializer.is_valid(raise_exception=True)
self.perform_create(serializer)
headers = self.get_success_headers(serializer.data)
# Created user
user = User.objects.get(email=serializer.data['email'])
# Add user to organization
self.active_organization.members.add(user)
# Make sure to format the ajax groups data properly
if groups:
try:
group = Group.objects.get(
id=groups,
organization=self.active_organization
)
group.members.add(user)
except:
pass
if permission_sets:
try:
permission_set = PermissionSet.objects.get(
id=permission_sets,
organization=self.active_organization
)
permission_set.members.add(user)
except:
pass
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
def get_queryset(self):
return self.queryset.filter(
userorganizationmembership__organization=self.request.user.activeorganization.organization
).all()