Django admin: วิธีจัดเรียงตามฟิลด์ 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 อาศัยฐานข้อมูลพื้นฐานในการจัดเรียง การสร้างฟิลด์รวมเพื่อให้มีจำนวนคำสั่งซื้อดูเหมือนจะเกินความจำเป็น

สิ่งที่น่าสนุก: หากคุณเปลี่ยน 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
ใช่นี่เป็นวิธีที่ดีกว่ามาก :)
Greg

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 (ตัวเองขอ): ... สำหรับ 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
นี่เป็นคำตอบที่ดีกว่าเมื่อเทียบกับคำตอบที่ยอมรับ ปัญหาที่ฉันพบในการใช้สิ่งที่ยอมรับคือเมื่อคุณค้นหาบางสิ่งพร้อมกับแบบสอบถามที่อัปเดตในระดับผู้ดูแลระบบต้องใช้เวลามากเกินไปและยังมีการนับผิดสำหรับผลลัพธ์ที่พบ
กลายพันธุ์

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

แก้ไขการนับ () วิธีแก้ปัญหาอื่น ๆ เท่านั้น (ย่อมาจาก subclassing กลุ่มใหญ่ของผู้ช่วยผู้ดูแลระบบ) คือแฮ็ค Jquery / Ajaxy
Andy Baker
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.