如何在Django admin中按外来对象的值过滤对象

时间:2014-07-07 05:55:43

标签: python django django-models django-admin

有表格ProductTransaction。在Product admin中,有一个字段显示已使用此产品创建了多少交易。

现在,我想过滤创建这些事务的时间段。例如,上周有30笔交易,但上个月有100笔交易。

class Transaction(models.Model):
    created = models.DateTimeField()
    product = models.ForeignKey('Product')

class Product(models.Model):
    name = models.CharField()

    def num_of_trans(self):
        return Transaction.objects.filter(created="""DATE_VALUE_HERE""").filter(product=self.id).count()

我尝试在queryset扩展的类中调整SimpleListFilter,但是我无法使其正常工作。

我想到的另一件事是向num_of_trans函数添加一个额外的参数,但似乎在使用过滤器时无法传递此参数。

我很感激任何提示。

修改

class MyListFilter(admin.SimpleListFilter):
    title = _('period')
    parameter_name = 'period'

    def lookups(self, request, model_admin):
        return (
            ('7', _('last week')),
            ('30', _('last month')),
        )

    def queryset(self, request, queryset):
        period = timezone.now() + timedelta(days=self.value()))
        return queryset.filter(transactions__gte=period)
        # of course it won't work, but represents the idea

2 个答案:

答案 0 :(得分:0)

from datetime import datetime, timedelta

class Transaction(models.Model):
    created = models.DateTimeField()
    product = models.ForeignKey('Product', related_name='products')

class Product(models.Model):
    name = models.CharField()

    def num_of_trans_last_week(self):
        now = datetime.now()
        self.products.filter(created__range=(now-timedelta(days=7), now)).count()

答案 1 :(得分:0)

虽然我尽量不使用带有ORM的纯SQL,但在这种情况下使用“extra”是我能想到的唯一方法。进行2次额外查询。

class MyListFilter(admin.SimpleListFilter):
    title = _('period')
    parameter_name = 'period'

    def lookups(self, request, model_admin):
        return (
            ('7', _('last week')),
            ('30', _('last month')),
        )

    def queryset(self, request, queryset):
        if self.value():  # Count transactions by date
            period = timezone.now() - timedelta(days=int(self.value())
            transaction_ids = Transaction.objects\
                    .filter(created__gte=period)\
                    .values_list('id', flat=True)

            qs = queryset.extra(select={
                    "num_transactions": """
                      SELECT COUNT(*)
                      FROM appname_transaction 
                      WHERE appname_transaction.id IN ({}) 
                      AND appname_transaction.product_id = appname_product.id
                      """.format(", ".join([str(t_id) for t_id in transaction_ids]))
            })

        else:  # Count all
            qs = queryset.extra(select={
                    "num_transactions": """
                      SELECT COUNT(*)
                      FROM appname_transaction 
                      WHERE appname_transaction.product_id = appname_product.id
                      """
            })
        return qs


class ProductAdmin(admin.ModelAdmin):
    list_filter = [MyListFilter, ]
    list_display = [..., 'num_transactions']
    ...

    def num_transactions(self, obj):
        return getattr(obj, 'num_transactions')