Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/django/24.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查询、反向查询和谓词中的DRY_Django_Dry - Fatal编程技术网

django查询、反向查询和谓词中的DRY

django查询、反向查询和谓词中的DRY,django,dry,Django,Dry,在Django中,我常常不得不在自定义管理器上编写方法,这让我感到沮丧: class EntryManager(Manager): def filter_beatle(self, beatle): return self.filter(headline__contains=beatle) 。。。对于反向查询,在不同的管理器中重复几乎相同的方法: class BlogManager(Manager): def filter_beatle(self, beatle)

在Django中,我常常不得不在自定义管理器上编写方法,这让我感到沮丧:

class EntryManager(Manager):
    def filter_beatle(self, beatle):
        return self.filter(headline__contains=beatle)
。。。对于反向查询,在不同的管理器中重复几乎相同的方法:

class BlogManager(Manager):
    def filter_beatle(self, beatle):
        return self.filter(entry__headline__contains=beatle)
。。。和一个入口谓词:

def headline_contains(self, beatle):
    return self.headline.find(beatle) != -1
[请注意,Entry上的谓词将用于尚未保存的Entry对象。]

这感觉像是对DRY的违反。是否有某种方法可以一次性表达这一点,并在所有三个地方使用它

我希望能够写下如下内容:

q = Q(headline__contains="Lennon")
lennon_entries = Entry.objects.filter(q)
lennon_blogs = Blog.objects.filter(q.reverse(Entry))
is_lennon = entry.would_filter(q)
class Thing(Model):
    class QuerySet(query.QuerySet):
        def need_to_be_whacked():
            # ... code ...

    def needs_to_be_whacked(self):
        return Thing.objects.need_to_be_whacked().filter(id=self.id).exists()

    def whack(self):
        assert self.needs_to_be_whacked()

for thing in Thing.objects.need_to_be_whacked():
    thing.whack()
。。。其中,“headline\uu contains=“Lennon”只表达了一次“关于“Lennon”的条目”的含义,这可用于构造反向查询和谓词。

您不应该很少执行以下操作:

if entry.headline.find('Lennon') >= 0:
因为过滤器应该注意将结果集限制为您感兴趣的实例

如果要多次使用同一个筛选器,可以创建一个或一个简单的类方法

class Entry(models.Model):
    ...
    # this really should be on a custom manager, but this was quicker to demonstrate
    @classmethod
    def find_headlines(cls, text):
        return cls.objects.filter(headline__contains=text)

entries = Entry.find_headlines('Lennon')
但实际上,Queryset API中已经包含了干燥度。您将每隔多久将字符串“Lennon”硬编码到查询中?通常,搜索参数将从GET或POST传递到视图中。干透了


那么,实际的问题是什么?除了探索queryset API之外,您是否曾经在像您的问题这样的多个查询中硬编码查找值?

最好的地方是自定义管理器。根据django的指导原则,对于影响一个类的多个对象的代码,管理器类是最好的地方

class EntryManager(models.Manager):
    def filter_lennons(self):
        return self.get_query_set().filter(headline__contains='Lennon')

class Entry(models.Model):
    headline = models.CharField(max_length=100)

    objects = EntryManager()

lennons = Entry.objects.filter_lennons()
对于“反向筛选”情况,可以使用子查询:

Blog.objects.filter(entries__in=Entry.objects.filter_beatle("Lennon"))

重用或生成谓词(通常)是不可能的,因为有些谓词不能表示为查询,有些查询不能表示为没有db访问权限的谓词

我对谓词最常用的用法似乎是在断言中。通常类似于:

q = Q(headline__contains="Lennon")
lennon_entries = Entry.objects.filter(q)
lennon_blogs = Blog.objects.filter(q.reverse(Entry))
is_lennon = entry.would_filter(q)
class Thing(Model):
    class QuerySet(query.QuerySet):
        def need_to_be_whacked():
            # ... code ...

    def needs_to_be_whacked(self):
        return Thing.objects.need_to_be_whacked().filter(id=self.id).exists()

    def whack(self):
        assert self.needs_to_be_whacked()

for thing in Thing.objects.need_to_be_whacked():
    thing.whack()

我想确保没有其他代码在不需要重击的状态下调用whack()。它需要一次数据库访问,但它可以工作。

你是说
Entry.objects.filter(…)
?此外,您还没有解释要执行的操作。将筛选器更改为在管理器上操作,而不是尝试构造无效对象。“谓词”仍然是错误的,我将把它留给OP来解决。感谢您的编辑和澄清问题。这不是关于硬编码“列侬”,而是关于必须用三种不同的方式表达“列侬·奈斯”(或者真正的“披头士·奈斯”)。例如,如果我有一个与一组条目匹配的查询,但我希望以红色显示所有列侬条目,那么可能需要一个谓词。子查询以另一次往返数据库为代价来解决这个问题。我这样做的目的是希望减轻负担。但是,如果有很多Lennon条目,我宁愿让数据库进行连接,而不是用Python创建一个中间结果。看看。在in子句中有足够的ID,您可以达到最大数据包大小的db限制(至少在MySQL中)。我决不会在in子句中使用任意数量的元素。它无法扩展。当它失败时,它会无声地失败,只是截断您的ID。我的问题是需要多次重新声明一个条件,并使用自定义管理器。我不确定这个答案想补充什么。