Django REST – Crea un objeto con clave externa usando serializadores

Soy un poco nuevo para Django y Django-REST, así que por favor tengan paciencia conmigo. Tal vez la respuesta esté en la documentación, así que si me la perdí, pido disculpas por adelantado.

Objetivo: me gustaría crear un objeto EquipmentInfo cuyos atributos incluyan claves externas preexistentes (EquipmentType y EquipmentManufacturer).

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

Suponiendo que ya tengo creados los objetos EquipmentType y EquipmentManufacturer relevantes, me gustaría agregar otro objeto EquipmentInfo. ¿Cuál es la forma adecuada de configurar mi serializador EquipmentInfo para que pueda pasar información como

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

o mejor:

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

Cualquier ayuda es apreciada.

El uso de serializadores nesteds hace que sea realmente difícil para las publicaciones (si es que incluso funciona, ya que no solía funcionar), y dados sus modelos simples, recomendaría simplemente eliminarlos.

Te recomendaré agregar APIs para

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

(o cualquier nombre que quieras usar). Los type y manufacturer deben ser vistas de vainilla y usar sus serializadores existentes.

Para info , quite los dos serializadores nesteds:

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

Después de eso, deberías poder hacer publicaciones usando:

 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 } 

En mi caso, me gusta hacer que los GET sean más convenientes, así que agrego campos de solo lectura para devolver un nombre (o incluso todo el registro serializado):

 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 

Espero que esto ayude.

También he enfrentado el problema y lo he resuelto, el siguiente es mi paso, espero que sea útil 1. Modelo de empresa y modelo de contacto de la siguiente manera:

 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.Creo un nuevo serializador llamado CompanyReferenceSerializer , y 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. Visualice lo siguiente, en el backend, obtengo el objeto Named company_instance acuerdo con el ‘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) 

y he logrado insertar un registro en la empresa_contacto, ¡espero que pueda ayudarte!