如何在Django Rest Framework中使用嵌套对象创建对象

时间:2019-05-22 23:55:55

标签: django django-rest-framework

在这里创建我的第一个Django应用。我在插入Route对象时遇到问题。这是我的models.py

class Location(models.Model):
    location_id = models.AutoField(primary_key=True)
    location_name = models.CharField(max_length=50)
    location_lat = models.FloatField()
    location_log = models.FloatField() 

    def __str__(self):
        return self.location_name

class Route(models.Model):
    route_id = models.AutoField(primary_key=True)
    route_code = models.CharField(max_length=50)
    origin_location = models.OneToOneField(Location, related_name="origin", on_delete=models.PROTECT)
    destination_location = models.OneToOneField(Location, related_name="destination", on_delete=models.PROTECT)
    waypoint1_location = models.OneToOneField(Location, related_name="waypoint1", on_delete=models.PROTECT, blank=True, null=True)
    waypoint2_location = models.OneToOneField(Location, related_name="waypoint2", on_delete=models.PROTECT, blank=True, null=True)
    route_duration = models.DurationField(blank=True, null=True)

    def __str__(self):
        return self.route_code

我基本上想要的是拥有Route,其中必须包含 origin destination ,而航路点是可选的。

首先,我有一个表单页面,用户可以在其中单独创建Location对象。

然后,我有另一个表单页面,用户可以在其中创建路线。它以Location对象的形式选择-一个用于 origin ,一个用于 destination ,还可以选择 waypoint1 waypoint2 < / em>

因此,在创建Route时,我显然不想创建一个新的Location。它已经在那里。我只想将新的route对象链接到已经存在的location对象。

我的serializers.py是:

class LocationSerializer(serializers.ModelSerializer):
    class Meta:
        model = Location
        fields = '__all__'

class RouteSerializer(serializers.ModelSerializer):
    origin_location = LocationSerializer(many=False, required=True)
    destination_location = LocationSerializer(many=False, required=True)
    waypoint1_location = LocationSerializer(many=False, required=False, read_only=True)
    waypoint2_location = LocationSerializer(many=False, required=False, read_only=True)

    class Meta:
        model = Route
        fields = '__all__'

要插入的route JSON是:

  

{“ route_code”:“ 213123”,“ origin_location”:{“ location_id”:3,“ location_name”:“ Tumut”,“ location_lat”:-35.31158,“ location_log”:148.21159},“ destination_location”:{ “ location_id”:3,“ location_name”:“ Tumut”,“ location_lat”:-35.31158,“ location_log”:148.21159}}

我得到的错误是:

  / api / route / \ n上的

AssertionError .create()方法不支持   默认情况下为可写的嵌套字段。\ n写一个明确的.create()   串行器planner.serializers.RouteSerializer的方法,或设置   read_only=True在嵌套的序列化程序字段上。\ n \ n请求方法:   POST \ n请求网址:http://localhost:8000/api/route/ \ n

好像我需要为我的create()写一个RouteSerializer函数,但是不确定如何处理它。 任何帮助表示赞赏。

1 个答案:

答案 0 :(得分:1)

好的,我知道了。这是我的更改:

serializers.py

class LocationSerializer(serializers.ModelSerializer):
    class Meta:
        model = Location
        fields = '__all__'

class RouteSerializer(serializers.ModelSerializer):
    class Meta:
        model = Route
        fields = '__all__'

class RouteReadSerializer(RouteSerializer):
    origin_location = LocationSerializer(read_only=True)
    destination_location = LocationSerializer(read_only=True)
    waypoint1_location = LocationSerializer(read_only=True)
    waypoint2_location = LocationSerializer(read_only=True)

viewsets.py

class RouteViewSet(viewsets.ModelViewSet):
    queryset = Route.objects.all()
    serializer_class = RouteSerializer

    def get_serializer_class(self):
         # Define your HTTP method-to-serializer mapping freely.
         # This also works with CoreAPI and Swagger documentation,
         # which produces clean and readable API documentation,
         # so I have chosen to believe this is the way the
         # Django REST Framework author intended things to work:
         if self.request.method in ['GET']:
             # Since the ReadSerializer does nested lookups
             # in multiple tables, only use it when necessary
             return RouteReadSerializer
         return RouteSerializer

class LocationViewSet(viewsets.ModelViewSet):
    queryset = Location.objects.all()
    serializer_class = LocationSerializer

models.py

class Route(models.Model):
    route_id = models.AutoField(primary_key=True)
    route_code = models.CharField(max_length=50, unique=True)
    origin_location = models.ForeignKey(Location, related_name="origin", on_delete=models.CASCADE)
    destination_location = models.ForeignKey(Location, related_name="destination", on_delete=models.PROTECT)
    waypoint1_location = models.ForeignKey(Location, related_name="waypoint1", on_delete=models.PROTECT, blank=True, null=True)
    waypoint2_location = models.ForeignKey(Location, related_name="waypoint2", on_delete=models.PROTECT, blank=True, null=True)
    route_duration = models.DurationField(blank=True, null=True)

    def __str__(self):
        return self.route_code

我将OneToOneField更改为ForeignKey。这实际上更有意义。

谢谢