/ / 1対多の関係を投稿する-django、1対多、django-rest-framework

1対多の関係を投稿する-django、one-to-many、django-rest-framework

DjangoRESTフレームワークを介して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()

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

私は今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できるようにするには、何をする必要がありますか?私はそれを把握することはできません。どうもありがとう。

回答:

回答№1は8

(多かれ少なかれ別のものからコピーされた答え 類似しているが明確ではない質問

1つの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)

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

他のオプションは、関連するを作成することです Observation 個別のPOSTを使用して個別にオブジェクトを作成し、 PrimaryKeyRelatedFieldまたはHyperlinkedRelatedField 決勝でアソシエーションを行う ObservedThing 役職。


回答№2については4

私はこのスレッドがすでに答えを持っていることを知っていますが、私はこの問題の解決に取り組み始めました。この投稿は私のインスピレーションの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"

私はシリアライザーを定義しなければなりませんでした。子オブジェクトを直接管理するためのルーターアクセス可能な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を作成し、作成/更新ミックスインをオーバーライド/拡張​​し、他の場合に再利用するために汎用にする準備ができました。

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)

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


回答№3の場合は1
thing = models.ManyToManyField("Thing")

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