I'm trying to expose an API to my Django model through Django REST framework.
我正在尝试通过Django REST框架向我的Django模型公开API。
I have an object Observation
. An observation can contain multiple things that have been observed. So I represented it like this:
我有一个对象观察。观察可以包含已观察到的多个事物。所以我这样代表它:
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()
As I understand this is a one-to-many relationship.
据我所知,这是一对多的关系。
I now have an API View:
我现在有一个API视图:
class ObsvList(generics.ListCreateAPIView):
"""
API endpoint that represents a list of observations.
"""
model = Observation
serializer_class = ObsvSerializer
and the corresponding serialiser:
和相应的序列化器:
class ObsvSerializer(serializers.ModelSerializer):
observed_thing = serializers.PrimaryKeyRelatedField(many=True)
class Meta:
model = Observation
What do I have to do to be able to POST an observation with several things detected? I cannot figure it out. Many thanks.
我需要做些什么来检测观察到的几件事情?我想不明白。非常感谢。
3 个解决方案
#1
8
(answer more or less copied from another similar but less clear question)
(回答或多或少从另一个类似但不太清楚的问题复制)
To create multiple related objects in a single POST requires writable nested serializers which are not yet available.
要在单个POST中创建多个相关对象,需要可写的嵌套序列化程序,这些序列化程序尚不可用。
Full support is a work in progress, but in the mean time one (hacky) solution is to override the create
method in the view in each case:
完全支持是一项正在进行的工作,但同时一个(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)
Probably not ideal, but it works for me until the proper way comes along.
可能不理想,但它适用于我,直到正确的方式出现。
The other option is to create the related Observation
objects individually with separate POSTs, and the use PrimaryKeyRelatedField or HyperlinkedRelatedField to make the associations in the final ObservedThing
POST.
另一个选项是使用单独的POST单独创建相关的Observation对象,并使用PrimaryKeyRelatedField或HyperlinkedRelatedField在最终的ObservedThing POST中创建关联。
#2
4
I know this thread has already an answer but I started working to solve this problem, and since this post was one of my inspirations, I would like to share my final solution. It can be useful to someone. I have the models, so the parent class:
我知道这个帖子已经有了答案,但我开始努力解决这个问题,因为这篇文章是我的灵感之一,我想分享我的最终解决方案。它对某人有用。我有模型,所以父类:
#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'
then, the child class:
然后,孩子班:
#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'
I had to define the serializers, since I didn't want to create a router accessible url to directly manage Children objects, but I wanted to create them through the ModelViewSet of the parent ModelViewSet, this is what I needed:
我不得不定义序列化程序,因为我不想创建路由器可访问的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)
I was then ready to create the ModelViewSet, overriding/extending the create/update mixins, and make it generic in order to reuse it for other cases:
然后我准备创建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)
So I can reuse it for every nested relationship case I have in my app like this:
所以我可以为我在我的应用程序中的每个嵌套关系案例重用它,如下所示:
class ParentViewSet(ParentChildViewSet):
child_field = 'children'
parent_field = 'parent'
model = Parent
model_child = Child
serializer_class = ParentSerializerNested
serializer_parent = ParentSerializer
serializer_child = ChildSerializer
And in the end, the routing:
最后,路由:
router = routers.DefaultRouter()
router.register(r'parents', ParentViewSet)
It works like a charm!
它就像一个魅力!
#3
1
thing = models.ManyToManyField('Thing')
you need to use many to many relationship for creating a temporary table that will store the keys and associate data automatically.
您需要使用多对多关系来创建临时表,该表将存储密钥并自动关联数据。
#1
8
(answer more or less copied from another similar but less clear question)
(回答或多或少从另一个类似但不太清楚的问题复制)
To create multiple related objects in a single POST requires writable nested serializers which are not yet available.
要在单个POST中创建多个相关对象,需要可写的嵌套序列化程序,这些序列化程序尚不可用。
Full support is a work in progress, but in the mean time one (hacky) solution is to override the create
method in the view in each case:
完全支持是一项正在进行的工作,但同时一个(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)
Probably not ideal, but it works for me until the proper way comes along.
可能不理想,但它适用于我,直到正确的方式出现。
The other option is to create the related Observation
objects individually with separate POSTs, and the use PrimaryKeyRelatedField or HyperlinkedRelatedField to make the associations in the final ObservedThing
POST.
另一个选项是使用单独的POST单独创建相关的Observation对象,并使用PrimaryKeyRelatedField或HyperlinkedRelatedField在最终的ObservedThing POST中创建关联。
#2
4
I know this thread has already an answer but I started working to solve this problem, and since this post was one of my inspirations, I would like to share my final solution. It can be useful to someone. I have the models, so the parent class:
我知道这个帖子已经有了答案,但我开始努力解决这个问题,因为这篇文章是我的灵感之一,我想分享我的最终解决方案。它对某人有用。我有模型,所以父类:
#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'
then, the child class:
然后,孩子班:
#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'
I had to define the serializers, since I didn't want to create a router accessible url to directly manage Children objects, but I wanted to create them through the ModelViewSet of the parent ModelViewSet, this is what I needed:
我不得不定义序列化程序,因为我不想创建路由器可访问的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)
I was then ready to create the ModelViewSet, overriding/extending the create/update mixins, and make it generic in order to reuse it for other cases:
然后我准备创建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)
So I can reuse it for every nested relationship case I have in my app like this:
所以我可以为我在我的应用程序中的每个嵌套关系案例重用它,如下所示:
class ParentViewSet(ParentChildViewSet):
child_field = 'children'
parent_field = 'parent'
model = Parent
model_child = Child
serializer_class = ParentSerializerNested
serializer_parent = ParentSerializer
serializer_child = ChildSerializer
And in the end, the routing:
最后,路由:
router = routers.DefaultRouter()
router.register(r'parents', ParentViewSet)
It works like a charm!
它就像一个魅力!
#3
1
thing = models.ManyToManyField('Thing')
you need to use many to many relationship for creating a temporary table that will store the keys and associate data automatically.
您需要使用多对多关系来创建临时表,该表将存储密钥并自动关联数据。