Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/django/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Django ';私人';模型、默认查询集和链接方法_Django_Django Models_Orm_Django Queryset - Fatal编程技术网

Django ';私人';模型、默认查询集和链接方法

Django ';私人';模型、默认查询集和链接方法,django,django-models,orm,django-queryset,Django,Django Models,Orm,Django Queryset,我的模型上有一个privateboolean标志,还有一个自定义管理器,它使用一个过滤器覆盖get\u query\u set方法,删除private=True: class myManager(models.Manager): def get_query_set(self): qs = super(myManager, self).get_query_set() qs = qs.filter(private=False) return q

我的模型上有一个
private
boolean标志,还有一个自定义管理器,它使用一个过滤器覆盖get\u query\u set方法,删除private=True:

class myManager(models.Manager):
    def get_query_set(self):
        qs = super(myManager, self).get_query_set()
        qs = qs.filter(private=False)
        return qs

class myModel(models.Model):
    private = models.BooleanField(default=False)
    owner = models.ForeignKey('Profile', related_name="owned")
    #...etc...

    objects = myManager()
作为一种安全措施,我希望默认查询集排除私有模型,以防止意外使用显示私有模型的模型

但是,有时我会想展示私有模型,因此我在manager上有以下内容:

def for_user(self, user):
    if user and not user.is_authenticated():
        return self.get_query_set()
    qs = super(myManager, self).get_query_set()
    qs = qs.filter(Q(owner=user, private=True) | Q(private=False))
    return qs
这项工作非常出色,但我不能将过滤器链接起来。当我有一个指向myModel的fk并使用otherModel.myModel\u集时,这会成为一个问题。otherModel.mymodel\u set.for\u用户(用户)不起作用,因为mymodel\u集合返回的是QuerySet对象,而不是管理器

现在真正的问题开始了,因为我看不到让for_user()方法在QuerySet子类上工作的方法,因为我无法访问QuerySet子类中完整的、未过滤的QuerySet(基本上覆盖get_query_集),就像我在管理器中一样(使用super()获取基本QuerySet)

解决这个问题的最佳方法是什么

我并不局限于任何特定的接口,但我希望它尽可能地使用djangoy/DRY。显然,我可以放弃安全性,在每次调用时只调用一个方法来过滤掉私有任务,但我真的不想这样做

更新


manji下面的答案非常接近,但是当我想要的查询集不是默认查询集的子集时,它会失败。我想这里真正的问题是如何从链式查询中删除特定筛选器?

要使用链式查询,您应该覆盖管理器中的get\u query\u集,并将for\u用户放在自定义查询集中

我不喜欢这个解决方案,但它是有效的

class CustomQuerySet(models.query.QuerySet):
    def for_user(self):
        return super(CustomQuerySet, self).filter(*args, **kwargs).filter(private=False)

class CustomManager(models.Manager):
    def get_query_set(self):
        return CustomQuerySet(self.model, using=self._db)
定义自定义查询集(包含自定义筛选方法):

定义一个将使用
MyQuerySet
的自定义管理器(
MyQuerySet
自定义筛选器将被访问,就像它们是在管理器中定义的一样[通过重写
\uu getattr\uuu
]):

然后在模型中:

class MyModel(models.Model):
    private = models.BooleanField(default=False)
    owner = models.ForeignKey('Profile', related_name="owned")
    #...etc...

    objects = myManager(MyQuerySet)
现在您可以:

·默认情况下仅访问公共型号:

    MyModel.objects.filter(..
    MyModel.objects.for_user(user1).filter(..
为用户访问型号:

    MyModel.objects.filter(..
    MyModel.objects.for_user(user1).filter(..
由于(),此管理器将用于相关管理器。因此,您还可以:

默认情况下,只能访问相关经理提供的公共模型:

    otherModel.mymodel_set.filter(..
    otherModel.mymodel_set.for_user(user).filter(..
从相关经理处为用户访问

    otherModel.mymodel_set.filter(..
    otherModel.mymodel_set.for_user(user).filter(..

更多信息:&(django snippet)如果需要“重置”查询集,可以访问查询集的模型并再次调用原始管理器(以完全重置)。但是,这可能对您不是很有用,除非您跟踪以前的filter/exclude etc语句,并且可以在reset queryset上再次重播它们。做一点计划其实并不难,但可能有点野蛮

总的来说,曼吉的答案肯定是正确的

因此,修改manji的答案时,您需要将现有的
“model”“private”=False
替换为
(“model”。“owner\u id”=2和“model”。“private”=True)或“model”。“private”=False)
。为此,您需要遍历queryset的
query
对象上的
where
对象,以找到要删除的相关位。查询对象有一个
WhereNode
对象,该对象表示where子句的树,每个节点都有多个子节点。您必须在节点上调用
as_sql
,以确定它是否是您要查找的对象:


from django.db import connection
qn = connection.ops.quote_name
q = myModel.objects.all()
print q.query.where.children[0].as_sql(qn, connection)
这会给你一些类似的东西:


('"model"."private" = ?', [False])
然而,试图做到这一点可能需要付出的努力远远超过了它的价值,而且它正在深入研究Django中可能不稳定的API


我的建议是使用两名经理。一个可以访问所有内容(某种转义图案填充),另一个应用默认筛选。默认的管理器是第一个,因此您需要根据需要执行的操作来处理订单。然后重新构造代码,以知道要使用哪一个-这样就不会有额外的private=False子句已经存在的问题。

MyModel.objects.all()的作用是什么?看来那会把一切都还回来。不过,这似乎是迄今为止最好的选择。我将试一试。不,
MyModel.objects.all()
将返回过滤后的模型(仅公共)。
models.Manager
的所有筛选方法都使用
get\u query\u set
。绑定后,SQL中的WHERE cluse被AND在一起:从[“表”]中选择[*],其中(“模型”。“私有”=False和((“模型”。“所有者id”=2和“模型”。“私有”=True)或“模型”。“私有”=False))按“模型”。“id”排序描述我需要的是用OR而不是AND来连接过滤器……为了澄清,我的装置应该有4个对象(私有对象和3个公共对象),而实际上我只有1个。