Django Admin:显示重复实例的单个实例

时间:2013-06-30 16:24:55

标签: django django-models django-admin

我正在尝试从模型中显示单个实例(db行),其中多个实例共享多行的相同字段(列)值。为澄清该陈述,我有以下情况:

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

如果上面的小表是我的db我希望我的Django管理页面显示基于我的slug字段(列)的不同行显示最后编辑的版本(我有另一列时间...所以上面的表格会显示在管理页面中,如下所示:

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

虽然第1行和第1行2有不同的pk,他们有相同的slug,我只希望其中一个与更晚的时间......

我可以在我的views.py中实现这一点,如下所示

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

但那是因为我正在寻找一个特定的slug实例..如果我不是,我也可以使用group_by ......

我正在尝试在管理页面中显示此内容。我在模型管理器中尝试了以下技术,

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

但我收到此错误

'QuerySet' object has no attribute 'group_by'

然后我正在阅读this part of the Django book并且他们在模型管理器中实现了原始sql,我尝试按照以下方式复制到我的情况,

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()]

我是我的模特

objects = ModelManager()

我只是不确定如何让管理模型查看我的自定义管理器,它不会覆盖get_query_set。当我使用此自定义管理器覆盖get_query_set时,我收到此错误

'long' object has no attribute '__getitem__'

我也尝试过测试'values(),values_list(),distinct()等但是它们都给我错误... distinct()告诉我我的数据库(mysql)不支持这个功能..现在确定我是否必须切换数据库以实现此功能,现在我没有想法进行实验......任何人都知道如何实现此功能..谢谢。

在我的admin.py页面中,我可以获得旁边过滤器(list_filter),以根据每this thread推荐的slug列显示唯一条目...

不幸的是,基于某个列,我无法将管理页面中显示的行显示为我的模型唯一...

1 个答案:

答案 0 :(得分:4)

如果您在PostgreSQL中使用Django 1.4+,则可以使用带有* fields参数的queryset.distinct()。如果您使用的是较旧版本的Django或其他数据库引擎,请告诉我,我会以不同的方式进行操作。

因此,如果您的模型看起来像这样:

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)

然后您可以在ModelAdmin的queryset方法中执行此操作:

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)

希望这有帮助。

修改 好吧,如果你使用的是MySQL,它就不那么整洁了。您不能使用原始SQL,因为Django管理员希望使用QuerySet而不是RawQuerySet。即使我们可以使用原始SQL,它也不会像GROUP BY slug那么简单,因为如果你这样做,MySQL会按照它们在表中出现的顺序给出结果。因此,如果您的数据如下所示:

+----+-------+------+---------------------+
| 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 |
+----+-------+------+---------------------+

按句子分组,无论是否有任何order by子句,都会给你id 1,2和4。我们实际上需要ID 3,4和5,否则Django管理员不会向我们显示最近修改过的条目(这就是你想要的)。因此,在我们进行任何分组之前,我们必须从预先排序的表中进行选择。

我能想到的最好的方法是将我给PostgreSQL的答案中的queryset方法更改为:

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

您必须将id更改为表格主键名称,并将myapp_testmodel更改为表格名称。