Django REST - Create object with foreign key using

2019-02-17 06:02发布

I'm a little new to Django and Django-REST so please bear with me. Perhaps the answer is in the documentation, so if I missed it, apologies in advance.

Goal: I would like to create an EquipmentInfo object whose attributes include pre-existing foreign keys (EquipmentType and 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

serializers.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

Assuming I already have relevant EquipmentType and EquipmentManufacturer objects created, I would like to add another EquipmentInfo object. What is the appropriate way to set up my EquipmentInfo serializer so that I can pass in information such as

{
 "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
}

or even better:

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

Any help is appreciated.

2条回答
唯我独甜
2楼-- · 2019-02-17 06:38

Using nested serializers makes it really hard for posts (if it even works, as it didn't used to work), and given your simple models, I would recommend just removing them.

I will recommend you add APIs for

/api/v1/type
/api/v1/manufacturer
/api/v1/info

(or whatever names you want to use). The type and manufacturer ones should be vanilla views and using your existing serializers.

For info, remove the two nested serializers:

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

After that, you should be able to do post using:

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
}

In my case, I do like making it the GETs more convenient so I add read-only fields to return a name (or even the whole serialized record):

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

Hope this helps.

查看更多
Lonely孤独者°
3楼-- · 2019-02-17 06:38

I have also faced the problem ,and have solved it ,the following is my step ,hope it will be helpful 1.company Model and contact model as follows:

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.I create A New Serializer Named CompanyReferenceSerializer,and company_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 as follows,in the backend,I get the object Namedcompany_instanceaccording to the 'company_id'

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) 

and I success insert one record in the company_contact ,Hope it can help you !

查看更多
登录 后发表回答