我正在尝试通过Django REST框架向我的Django模型公开API。
我有一个对象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
如果能够通过检测到的几件事情发布观察,我该怎么办?我想不明白。非常感谢。
答案 0 :(得分:8)
(或多或少地从另一个similar but less clear question复制)
要在单个POST中创建多个相关对象,需要可写嵌套序列化程序,但尚未提供。
完全支持是work in progress,但同时一个(hacky)解决方案是在每种情况下覆盖视图中的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)
可能不理想,但它适用于我,直到正确的方式出现。
另一个选项是使用单独的POST单独创建相关的Observation
对象,并使用PrimaryKeyRelatedField or HyperlinkedRelatedField在最终的ObservedThing
POST中建立关联。
答案 1 :(得分:4)
我知道这个帖子已经有了答案,但我开始努力解决这个问题,因为这篇文章是我的灵感之一,我想分享我的最终解决方案。它对某人有用。我有模型,所以父类:
#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来直接管理Children对象,但是我想通过父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,覆盖/扩展create / update mixins,并使其成为通用的,以便在其他情况下重用它:
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)
它就像一个魅力!
答案 2 :(得分:1)
thing = models.ManyToManyField('Thing')
您需要使用多对多关系来创建临时表,该表将存储密钥并自动关联数据。