SlugRelatedField查询 [英] SlugRelatedField queryset

查看:215
本文介绍了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. Objects can have the same name only if they below to different Projects.

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 Bars:

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆