Django admin: show one instance of duplicate instances

I am trying to show a single instance (row db) from a model where multiple instances use the same field (column) value for multiple rows. To clarify this statement, I have the following situation:

ID/Title/Slug/Modified 1 Car A 1s ago 2 Car A 2s ago 3 House B 1s ago 

If the above small table was my db, I want my Django admin page to display different rows based on my slug field (column) showing the last edited version (I have another column for the time ... So the above the table will show on the administration page as follows:

 ID/Title/Slug/Modified 1 Car A 1s ago 3 House B 1s ago 

Although lines 1 and 2 have different pk, they have the same slime, I want only one of them with a later time ...

I can achieve this in my views.py as follows

 existing_data = MyModel.objects.filter(slug=slug).latest('modified') 

but this is because I am looking for a specific instance of a bullet. If I were not, I could also use group_by ...

I am trying to get this display on the admin page. I tried using the following methods in the model manager,

 class ModelManager(models.Manager): def get_query_set(self): return super(ModelManager, self).get_query_set().group_by('title') 

but i get this error

 'QuerySet' object has no attribute 'group_by' 

Then I read , and they implemented raw sql in the model manager, which I tried to copy into my situation properly,

 class ModelManager(models.Manager): def uniques(self): cursor = connection.cursor() cursor.execute(""" SELECT * FROM eventform_event GROUP BY slug """) return [row[0] for row in cursor.fetchone()] 

Im my model I have

 objects = ModelManager() 

I'm just not sure how to get the admin model to view my custom manager, which does not override get_query_set. When I used this user manager to override get_query_set, I get this error

 'long' object has no attribute '__getitem__' 

I also tried to test the values ​​(), values_list (), distinct (), etc., but they all give me errors ... distinct () tells me that my database (mysql) does not support this function. Now I am sure that I need to switch databases to achieve this function, and now I have no idea to experiment with ... Does anyone know how to achieve this functionality .. Thanks.

#

On my admin.py page, I can get a side filter (list_filter) to show unique entries based on the slug column in this thread of recommendation ...

Unfortunately, I cannot get the rows displayed on the admin page so that my model is unique based on a specific column ...

+4
source share
1 answer

If you are using Django 1.4+ with PostgreSQL, you can use queryset.distinct () with * fields argument. If you are using an earlier version of Django or another database engine, let me know and I will develop another way to do this.

So, if your model looks something like this:

 from django.db import models class TestModel(models.Model): title = models.TextField(max_length=150) slug = models.TextField(max_length=150) modified = models.DateTimeField(auto_now=True) 

Then you can do this in the ModelAdmin queryset method:

 from django.contrib import admin import models class TestModelAdmin(admin.ModelAdmin): list_display = ('title', 'slug', 'modified') def queryset(self, request): qs = super(TestModelAdmin, self).queryset(request) qs = qs.order_by('slug', '-modified').distinct('slug') return qs admin.site.register(models.TestModel, TestModelAdmin) 

Hope this helps.

Edit: Well, if you use MySQL, this is not quite so neat. You cannot use raw SQL because the Django administrator expects to work with QuerySet, not RawQuerySet. Even if we could use raw SQL, it would not be as simple as GROUP BY slug , because if you do this, MySQL will give you the results in the order that they will be displayed in the table. Therefore, if your data looks like this:

 +----+-------+------+---------------------+ | id | title | slug | modified | +----+-------+------+---------------------+ | 1 | Car | A | 2013-06-30 20:18:06 | | 2 | House | B | 2013-06-30 20:18:12 | | 3 | Car | A | 2013-06-30 21:02:51 | | 4 | Thing | C | 2013-06-30 22:08:00 | | 5 | House | B | 2013-06-30 22:08:05 | +----+-------+------+---------------------+ 

Grouping by slug gives you identifiers 1,2 and 4 regardless of any order by clause. We really need identifiers 3, 4, and 5, because otherwise the Django administrator will not show us the most recently modified record (which, as you say, you want). Therefore, before we can do any grouping, we must select from a pre-sorted table.

The best way I can come up with is to change the queryset method in the answer I gave for PostgreSQL:

 def queryset(self, request): qs = super(TestModelAdmin, self).queryset(request) qs = qs.extra(where=[ "id IN ( SELECT id FROM ( SELECT * FROM myapp_testmodel ORDER BY modified DESC ) AS last_modified GROUP BY slug)" ]) return qs 

You will need to change id to the name of the primary key of your table and myapp_testmodel to the name of your table.

+4
source

Source: https://habr.com/ru/post/1488969/


All Articles