4

I have the following code:

#models.py
class Repair(models.Model):
    products = models.ManyToManyField(Product)
    description = models.TextField()

    def products_list(self):
        return ', '.join([a.name for a in self.products.all()])

class Product(models.Model):
    name = models.CharField(max_length=50,blank=False)
    description = models.TextField(blank=True)


#admin.py
class RepairAdmin(admin.ModelAdmin):
    list_display = ('products_list', 'description')

As you can see I use a custom model field with a join to show all repair related products on the ModelAdmin list_display property, this is working corretcly.

Now my question is: How I can make the custom field sortabe on the list_display? I only want to sort by the first item on the ManyToMany relashiontship. I tried to use the following code on the model:

products_list.admin_order_field = 'products__name'

Including this line I can activate the field sorting, but its not working correctly... When field sorting is requested it shows as many record duplications on the table as relations it has.

I've been researching and the closest thing to a solution I found is this:

Django admin: how to sort by one of the custom list_display fields that has no database field

But I dont see the correct way to apply it to my case.

Community
  • 1
  • 1
Khonix
  • 4,128
  • 1
  • 16
  • 15

1 Answers1

5

You're seeing "as many record duplicates on the table as relations it has" because 'products__name' is getting all the Products related to the Repair.

If you want to sort by the first item on the ManyToMany relationship products in your ModelAdmin, then it's probably easiest to make a property that gets the first product--then assign it to the admin_order_field:

class Repair(models.Model):
    products = models.ManyToManyField(Product)
    description = models.TextField()

    def products_list(self):
        return ', '.join([a.name for a in self.products.all()])

    # add a property which gets the name of the first product
    @property
    def first_product(self):
        self.products.all().first()  # first() was added in 1.6, otherwise use [0]


class RepairAdmin(admin.ModelAdmin):
    list_display = ('products_list', 'description')
    # use that property to only get the first product when ordering
    products_list.admin_order_field = 'first_product__name'
pcoronel
  • 3,833
  • 22
  • 25
  • Thanks for your reply, i've tried to apply this code, but the admin_order_field property does not accept the 'first_product__name' value. django throws the following error: FieldError at /admin/support/repair/ Cannot resolve keyword 'first_product' into field. Choices are: description, id, products – Khonix May 28 '14 at 12:46
  • This will already cause a `NameError`, because `products_list.admin_order_field` cannot be assigned. `products_list` would have to be a method of `RepairAdmin`. But then it still appears that a custom property cannot be used here. – blueyed Jul 01 '14 at 14:29
  • admin_order_field must be a model field name, because the ordering is done by the database. Thus, `myfield`, `related_field__name`, etc. can work, but not `myproperty`. – merwok Feb 13 '19 at 04:53