DRF:如何在保存到数据库之前更改模型字段的值

Jek*_*son 7 python django django-rest-framework

如果我需要在保存到数据库之前更改一些字段值,因为我认为模型方法clear()是合适的。但尽管我竭尽全力,还是无法给他打电话。

例如,我需要将字段email设置为小写,将字段nda设置为null

模型.py

class Vendors(models.Model):

    nda = models.DateField(blank=True, null=True)
    parent = models.OneToOneField('Vendors', models.DO_NOTHING, blank=True, null=True)

    def clean(self):
        if self.nda == "":
            self.nda = None

class VendorContacts(models.Model):
    ....
    vendor = models.ForeignKey('Vendors', related_name='contacts', on_delete=models.CASCADE)
    email = models.CharField(max_length=80, blank=True, null=True, unique=True)

    def clean(self):
        if self.email:
            self.email = self.email.lower()
Run Code Online (Sandbox Code Playgroud)

序列化器.py

class VendorContactSerializer(serializers.ModelSerializer):
    class Meta:
        model = VendorContacts
        fields = (
                  ...
                  'email',)

class VendorsSerializer(serializers.ModelSerializer):
    contacts = VendorContactSerializer(many=True)

    class Meta:
        model = Vendors
        fields = (...
                  'nda',
                  'contacts',
                  )

    def create(self, validated_data):
        contact_data = validated_data.pop('contacts')
        vendor = Vendors.objects.create(**validated_data)
        for data in contact_data:
            VendorContacts.objects.create(vendor=vendor, **data)

        return vendor
Run Code Online (Sandbox Code Playgroud)

视图.py

class VendorsCreateView(APIView):
    """Create new vendor instances from form"""
    permission_classes = (permissions.AllowAny,)
    serializer_class = VendorsSerializer

    def post(self, request, *args, **kwargs):
        serializer = VendorsSerializer(data=request.data)
        try:
            serializer.is_valid(raise_exception=True)
            serializer.save()
        except ValidationError:
            return Response({"errors": (serializer.errors,)},
                            status=status.HTTP_400_BAD_REQUEST)
        else:
            return Response(request.data, status=status.HTTP_200_OK)
Run Code Online (Sandbox Code Playgroud)

据我从文档中了解到

验证模型序列化器时,Django Rest Framework 序列化器不会调用 Model.clean

在处理这个问题时,我找到了两种方法来解决。1. 在序列化器中使用自定义方法。对于我的情况,它看起来像

类 VendorsSerializer(serializers.ModelSerializer): 联系人 = VendorContactSerializer(many=True)

class Meta:
    model = Vendors
    fields = (...
              'nda',
              'contacts',
              )

def create(self, validated_data):
    contact_data = validated_data.pop('contacts')
    vendor = Vendors.objects.create(**validated_data)
    for data in contact_data:
        VendorContacts.objects.create(vendor=vendor, **data)

    return vendor

def validate(self, attrs):
    instance = Vendors(**attrs)
    instance.clean()
    return attrs
Run Code Online (Sandbox Code Playgroud)
  1. 使用full_clean()方法。对我来说,它看起来像

类 VendorsSerializer(serializers.ModelSerializer): 联系人 = VendorContactSerializer(many=True)

class Meta:
    model = Vendors
    fields = (...
              'nda',
              'contacts',
              )

def create(self, validated_data):
    contact_data = validated_data.pop('contacts')
    vendor = Vendors(**validated_data)
    vendor.full_clean()
    vendor.save()
    for data in contact_data:
        VendorContacts.objects.create(vendor=vendor, **data)

    return vendor
Run Code Online (Sandbox Code Playgroud)

但在这两种情况下,都不会调用 clean() 方法。我真的不明白我做错了什么。

MK *_*tel 5

对于 DRF,您可以在保存之前更改序列化器,如下所示...

首先,您应该检查 是否serializer有效,如果有效,valid则更改 所需的对象serializer,然后保存该serializer.

if serializer.is_valid():
    serializer.object.user_id = 15  # For example 
    serializer.save() 
Run Code Online (Sandbox Code Playgroud)

更新! 视图.py

class VendorsCreateView(APIView):
    """Create new vendor instances from form"""
    permission_classes = (permissions.AllowAny,)
    serializer_class = VendorsSerializer

    def post(self, request, *args, **kwargs):
        data = request.data
        if data['nda'] == '':
            data['nda'] = None
        for contact in data['contacts']:
            if contact['email']:
                print(contact['email'])
                contact['email'] = contact['email'].lower()
        serializer = VendorsSerializer(data=request.data)
        try:
            serializer.is_valid(raise_exception=True)
            serializer.save()
        except ValidationError:
            return Response({"errors": (serializer.errors,)},
                            status=status.HTTP_400_BAD_REQUEST)
Run Code Online (Sandbox Code Playgroud)


Ale*_*xKh 5

就我而言,我遇到了同样的问题,但通过验证功能,我使用了下面的方法,它对我有用(不排除上面找到的方法):

class CustomViewClass(APIView):

    def post(self, request, format=None):
        
        prepared_data_variable = 'some data in needed format'
        serializer = CustomSerializer(data=request.data)
    
        if serializer.is_valid(self):
            serializer.validated_data['field_name'] = prepared_data_variable
            serializer.save()
            return Response(data=serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
Run Code Online (Sandbox Code Playgroud)

该字符串是我的解决方案的关键serializer.validated_data['field_name'] = prepared_data_variable