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等价物+;案例_Django_Django Models - Fatal编程技术网

和的Django等价物+;案例

和的Django等价物+;案例,django,django-models,Django,Django Models,我有一堆django模特儿 class ReviewItem(Model): review = models.ForegnKey("Review") person = models.ForeignKey("Person") category = models.ForeignKey("Category") item = models.ForeignKey("item") reviewed = models.DateTimeField(null=True) class Pers

我有一堆django模特儿

class ReviewItem(Model):
  review = models.ForegnKey("Review")
  person = models.ForeignKey("Person")
  category = models.ForeignKey("Category")
  item = models.ForeignKey("item")
  reviewed = models.DateTimeField(null=True)

class Person(Model):
  name = models.CharField(max_length=255)

class Category(Model):
  name = models.CharField(max_length=127)

class Item(Model):
  name = models.CharField(max_length=127)
  category = models.ForeignKey("Category")
(如您所见,ReviewItem中的“类别”fk是多余的)

最多会有NxM ReviewItem记录,其中N是人数,M是他们可能分配给他们的项目数量,他们将在审查后设置“审查”日期。项目分为多个类别

我想要的是计算每个项目中有多少项目已经审核,有多少没有审核。在SQL中,我可以

select category.name, item.name,
sum(case when reviewed is null then 1 else 0 end) as un_reviewed
sum(case when reviewed is null then 0 else 1 end) as reviewed
from reviewitem
join  category on category.id = reviewitem.category_id
join  item on item.id = reviewitem.item_id
group by category.id, item.id
order by category.name, item.name
如果不在django中执行两个单独的查询集,我就不知道如何执行此操作

通过两个查询集,我得到了:

uncompleted_items = Item.objects.filter(
    reviewitem__review=current_review,
    reviewitem__person__reports_to=eff_user,
    reviewitem__reviewed__isnull=True
).select_related(
    'category',
).annotate(num_uncompleted=Count('reviewitem'))

completed_items = Item.objects.filter(
    reviewitem__review=current_review,
    reviewitem__person__reports_to=eff_user,
    reviewitem__reviewed__isnull=False
).select_related(
    'category',
).annotate(num_completed=Count('reviewitem'))

尽管这样做不太方便,但使用Django ORM并不是不可能做到这一点:)

好吧,黑客解决方案不起作用,所以这里有一个漂亮的解决方案;)

生成的查询:

SELECT "test_models_category"."name",
       "test_models_item"."name",
       COUNT("test_models_reviewitem"."reviewed" IS NULL) AS "unreviewed",
       COUNT("test_models_reviewitem"."reviewed" IS NOT NULL) AS "reviewed"
FROM "test_models_reviewitem"
INNER JOIN "test_models_item" ON ("test_models_reviewitem"."item_id" = "test_models_item"."id")
INNER JOIN "test_models_category" ON ("test_models_item"."category_id" = "test_models_category"."id")
GROUP BY "test_models_category"."name",
         "test_models_item"."name"
示例结果:

[{'item__category__name': u'cat a',
  'item__name': u'aa',
  'reviewed': 1,
  'unreviewed': 1},
 {'item__category__name': u'cat a',
  'item__name': u'ab',
  'reviewed': 1,
  'unreviewed': 1},
 {'item__category__name': u'cat b',
  'item__name': u'ba',
  'reviewed': 1,
  'unreviewed': 1},
 {'item__category__name': u'cat b',
  'item__name': u'bb',
  'reviewed': 1,
  'unreviewed': 1}]
Paul Tomblin的更新 如上所述的CountNull和CountNotNull方法不起作用(很明显,布尔值无论是真是假都计为1),因此我对它们进行了如下更改:

from django.db import models


class CountNullSql(models.sql.aggregates.Sum):
    sql_template = '%(function)s((%(field)s IS NULL)::integer)'


class CountNotNullSql(CountNullSql):
    sql_template = '%(function)s((%(field)s IS NOT NULL)::integer)'


class CountNull(models.Sum):
    sql = CountNullSql

    def add_to_query(self, query, alias, col, source, is_summary):
        aggregate = self.sql(
            col,
            source=source,
            is_summary=is_summary,
            **self.extra)
        query.aggregates[alias] = aggregate

    def _default_alias(self):
        return '%s__%s' % (self.lookup, self.sql.__class__.__name__.lower())

    default_alias = property(_default_alias)


class CountNotNull(CountNull):
    sql = CountNotNullSql
试试这个:

params = {'ri_table': ReviewItem._meta.db_table, 'i_table': Item._meta.db_table}
reviewed_query = 'SELECT COUNT(*) FROM %(ri_table)s WHERE %(ri_table)s.item_id=%(i_table)s.id AND reviewed IS NOT NULL' % params
unreviewed_query = 'SELECT COUNT(*) FROM %(ri_table)s WHERE %(ri_table)s.item_id=%(i_table)s.id AND reviewed IS NULL' % params
items = Item.objects.extra(select={'reviewed': reviewed_query, 'unreviewed': unreviewed_query})
这将返回一个项的查询集,这些项本质上用审阅和未审阅的计数进行了注释。每个项目都是一个模型对象,因此可以从中获取类别等
print items.query
将向您显示SQL语句,但当然,Django magic会进一步构建模型实例对象

在一个查询中收集所有这些数据对于Django ORM来说并不优雅(公平地说,它也是一种非平凡的SQL)。这已经够复杂了,我认为不值得去做,至少一开始不值得。Django ORM范例中更简单的代码将更容易理解、更快地编写代码并更易于维护。它可能(也可能不)需要对数据库进行更多的点击,但这种担心可能是过早的优化。模式规范化之类的事情可能会使您获得更大的性能收益。根据您的使用情况,像这样获取计数实际上可能会更快

reviewed = item_obj.reviewitem_set.exclude(reviewed__isnull=True).count()
unreviewed = item_obj.reviewitem_set.filter(reviewed__isnull=True).count()

这可以通过Django 1.8中的内置支持直接完成。请参阅。

对于Django 1.8,可以使用

因此,您的示例查询可能如下所示:

from django.db.models import When, Case, Sum, IntegerField

items = Item.objects.annotate(
    un_reviewed=Sum(Case(When(reviewed__isnull=True, then=1)
                         When(reviewed__isnull=False, then=0),
                         output_field=IntegerField())),
    reviewed=Sum(Case(When(reviewed__isnull=True, then=0)
                      When(reviewed__isnull=False, then=1),
                      output_field=IntegerField())))

很抱歉“maxLength”-我实际上是从内存中输入的。不用担心:)这个答案大概是你想要的还是你需要其他的?有多种方法可以做到这一点,但我认为这是最简单的方法。我会在早上试一试,然后让你知道。嗯。。。回到绘图板上,我想,我会给你回复:)这是返回对象,还是一个dict?澄清一下。您是否在查找每个类别的已审核和未审核项目的数量?或者每个项目的审查次数?您是只想要计数还是想要模型对象的查询集?我想要为每个
项目设置了
已审核日期的
已审核项目的数量,以及没有为每个
项目设置了
已审核日期的数量,但我还想要项目和类别模型对象(或每个字段中至少有两个字段)。你有机会尝试一下吗?让我们知道什么是有效的。我严重怀疑使用“选择计数”子查询是否会是最优的。我同意选择计数可能不会赢得任何速度竞赛,但这是一个解决方案,或者至少是一个起点。你对帮助你的人做出了尖刻的回应……我想知道为什么。这不是尖刻的回应,而是一个原因为什么我认为在你写答案之前已经给出的答案更好。好吧,这很公平。得到最好、最合适的答案就是目标。干杯。
from django.db.models import When, Case, Sum, IntegerField

items = Item.objects.annotate(
    un_reviewed=Sum(Case(When(reviewed__isnull=True, then=1)
                         When(reviewed__isnull=False, then=0),
                         output_field=IntegerField())),
    reviewed=Sum(Case(When(reviewed__isnull=True, then=0)
                      When(reviewed__isnull=False, then=1),
                      output_field=IntegerField())))