10

Django REST フレームワークを介して API を Django モデルに公開しようとしています。

私はオブジェクトを持っていますObservation。観測には、観測された複数のものが含まれる場合があります。だから私はそれを次のように表現しました:

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()

私が理解しているように、これは一対多の関係です。

API ビューができました。

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

および対応するシリアライザー:

class ObsvSerializer(serializers.ModelSerializer):

    observed_thing = serializers.PrimaryKeyRelatedField(many=True)

    class Meta:
        model = Observation

複数のものが検出された観測を POST できるようにするには、どうすればよいですか? 私はそれを把握することはできません。どうもありがとう。

4

3 に答える 3

8

(似ているがあまり明確でない別の質問から多かれ少なかれコピーされた回答)

単一の POST で複数の関連オブジェクトを作成するには、まだ使用できない書き込み可能なネストされたシリアライザーが必要です。

完全なサポートは進行中の作業ですが、当面の 1 つの (ハッキーな) 解決策はcreate、それぞれの場合にビューでメソッドをオーバーライドすることです。

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)

おそらく理想的ではありませんが、適切な方法が見つかるまではうまくいきます。

もう 1 つのオプションは、個別の POST で関連Observationオブジェクトを個別に作成し、 PrimaryKeyRelatedField または HyperlinkedRelatedFieldを使用して最終的なObservedThingPOST で関連付けを行うことです。

于 2013-03-05T10:18:01.427 に答える
7

このスレッドには既に回答があることは知っていますが、私はこの問題の解決に取り組み始めました。この投稿は私のインスピレーションの 1 つだったので、最終的な解決策を共有したいと思います。それは誰かに役立つことができます。私はモデルを持っているので、親クラス:

#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'

次に、子クラス:

#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'

Children オブジェクトを直接管理するためのルーター アクセス可能な URL を作成したくなかったので、シリアライザーを定義する必要がありましたが、親 ModelViewSet の ModelViewSet を介してそれらを作成したかったので、これが必要でした。

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)

その後、ModelViewSet を作成し、作成/更新 mixin をオーバーライド/拡張​​して、他のケースで再利用できるように汎用化する準備が整いました。

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)

したがって、次のように、アプリ内にあるネストされたリレーションシップのすべてのケースで再利用できます。

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

最後に、ルーティングは次のとおりです。

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

それは魅力のように機能します!

于 2014-05-22T15:19:34.320 に答える
0
thing = models.ManyToManyField('Thing')

キーを格納してデータを自動的に関連付ける一時テーブルを作成するには、多対多の関係を使用する必要があります。

于 2013-03-05T07:20:10.867 に答える