Django 관리자 : 데이터베이스 필드가없는 사용자 지정 list_display 필드 중 하나로 정렬하는 방법


122
# 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을 변경하면 예상대로 작동합니다!


"재미있는 점 : 브라우저에서 직접 URL을 변경하여이 열을 정렬하면 예상대로 작동합니다!" 의미 : / admin / myapp / customer /? ot = asc & o = 2 계속 하시겠습니까?
Andy Baker

예, asc와 dsc 모두. 어쩌면 소수로만 작동 할 수도 있습니다.
mike_k

여러 페이지에서 작동하지 않을 것이라고 생각합니다.
Chase Seibert

답변:


159

이 문제에 대한 Greg의 솔루션이 마음에 들었지만 관리자에서 직접 동일한 작업을 수행 할 수 있다는 점을 지적하고 싶습니다.

from django.db import models

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

    def get_queryset(self, request):
    # def queryset(self, request): # For Django <1.6
        qs = super(CustomerAdmin, self).get_queryset(request)
        # qs = super(CustomerAdmin, self).queryset(request) # For Django <1.6
        qs = qs.annotate(models.Count('order'))
        return qs

    def number_of_orders(self, obj):
        return obj.order__count
    number_of_orders.admin_order_field = 'order__count'

이렇게하면 관리 인터페이스 내에서만 주석을 달 수 있습니다. 당신이 수행하는 모든 쿼리가 아닙니다.


5
예, 이것이 훨씬 더 나은 방법입니다. :)
그렉

2
있습니다 제안 편집 이 답변에가. 너무 많은 텍스트를 제거했기 때문에 거부하기로 결정했습니다. 저는 Django를 모릅니다. 제안 된 코드 변경이 언급 할 가치가 있는지 모르겠습니다.
Gilles 'SO- 사악한 중지'

1
@Gilles 제안 된 편집은 더 간단한 number_of_orders 정의에 대해 정확합니다. 작동 : def number_of_orders(self, obj): return obj.order__count
Nils

1
get_queryset()대신 해야 하지 queryset()않습니까?
Mariusz Jamro

2
get_queryset (self, request) : ... for Django 1.6+
michael

50

나는 이것을 테스트하지 않았지만 (작동하는지 알고 싶습니다) 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'

편집 : 방금이 아이디어를 테스트했으며 완벽하게 작동합니다. django 관리자 서브 클래 싱이 필요하지 않습니다!


1
이것은 받아 들여진 것보다 더 나은 대답입니다. 내가 받아 들인 것을 적용하는 문제는 관리자 수준에서 업데이트 된 쿼리 세트와 함께 무언가를 검색 할 때 너무 많은 시간이 걸리고 발견 한 결과에 대해 잘못된 카운트가 발생한다는 것입니다.
Mutant

0

내가 생각할 수있는 유일한 방법은 필드를 비정규 화하는 것입니다. 즉, 파생 된 필드와 동기화 상태를 유지하도록 업데이트되는 실제 필드를 만듭니다. 일반적으로 비정규 화 된 필드가있는 모델 또는 파생 된 모델 중 하나에 대한 저장을 재정 의하여이 작업을 수행합니다.

# 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[...]

1
이것은 확실히 작동하지만 추가 DB 필드가 관련되어 있으므로 허용됨으로 표시 할 수 없습니다. 또한 쿼리 세트 행 끝에 .count ()가 누락되어 있습니다.
mike_k 2010

count ()를 수정했습니다. (contrib.admin의 큰 덩어리를 서브 클래 싱하는 것보다 부족한) 유일한 다른 해결책은 Jquery / Ajaxy 해킹입니다.
Andy Baker
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.