Администратор Django: как отсортировать по одному из пользовательских list_display полей, которое не имеет никакого поля базы данных

# admin.py
class CustomerAdmin(admin.ModelAdmin):  
    list_display = ('foo', 'number_of_orders')

# models.py
class Order(models.Model):
    bar = models.CharField[...]
    customer = models.ForeignKey(Customer)

class Customer(models.Model):
    foo = models.CharField[...]
    def number_of_orders(self):
        return u'%s' % Order.objects.filter(customer=self).count()  

Как я мог отсортировать Клиентов, в зависимости от number_of_orders они имеют?

admin_order_field свойство не может использоваться здесь, поскольку оно требует поля базы данных к виду на. Действительно ли это возможно вообще, поскольку Django полагается на базовый DB для выполнения сортировки? Создание совокупного поля для содержания количества заказов походит на излишество здесь.

Забавная вещь: при изменении URL вручную в браузере к виду на этом столбце - он работает как ожидалось!

113
задан mike_k 30 January 2010 в 16:06
поделиться

2 ответа

Единственный способ, который я могу придумать, - это денормализовать поле. То есть - создать реальное поле, которое будет обновляться, чтобы оставаться в синхронизации с полями, из которых оно получено. Я обычно делаю это, переопределяя save on либо моделью с денормализованными полями, либо моделью, из которой она получена:

# models.py
class Order(models.Model):
    bar = models.CharField[...]
    customer = models.ForeignKey(Customer)
    def save(self):
        super(Order, self).save()
        self.customer.number_of_orders = Order.objects.filter(customer=self.customer).count()
        self.customer.save()

class Customer(models.Model):
    foo = models.CharField[...]
    number_of_orders = models.IntegerField[...]
0
ответ дан 24 November 2019 в 02:43
поделиться

Я не тестировал это (мне было бы интересно узнать, работает ли это), но что если определить пользовательский менеджер для Customer, который включает количество заказов, агрегированных, а затем установить admin_order_field в это агрегированное поле, т.е.

from django.db import models 


class CustomerManager(models.Manager):
    def get_query_set(self):
        return super(CustomerManager, self).get_query_set().annotate(models.Count('order'))

class Customer(models.Model):
    foo = models.CharField[...]

    objects = CustomerManager()

    def number_of_orders(self):
        return u'%s' % Order.objects.filter(customer=self).count()
    number_of_orders.admin_order_field = 'order__count'

EDIT: Я только что протестировал эту идею, и она отлично работает - не требуется подклассификация django admin!

49
ответ дан 24 November 2019 в 02:43
поделиться
Другие вопросы по тегам:

Похожие вопросы: