17

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
  • Can you clarify? Is the issue that you want to be able to get the nested serializers when doing gets, but when posting, you just want to pass record IDs for existing objects? Commented Feb 22, 2016 at 4:29
  • When I use the browsable API to post a new EquipmentInfo record, I get an error saying equipment_type and manufacturer_name already exist. That is expected because I already have EquipmentType and EquipmentManufacturer records. But now I would like to add a new EquipmentInfo record. So in a way, yes, I just want to pass the record IDs for existing objects. Ideally, whatever device sending the information would not have to know the value of the id field and just be able to use equipment_type and manufacturer_name. Does that help clarify? Commented Feb 22, 2016 at 4:42

2 Answers 2

5

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.

Sign up to request clarification or add additional context in comments.

Comments

4

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 !

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.