2013-03-04 44 views
8

Tôi đang cố gắng để lộ một API cho mô hình Django của tôi thông qua khung công tác REST Django.Đăng một mối quan hệ một-nhiều

Tôi có một đối tượng Observation. Một quan sát có thể chứa nhiều thứ đã được quan sát. Vì vậy, tôi đại diện cho nó như thế này:

class Observation(models.Model): 

    photo_file = models.ImageField(upload_to=img_dir, blank=True, null=True) 
    titestamp = models.DateTimeField(blank=True, null=True) 
    latitude = models.FloatField() 
    longitude = models.FloatField() 


class ObservedThing(models.Model): 
    thing = models.ForeignKey(Thing) # the thing being observed 
    observation = models.ForeignKey(Observation, related_name='observed_thing') 
    value = models.FloatField() 

Vì tôi hiểu đây là mối quan hệ một-nhiều.

bây giờ tôi có một Xem API:

class ObsvList(generics.ListCreateAPIView): 
    """ 
    API endpoint that represents a list of observations. 
    """ 
    model = Observation 
    serializer_class = ObsvSerializer 

và serialiser tương ứng:

class ObsvSerializer(serializers.ModelSerializer): 

    observed_thing = serializers.PrimaryKeyRelatedField(many=True) 

    class Meta: 
     model = Observation 

gì làm tôi phải làm gì để có thể đăng một quan sát với một vài điều phát hiện? Tôi không thể hình dung nó ra. Cảm ơn nhiều.

Trả lời

8

(trả lời nhiều hay ít sao chép từ similar but less clear question khác)

Để tạo nhiều đối tượng liên quan trong một POST đơn đòi hỏi serializers lồng nhau ghi mà chưa có sẵn.

Hỗ trợ đầy đủ là một work in progress, nhưng trong thời gian trung bình một (hacky) Giải pháp là để ghi đè lên các phương pháp create trong giao diện trong mỗi trường hợp:

class FooListCreateView(ListCreateAPIView): 
    model = Foo 
    serializer_class = FooSerializer 

    def create(self, request, *args, **kwargs): 
     data=request.DATA 

     f = Foo.objects.create() 

     # ... create nested objects from request data ... 

     # ... 
     return Response(serializer.data, 
         status=status.HTTP_201_CREATED, 
         headers=headers) 

Có lẽ không lý tưởng, nhưng nó làm việc cho tôi cho đến khi cách thích hợp đi kèm.

Tùy chọn khác là tạo các đối tượng liên quan Observation riêng lẻ với POST riêng biệt và sử dụng PrimaryKeyRelatedField or HyperlinkedRelatedField để tạo liên kết trong bài đăng cuối cùng ObservedThing.

+0

Aha, đó là những gì tôi đang tìm kiếm. Rất cám ơn, câu trả lời đã được chấp nhận. – gozzilli

1
thing = models.ManyToManyField('Thing') 

bạn cần sử dụng nhiều mối quan hệ để tạo bảng tạm thời sẽ lưu trữ khóa và liên kết dữ liệu tự động.

+0

Cảm ơn, nhưng bảng trung gian của tôi là bảng '' ObservedThing''. '' ManyToManyField'' chỉ hoạt động nếu bạn không có bất kỳ thông tin nào khác được đính kèm với mối quan hệ. Những gì tôi có thể làm là để có '' điều = models.ManyToManyField (Thing, thông qua = 'ObservedThing') '', nhưng điều đó vẫn không giải quyết được vấn đề ban đầu của tôi. – gozzilli

4

Tôi biết chủ đề này đã là câu trả lời nhưng tôi bắt đầu làm việc để giải quyết vấn đề này và vì bài đăng này là một trong những nguồn cảm hứng của tôi, tôi muốn chia sẻ giải pháp cuối cùng của mình. Nó có thể hữu ích cho ai đó.Tôi có các mô hình, vì vậy các tầng lớp phụ huynh:

#parent model class 
class Parent(models.Model): 

    id = models.AutoField(primary_key=True) 
    field = models.CharField(max_length=45) 

    class Meta: 
     managed = False 
     db_table = 'parent' 

sau đó, lớp trẻ:

#child model class 
class Child(models.Model): 

    id = models.AutoField(primary_key=True) 
    field = models.CharField(max_length=45) 
    parent = models.ForeignKey(Parent, related_name='children') 

    class Meta: 
     managed = False 
     db_table = 'child' 

tôi phải xác định serializers, vì tôi không muốn tạo ra một router url thể truy cập đến trực tiếp quản lý đối tượng trẻ em, nhưng tôi muốn tạo ra chúng thông qua ModelViewSet của phụ huynh ModelViewSet, đây là những gì tôi cần:

class ChildSerializer(serializers.ModelSerializer): 
    class Meta: 
     model = Child 
     read_only_fields = ('id',) 

class ParentSerializer(serializers.ModelSerializer): 
    class Meta: 
     model = Banner 
     read_only_fields = ('id',) 

class ParentSerializerNested(ParentSerializer): 
    children = ChildSerializer(many=True) 

tôi lúc đó đã sẵn sàng để tạo ra các ModelViewSet, trọng/cũ chăm sóc các tạo/cập nhật mixins, và làm cho nó chung chung để tái sử dụng nó cho các trường hợp khác:

class ParentChildViewSet(viewsets.ModelViewSet): 

    def create(self, request, *args, **kwargs): 
     serializer = self.serializer_parent(data=request.DATA, 
              files=request.FILES) 

     try: 
      if serializer.is_valid(): 
       with transaction.commit_on_success(): 
        self.pre_save(serializer.object) 
        parent = serializer.save(force_insert=True) 
        self.post_save(parent, created=True) 

        # need to insert children records 
        for child in request.DATA[self.child_field]: 
         child[self.parent_field] = parent.id 
         child_record = self.serializer_child(data=child) 
         if child_record.is_valid(): 
          child_record.save(force_insert=True) 
         else: 
          raise ValidationError('Child validation failed') 

        headers = self.get_success_headers(serializer.data) 

        serializer.data[self.child_field] = self.serializer_child(
         self.model_child.objects.filter(
          **{self.parent_field: parent.id}).all(), 
          many=True).data 
        return Response(serializer.data, 
            status=status.HTTP_201_CREATED, 
            headers=headers) 
     except ValidationError: 
      pass 
     return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) 

Vì vậy, tôi có thể tái sử dụng nó cho mọi trường hợp mối quan hệ lồng nhau tôi có trong ứng dụng của tôi như thế này:

class ParentViewSet(ParentChildViewSet): 
    child_field = 'children' 
    parent_field = 'parent' 
    model = Parent 
    model_child = Child 
    serializer_class = ParentSerializerNested 
    serializer_parent = ParentSerializer 
    serializer_child = ChildSerializer 

Và cuối cùng, routing:

router = routers.DefaultRouter() 
router.register(r'parents', ParentViewSet) 

Nó hoạt động như một nét duyên dáng!

Các vấn đề liên quan