Django-使用外键进行序列化程序验证

时间:2019-01-21 07:09:48

标签: python django

我有两个模型来代表一个学生及其联系人。

class Contact(models.Model):
  phone_num = models.IntegerField()
  email = models.TextField()

class Student(models.Model):
  name = models.TextField()
  age = models.IntegerField()
  contact = models.ForeignKey(Contact)

我需要返回的数据结构:

{
  name: 'Peter',
  age: 18,
  contact: {
    phone_num: 1234567890,
    email: 'peter123@gmail.com'
  }
}

在我的发布请求中,我收到json格式的数据:

{
  name: 'Mary',
  age: 19,
  phone_num: 9876543210,
  email: mary987@gmail.com
}

我正在尝试创建用于数据验证的序列化器。

联系方式:

class ContactSerializer(ModelSerializer):
  class Meta:
    model = Contact
    exclude = ('id',)

学生:

class StudentSerializer(ModelSerializer):
  contact = ContactSerializer()

  class Meta:
    model = Student
    exclude = ('id',)

我试图将请求后的数据放入序列化器中,并检查其是否有效。

data = {
  name: 'Mary',
  age: 19,
  phone_num: 9876543210,
  email: mary987@gmail.com
}
student = StudentSerializer(data=data)
student.is_valid()
// It returns false.
print(student.errors)
// Print: {'contact': [ErrorDetail(string='This field is required.', code='required')]}

如何使用此数据结构验证我的数据?

3 个答案:

答案 0 :(得分:0)

它表示contact是必填字段。如果您想在数据中传递联系人ID,
像下面这样写,

class StudentSerializer(ModelSerializer):
  contact = ContactSerializer(read_only=True)

  class Meta:
    model = Student
    exclude = ('id',)

  def create(self, attrs):
    instance = super(StudentSerializer, self).create(attrs)
    instance.contact = self.initial_data.get('contact')
    instance.save()

答案 1 :(得分:0)

方法1

简单的解决方案是将输入json有效负载的结构更改为嵌套形式,例如

{
  "name": "Peter",
  "age": 18,
  "contact": {
    "phone_num": 1234567890,
    "email": "peter123@gmail.com"
  }
}

方法2

如下更改您的序列化器,

class StudentSerializer(serializers.ModelSerializer):
    contact = ContactSerializer(read_only=True)
    phone_num = serializers.IntegerField(write_only=True)
    email = serializers.EmailField(write_only=True)

    def create(self, validated_data):
        contact = Contact.objects.create(phone_num=validated_data.pop('phone_num'),
                                         email=validated_data.pop('email'))
        return Student.objects.create(**validated_data, contact=contact)

    class Meta:
        model = Student
        exclude = ('id',)

为您的序列化器添加两个额外的字段,phone_numemail作为 write_only=True ,并使您的ContactSerializer仅准备就绪,这将绕过序列化程序验证。
因此,我们需要一个自定义的创建方法。因此,请覆盖 create() 方法。

示例(方法2)

In [3]: data = { 
   ...:     'name': 'Mary', 
   ...:     'age': 19, 
   ...:     'phone_num': 9876543210, 
   ...:     'email': 'mary987@gmail.com' 
   ...: }                                                                                                                                                                                                          

In [4]: student = StudentSerializer(data=data)                                                                                                                                                                     

In [5]: student.is_valid()                                                                                                                                                                                         
Out[5]: True

In [6]: student.save() # creates new student method                                                                                                                                                                
Out[6]: <Student: Student object>

In [7]: student.data                                                                                                                                                                                               
Out[7]: {'contact': OrderedDict([('phone_num', 9876543210), ('email', 'mary987@gmail.com')]), 'name': 'Mary', 'age': 19}

答案 2 :(得分:0)

您必须首先在联系表中创建数据,因为学生将其用作外键。 方便的方法之一就是以这种格式接收json

0 0 0

在您的views.py

`

{
  name: 'Mary',
  age: 19,
  contact: {
           phone_num: 9876543210,
           email: mary987@gmail.com
    }
}

`

在serializers.py

context = {
    phone_num: 9876543210,
    email: mary987@gmail.com
}

serializer = ContactSerializer(data=request.data['contact'))
if serializer.is_valid():
    serializer.save     #saved contact data first

data = request.data
data['contact']=serializer.data['id']

serializer = StudentSerializer(data=data)
if serializer.is_valid():
    serializer.save
return Response(serializer.data)

您要隐藏ID字段有什么具体说明吗?