Django Rest Framework — Справка по вложенному сериализатору — не удается назначить OrderedDict

#python #django #serialization #django-rest-framework

#python #django #сериализация #django-rest-framework

Вопрос:

Я работаю над созданием вложенного записываемого сериализатора для своего проекта и сталкиваюсь с препятствиями. Я следую фрагменту кода здесь DRF с возможностью записи вложенных сериализаторов, но я сталкиваюсь с этой ошибкой, когда пытаюсь отправить свою полезную нагрузку в конечную точку API через postman:

 Cannot assign "OrderedDict([('first_name', 'Mike'), ('last_name', 'Doe'), ('phone_number', '123-456-7890'), ('company_name', 'Trucking Company')])": "Load.primary_driver" must be a "Driver" instance.
 

По сути, в этом конкретном сценарии мне нужно иметь возможность создать объект «Load» (или, другими словами, объект отгрузки), а также создать объект «Driver», который связан с запросом «Load» one POST. Драйвер — это FK в модели нагрузки.

Models.py (модель загрузки находится в конце)

 class Broker(models.Model):
    id = models.AutoField(primary_key=True)
    first_name = models.CharField(max_length=50)
    last_name = models.CharField(max_length=50)
    e_mail = models.EmailField(max_length=50)
    company_name = models.CharField(max_length=50)
    phone_number = models.CharField(max_length=50)

    class Meta:
        db_table = "Broker"

class Employee(models.Model):
    id = models.AutoField(primary_key=True)
    first_name = models.CharField(max_length=50)
    last_name = models.CharField(max_length=50)
    e_mail = models.EmailField(max_length=50)
    phone_number = models.CharField(max_length=50)

    class Meta:
        db_table = "Employee"

class Delivery_Location(models.Model):
    id = models.AutoField(primary_key=True)
    street_address = models.CharField(max_length=50)
    city = models.CharField(max_length=30)
    state = models.CharField(max_length=20)
    zip_code = models.IntegerField()

    class Meta:
        db_table = "Delivery Location"

class Pickup_Location(models.Model):
    id = models.AutoField(primary_key=True)
    street_address = models.CharField(max_length=50)
    city = models.CharField(max_length=30)
    state = models.CharField(max_length=20)
    zip_code = models.IntegerField()

    class Meta:
        db_table = "Pickup Location"

class Driver(models.Model):
    id = models.AutoField(primary_key=True)
    first_name = models.CharField(max_length=100)
    last_name = models.CharField(max_length=100)
    phone_number = models.CharField(max_length=14)
    company_name = models.CharField(max_length=50)

    def __str__(self):
        return self.id

    class Meta:
        db_table = "Driver"

class Container(models.Model):
    id = models.AutoField(primary_key=True)
    container_number = models.CharField(max_length=15)

    class Meta:
        db_table = "Container"

class Load(models.Model):
    id = models.AutoField(primary_key=True)
    primary_driver = models.ForeignKey(Driver,blank=True,null=True,on_delete=CASCADE)
    pickup_location = models.ForeignKey(Pickup_Location,blank=True,null=True,on_delete=CASCADE)
    delivery_location = models.ForeignKey(Delivery_Location,blank=True,null=True,on_delete=CASCADE)
    booked_by = models.ForeignKey(Employee,blank=True,null=True,on_delete=CASCADE)
    broker = models.ForeignKey(Broker,blank=True,null=True,on_delete=CASCADE)
    delivery_date = models.DateField('Delivery Date')
    delivery_time = models.TimeField('Delivery Time')
    pickup_date = models.DateField(default='2000-1-1')
    pickup_time = models.TimeField(default='12:00:00')
    bnsf_container_number = models.ForeignKey(Container,blank=True, null=True, on_delete=CASCADE)
    load_number = models.CharField(max_length=20)
    trailer_number = models.IntegerField(default=0000)
    seal_number = models.IntegerField(default=0000)
    shipment_cost = models.DecimalField(max_digits=6,decimal_places=2, default=0)
    shipment_revenue = models.DecimalField(max_digits=6,decimal_places=2, default=0)

    def __str__(self):
        return self.id

    class Meta:
        db_table = "Load"
 

views.py (частичный фрагмент кода, но важная часть

 class LoadViews(APIView):
    def get(self,request,id=None):
        if id:
            load = Load.objects.get(id=id)
            serializer = LoadSerializer2(load)
            return Response({"status": "success", "data": serializer.data}, status=status.HTTP_200_OK)
        else:
            loads = Load.objects.all()
            serializer = LoadSerializer2(loads, many=True)
            return Response({"status": "success", "data": serializer.data}, status=status.HTTP_200_OK)

    def post(self,request):
        serializer = LoadSerializer2(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response({"status":"success", "data":serializer.data}, status=status.HTTP_200_OK)
        else:
            return Response({"status": "Error", "data": serializer.errors}, status=status.HTTP_400_BAD_REQUEST)
    
    def patch(self,request,id=None):
        load = Load.objects.get(id=id)
        serializer = LoadSerializer2(load,data=request.data,partial=True)
        if serializer.is_valid():
            serializer.save()
            return Response({"status": "success", "data": serializer.data})
        else:
            return Response({"status": "error", "data": serializer.errors})
 

serializers.py

 class ContainerSerializer(serializers.ModelSerializer):
    # container_number = serializers.CharField()

    class Meta:
        model = Container
        fields = '__all__'
        depth = 1

class DriverSerializer(serializers.ModelSerializer):

    class Meta:
        model = Driver
        fields = '__all__'
        depth = 1

class BrokerSerializer(serializers.ModelSerializer):

    class Meta:
        model = Broker
        fields = '__all__'
        depth = 1

class EmployeeSerializer(serializers.ModelSerializer):

    class Meta:
        model = Employee
        fields = '__all__'
        depth = 1

class DeliveryLocationSerializer(serializers.ModelSerializer):

    class Meta:
        model = Delivery_Location
        fields = '__all__'
        depth = 1

class PickupLocationSerializer(serializers.ModelSerializer):

    class Meta:
        model = Pickup_Location
        fields = '__all__'
        depth = 1

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = '__all__'
        depth = 1

class LoadSerializer2(serializers.ModelSerializer):

    primary_driver = DriverSerializer(read_only=False)
    bnsf_container_number = ContainerSerializer(read_only=False)
    pickup_location = PickupLocationSerializer(read_only=False)
    delivery_location = DeliveryLocationSerializer(read_only=False)
    broker = BrokerSerializer(read_only=False)
    booked_by = EmployeeSerializer(read_only=False) 

    class Meta:
        model = Load
        fields = '__all__'
        depth = 1

    #custom create method for drivers
    def create(self, validated_data):
        drivers_data = validated_data.pop('primary_driver')
        load = Load.objects.create(**validated_data)
        for driver_data in drivers_data:
            Driver.objects.create(load=load, **driver_data)
        return load 
 

json, который я пытаюсь отправить

 {
    "primaryDriver": {
        "firstName": "Mike",
        "lastName": "Doe",
        "phoneNumber": "123-456-7890",
        "companyName": "Trucking Company"
        },
    "bnsfContainerNumber": {
        "containerNumber": "CFQU1111"
        },
    "pickupLocation": {
        "streetAddress": "9999 Pickup Street",
        "state": "Wisconsin",
        "zipCode": 55555,
        "city": "Madison"
        },
    "deliveryLocation": {
        "streetAddress": "5568 Delivery Street",
        "state": "California",
        "zipCode": 90210,
        "city": "Los Angeles"
        },
    "broker": {
        "firstName": "Postman",
        "lastName": "Guy",
        "eMail": "plswork@work.com",
        "companyName": "Hot Brokers 4 u",
        "phoneNumber": "123-456-7890"
        },
    "bookedBy": {
        "firstName": "Dane",
        "lastName": "Doe",
        "eMail": "danedoe@email.com",
        "phoneNumber": "123-456-7890"
        },
    "deliveryDate": "2021-10-21",
    "deliveryTime": "12:00:00",
    "pickupDate": "2021-10-09",
    "pickupTime": "12:00:00",
    "loadNumber": "789045",
    "trailerNumber": 776543,
    "sealNumber": 545156,
    "shipmentCost": "900.00",
    "shipmentRevenue": "1500.00"
}