在Django Admin中按无字段过滤

时间:2014-12-24 18:53:25

标签: django django-models

如何解决这个问题?

model.py

class Sale(models.Model):
    customer = models.ForeignKey(Customer, related_name='customer_sale')

...

    def get_itens(self):
        return self.sales_det.count()
    item = property(get_itens)

class SaleDetail(models.Model):
    sale = models.ForeignKey(Sale, related_name='sales_det')
    product = models.ForeignKey(Product, related_name='product_det')
    quantity = models.PositiveSmallIntegerField()

admin.py

class SaleAdmin(admin.ModelAdmin):
    list_display = ('__unicode__', 'customer', 'get_itens', 'get_total')
    readonly_fields = ['get_total']
    list_filter = ('customer','item')

问题

在这种情况下如何按项目过滤? 因为如果没有使用属性创建的字段或计算字段或字段,我不会过滤。

错误消息追溯

ERRORS:
<class 'vendas_project.vendas.admin.SaleAdmin'>: (admin.E116) The value of 'list_filter[1]' refers to 'item', which does not refer to a Field.

1 个答案:

答案 0 :(得分:2)

ModelAdmin list_filter接受从django.contrib.admin.SimpleListFilter继承的字段或类,您需要向其提供title和parameter_name属性并覆盖查找和查询集方法。在这种情况下,您可以选择第二个选项并执行以下操作:

class ItemCountListFilter(admin.SimpleListFilter):
    # Human-readable title which will be displayed in the
    # right admin sidebar just above the filter options.
    title = 'item count'

    # Parameter for the filter that will be used in the URL query.
    parameter_name = 'count'

    def lookups(self, request, model_admin):
        """
        Returns a list of tuples. The first element in each
        tuple is the coded value for the option that will
        appear in the URL query. The second element is the
        human-readable name for the option that will appear
        in the right sidebar.
        """
        max_value = Sale.objects.all().annotate(
            count_items=Count('sales_det')
        ).aggregate(max_value=Max('count_items'))['max_value']
        return [(i, i) for i in range(0, max_value)]

    def queryset(self, request, queryset):
        """
        Returns the filtered queryset based on the value
        provided in the query string and retrievable via
        `self.value()`.
        """
        # Compare the requested value (either '80s' or '90s')
        # to decide how to filter the queryset.
        return queryset.annotate(
            count_items=Count('sales_det')
        ).filter(
            count_items=self.value()
        )


class SaleAdmin(admin.ModelAdmin):
    list_display = ('__unicode__', 'customer', 'get_itens', 'get_total')
    readonly_fields = ['get_total']
    list_filter = ('customer', ItemCountListFilter)


admin.site.register(Sale, SaleAdmin)