SlugRelatedField查询 [英] SlugRelatedField queryset
问题描述
我的数据是这样的,我有一堆属于
Project
的 Object
实例。一个项目有一个独特的'顶级'对象
。 对象
只能在下面的不同项目
之间具有相同的名称。 class Object(models.Model):
project = models.ForeignKey('Project',null = False,related_name ='objs')
name = models.TextField(null = False,db_index = True)
....
class Meta:
index_together = unique_together =('project','name')
class Project(models.Model):
user = models.ForeignKey(get_user_model(),null = False,related_name ='+')
name = models.TextField(null = False)
top = models.OneToOneField(Object,null = True,related_name ='+')
....
class ObjectSerializer(NonNullSerializer):
class Meta:
model = Object
fields =('name',)
class ProjectSerializer(NonNullSerializer):
objs = ObjectSerializer(many = True,required = False)
top = serializers.SlugRelatedField(slug_field ='name',que ryset = Object.objects.filter(????))
class Meta:
model = Project
fields =('id','name','objs' ,'top')
我的查询会是什么样子,看起来像 top
如果我想只找到属于正确的项目
的一个对象
?换句话说,如何反序列化:
[{
'name':'Project1',
'objs':[{
'name':'One'
}],
'top':'One'
},
{
'name':'Project2',
'objs':[{
'name':'One'
}],
'top':'One' - 这应该指向Project2下的One,而不是Project1下的One
}]
我有一个解决方案来解决这个问题,我将尝试在这里解释。
问题,抽象: / p>
假设我有一个具有 Foo
的层次结构作为顶级对象,每个对象与几个 Bar
s:
class Foo(Model):
pass
class Bar(Model):
bar_text = CharField()
foo = ForeignKey(Foo,related_name ='bars')
然后我可以使用 SlugRelatedField
简单地为 Foo
的只读序列化,我的意思是串行器: p>
class FooSerializer(ModelSerializer):
bars = serializers.SlugRelatedField(slug_field ='bar_text',
many = True,read_only = True
class Meta:
model = Foo
fields =('bars',)
将产生如下所示的序列:
{'bars':[< bar_text> ,< bar_text> ...]}
但是,这是只读的。为了允许写作,我必须提供一个queryset类属性,而不是任何方法。问题是,因为我们有一个 Foo-> Bar
层次结构,我们不知道什么是任何请求之外的查询集。我们希望能覆盖一个 get_queryset()
方法,但似乎没有。所以我们不能使用 SlugRelatedField
。我们可以解决这个错误的方式吗?
我的解决方案:
首先,将@property添加到Foo模型,并将此属性放在序列化器中:
在 models.py
中:
class Foo(Model):
@property
def bar_texts(self):
return [bar.bar_text for bar在self.bars.all()]
在 serializers.py
class FooSerializer(ModelSerializer):
class Meta:
model = Foo
fields =('bar_texts')
这允许条形码文本序列化但是我们仍然不能写(我们可以尝试 - 框架不会拒绝它,但是当尝试保存一个 Foo
)
所以,黑客部分 - 修复 Foo
perform_create()
/ code>列表视图。
class FooLis t:
def perform_create(self,serializer):
#串行器包含我们想要的bar_text字段,但不对应于$ f $的可写属性
#。提取字符串并保存Foo。如果bar_texts不在序列化数据中,则使用pop键。
bar_texts = serializer.validated_data.pop('bar_texts',[])
#保存Foo对象;它现在没有与它相关联的
foo = serializer.save()
#现在将bar添加到数据库
bar_text中的bar_text:
foo。 bars.create(bar_text = bar_text)
我希望这是有道理的。它肯定对我有用,但是我可以找到任何明显的错误。
I am struggling to figure out the queryset for SlugRelatedField.
My data is such that I have a bunch of Object
instances that belong to a Project
. A project has a unique 'top' Object
. Object
s can have the same name only if they below to different Project
s.
class Object(models.Model):
project = models.ForeignKey('Project', null=False, related_name='objs')
name = models.TextField(null=False, db_index=True)
....
class Meta:
index_together = unique_together = ('project', 'name')
class Project(models.Model):
user = models.ForeignKey(get_user_model(), null=False, related_name='+')
name = models.TextField(null=False)
top = models.OneToOneField(Object, null=True, related_name='+')
....
class ObjectSerializer(NonNullSerializer):
class Meta:
model = Object
fields = ('name',)
class ProjectSerializer(NonNullSerializer):
objs = ObjectSerializer(many=True, required=False)
top = serializers.SlugRelatedField(slug_field='name', queryset=Object.objects.filter(????))
class Meta:
model = Project
fields = ('id', 'name', 'objs', 'top')
What is my queryset going to look like for top
if I want to find only only the one Object
that belongs to the correct Project
? In other words, how to deserialize this:
[{
'name' : 'Project1',
'objs' : [{
'name': 'One'
}],
'top': 'One'
},
{
'name' : 'Project2',
'objs' : [{
'name': 'One'
}],
'top': 'One' <-- This should point to One under Project2, not One under Project1
}]
I have a solution that solves this problem in my case, which I will try to explain here.
The problem, abstracted:
Suppose I have a hierarchy with Foo
as the top-level objects, each associated with several Bar
s:
class Foo(Model):
pass
class Bar(Model):
bar_text = CharField()
foo = ForeignKey(Foo, related_name='bars')
Then I can use SlugRelatedField
trivially for read only serializations of Foo
, by which I mean the serializer:
class FooSerializer(ModelSerializer):
bars = serializers.SlugRelatedField(slug_field='bar_text',
many=True, read_only=True)
class Meta:
model = Foo
fields = ('bars',)
will produce serializations like:
{ 'bars' : [<bar_text>, <bar_text>, ...] }
However, this is read only. To allow writing, I have to provide a queryset class attribute outside of any methods. The problem is, because we have a Foo->Bar
hierarchy, we don't know what the queryset is outside of any request. We would like to be able to override a get_queryset()
method, but none seems to exist. So we can't use SlugRelatedField
. What horribly hacky way can we fix it?
My Solution:
First, add an @property to the Foo model and put this property in the serializer:
In models.py
:
class Foo(Model):
@property
def bar_texts(self):
return [bar.bar_text for bar in self.bars.all()]
In serializers.py
:
class FooSerializer(ModelSerializer):
class Meta:
model = Foo
fields = ('bar_texts',)
This allows for the bar texts to be serialized as before, but we still can't write (we can try - the framework won't reject it but it will hit an exception when trying to save the bar_texts attribute of a Foo
)
So, the hacky part - fix perform_create()
in the Foo
list view.
class FooList:
def perform_create(self, serializer):
# The serializer contains the bar_text field, which we want, but doesn't correspond
# to a writeable attribute of Foo. Extract the strings and save the Foo. Use pop with a default arg in case bar_texts isn't in the serialized data
bar_texts = serializer.validated_data.pop('bar_texts', [])
# Save the Foo object; it currently has no Bars associated with it
foo = serializer.save()
# Now add the Bars to the database
for bar_text in bar_texts:
foo.bars.create(bar_text=bar_text)
I hope that makes sense. It certainly works for me, but I have get to find any glaring bugs with it
这篇关于SlugRelatedField查询的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!