【问题标题】:Django REST - Create object with foreign key using serializersDjango REST - 使用序列化程序创建具有外键的对象
【发布时间】:2016-02-22 00:04:52
【问题描述】:

我对 Django 和 Django-REST 有点陌生,所以请多多包涵。也许答案在文档中,所以如果我错过了,请提前道歉。

目标:我想创建一个 EquipmentInfo 对象,其属性包括预先存在的外键(EquipmentType 和 EquipmentManufacturer)。

models.py

class EquipmentType(models.Model):
    equipment_type = models.CharField(verbose_name="Equipment Type", max_length=50, unique=True)

    def __unicode__(self):
        return self.equipment_type


class EquipmentManufacturer(models.Model):

    manufacturer_name = models.CharField(verbose_name="Manufacturer Name", max_length=50, unique=True)

    def __unicode__(self):
        return self.manufacturer_name


class EquipmentInfo(models.Model):

    equipment_type = models.ForeignKey(EquipmentType, verbose_name="Equipment Type")
    part_identifier = models.CharField(verbose_name="Machine ID (alias)", max_length=25)
    manufacturer_name = models.ForeignKey(EquipmentManufacturer, verbose_name="Manufacturer Name")
    serial_number = models.CharField(verbose_name="Serial Number", max_length=25)
    date_of_manufacture = models.DateField(verbose_name="Date of Manufacture", default=date.today)
    is_active = models.BooleanField(verbose_name="Is Active", default=True)

    def __unicode__(self):
        return self.part_identifier

序列化器.py

class EquipmentTypeSerializer(serializers.ModelSerializer):
    class Meta:
        model = EquipmentType
        fields = ('id', 'equipment_type',)

class EquipmentManufacturerSerializer(serializers.ModelSerializer):
    class Meta:
        model = EquipmentManufacturer
        fields = ('id', 'manufacturer_name',)

class EquipmentInfoSerializer(serializers.ModelSerializer):
    class Meta:
        model = EquipmentInfo
        fields = ('id', 'equipment_type', 'part_identifier', 'manufacturer_name','serial_number', 'date_of_manufacture', 'is_active')

    equipment_type = EquipmentTypeSerializer(many=False)
    manufacturer_name = EquipmentManufacturerSerializer(many=False)

    def create(self, validated_data):
        equipment_type = validated_data.pop('equipment_type')
        manufacturer_name = validated_data.pop('manufacturer_name')
        equipment_info = EquipmentInfo.objects.create(**validated_data)
        return equipment_info

假设我已经创建了相关的 EquipmentType 和 EquipmentManufacturer 对象,我想添加另一个 EquipmentInfo 对象。什么是设置我的 EquipmentInfo 序列化程序的合适方法,以便我可以传递诸如

之类的信息
{
 "equipment_type":{
  "equipment_type":"already_created",
 },
 "part_identifier":"something_new",
 "manufacturer_name":{
  "manufacturer_name":"already_created"
 },
 "serial_number":"WBA1",
 "date_of_manufacture": "1900-01-01",
 "is_active":true
}

甚至更好:

{
 "equipment_type":"already_created",
 "part_identifier":"something_new",
 "manufacturer_name":"already_created",
 "serial_number":"WBA1",
 "date_of_manufacture": "1900-01-01",
 "is_active":true
}

感谢任何帮助。

【问题讨论】:

  • 你能澄清一下吗?问题是您希望在获取时能够获取嵌套的序列化程序,但在发布时,您只想传递现有对象的记录 ID?
  • 当我使用可浏览 API 发布新的 EquipmentInfo 记录时,我收到一条错误消息,指出 equipment_typemanufacturer_name 已经存在。这是意料之中的,因为我已经有 EquipmentTypeEquipmentManufacturer 记录。但现在我想添加一个新的EquipmentInfo 记录。所以在某种程度上,是的,我只想传递现有对象的记录 ID。理想情况下,发送信息的任何设备都不必知道 id 字段的值,而只需能够使用equipment_typemanufacturer_name。这有助于澄清吗?

标签: python django django-rest-framework


【解决方案1】:

我也遇到了这个问题,已经解决了,下面是我的步骤,希望对你有帮助 1.公司型号和联系人型号如下:

class Company(models.Model):
    Company_Name = models.CharField(u'Company Name',max_length=255, default="")
    Modified_By = models.CharField(u'Modified By',max_length=255, default="")



class Company_Contact(models.Model):
     Company = models.ForeignKey(Company)
     Last_Name = models.CharField(u'Last Name',max_length=255, default="")
     First_Name = models.CharField(u'First Name',max_length=255, default="")

2.我创建了一个名为CompanyReferenceSerializercompany_contact的新序列化程序

class CompanyReferenceSerializer(serializers.ModelSerializer):
class Meta:
    model = Company
    fields = ['id', 'Company_Name', 'Company_Name_SC']





class CompanyContactSerializer(serializers.ModelSerializer):
   Company =  CompanyReferenceSerializer()
class Meta:
    model = Company_Contact
    fields = ['Company', 'Last_Name','First_Name']
    extra_kwargs = {
        'Company': {'allow_null': True, 'required': False},
        'Last_Name': {'allow_null': True, 'allow_blank': True, 'required': False}, 
        'First_Name': {'allow_null': True, 'required': False, 'allow_blank': True},     
    }

3.Viewset如下,在后台,我根据'company_id'得到了对象Namedcompany_instance

class CompanyContactViewSet(viewsets.ModelViewSet):
     serializer_class = CompanyContactSerializer
def create(self, validated_data):
    serializer = self.get_serializer(data=self.request.data)
    company_id_for_contact =  self.request.data.pop('Company_id')
    company_instance = Company.objects.filter(id=company_id_for_contact).first()
    if not serializer.is_valid():
        print serializer.errors
    data = serializer.validated_data
    serializer.save(Company=company_instance)
    headers = self.get_success_headers(serializer.data)
    return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers) 

我成功在company_contact中插入了一条记录,希望对你有帮助!

【讨论】:

  • 这很有帮助。谢谢。
【解决方案2】:

使用嵌套的序列化器让帖子变得非常困难(如果它甚至可以工作,因为它以前不工作),并且鉴于您的简单模型,我建议您删除它们。

我会推荐你​​为

添加 API
/api/v1/type
/api/v1/manufacturer
/api/v1/info

(或您想使用的任何名称)。 typemanufacturer 应该是普通视图并使用您现有的序列化程序。

对于info,移除两个嵌套的序列化器:

class EquipmentInfoSerializer(serializers.ModelSerializer):
    class Meta:
        model = EquipmentInfo
        fields = ('id', 'equipment_type', 'part_identifier', 'manufacturer_name','serial_number', 'date_of_manufacture', 'is_active')

之后,您应该可以使用以下方式发帖:

data = {
  "equipment_type": 5,  # The ID of the equipment type record
  "part_identifier":"something_new",
  "manufacturer_name": 10 # The ID of the manufacturer record
  "serial_number":"WBA1",
  "date_of_manufacture": "1900-01-01",
  "is_active":true
}

就我而言,我确实喜欢让 GET 更方便,因此我添加了只读字段以返回名称(甚至是整个序列化记录):

class EquipmentInfoSerializer(serializers.ModelSerializer):
    type_name = serializers.SerializerMethodField(read_only=True)

    class Meta:
        model = EquipmentInfo
        fields = ('id', 'equipment_type', 'part_identifier', 'manufacturer_name','serial_number', 'date_of_manufacture', 'is_active')

    def get_type_name(self, obj):
       return obj.equipment_type.equipment_type

希望这会有所帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-08-06
    • 1970-01-01
    • 1970-01-01
    • 2015-08-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多