3

How to resolve this?

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')

Question

How to filter by item in this case? Because i dont filter if no field or calculated field or field created with property.

Error message trace back

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.
Regis Santos
  • 3,469
  • 8
  • 43
  • 65
  • Filters only work on fields. See this answer for more information: http://stackoverflow.com/questions/1205375/filter-by-property – Brandon Taylor Dec 24 '14 at 19:17
  • I resolved with if 'filter_sale_zero' in self.request.GET: qs = Sale.objects.annotate( itens=Count('sales_det')).filter(itens=0) – Regis Santos Dec 24 '14 at 20:32
  • But how to work in Django Admin? – Regis Santos Dec 24 '14 at 20:32
  • You would need to override the initial queryset if the filter parameter is in the `request.GET` dictionary. See: https://docs.djangoproject.com/en/1.7/ref/contrib/admin/#django.contrib.admin.ModelAdmin.get_queryset for more information. – Brandon Taylor Dec 24 '14 at 20:34
  • @Brandon show me a example, please. – Regis Santos Dec 24 '14 at 22:23
  • Am on my mobile, but basically you have access to the request object from the get_queryset override. From there you can look at request.GET parameters and filter the queryset by whatever parameters are there. You'll need to compare your property value in a loop. – Brandon Taylor Dec 24 '14 at 22:36
  • This is not a duplicate of https://stackoverflow.com/questions/1205375/filter-by-property! That one is about ORM filters, while this is about django-admin filters, which is a very different thing. – frnhr Jul 10 '19 at 18:00

1 Answers1

4

ModelAdmin list_filter accepts either fields or a class inheriting from django.contrib.admin.SimpleListFilter, which you need to provide the title and parameter_name attributes to and override the lookups and queryset methods. In this case you could take the second option and do something like:

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)
suselrd
  • 734
  • 4
  • 10