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

use*_*401 5 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
Run Code Online (Sandbox Code Playgroud)

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

ID/Title/Slug/Modified
1   Car     A  1s ago
3   House   B  1s ago
Run Code Online (Sandbox Code Playgroud)

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

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

existing_data = MyModel.objects.filter(slug=slug).latest('modified')
Run Code Online (Sandbox Code Playgroud)

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

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

class ModelManager(models.Manager):
    def get_query_set(self):
        return super(ModelManager, self).get_query_set().group_by('title')
Run Code Online (Sandbox Code Playgroud)

但是我得到了这个错误

'QuerySet' object has no attribute 'group_by'
Run Code Online (Sandbox Code Playgroud)

然后我正在阅读这部分Django书,他们在模型管理器中实现了原始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()]
Run Code Online (Sandbox Code Playgroud)

我是我的模特

objects = ModelManager()
Run Code Online (Sandbox Code Playgroud)

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

'long' object has no attribute '__getitem__'
Run Code Online (Sandbox Code Playgroud)

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

#

在我的admin.py页面中,我可以获得侧过滤器(list_filter),以根据每个线程建议的slug列显示唯一条目...

遗憾的是,根据某个列,我无法将管理页面中显示的行显示为我的模型的唯一性...

Kev*_*vin 6

如果您将 Django 1.4+ 与 PostgreSQL 一起使用,您可以使用带有 *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)
Run Code Online (Sandbox Code Playgroud)

然后您可以在 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)
Run Code Online (Sandbox Code Playgroud)

希望这有帮助。

编辑: 好的,如果你使用 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 |
+----+-------+------+---------------------+
Run Code Online (Sandbox Code Playgroud)

无论任何 order by 子句如何,按 slug 分组都会为您提供 ids 1,2 和 4。我们实际上想要 ids 3、4 和 5,否则 Django 管理员将不会向我们显示最近修改的条目(这就是您所说的)。因此,在我们进行任何分组之前,我们必须从预先排序的表格中进行选择。

我能想到的最好方法是将queryset我为 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
Run Code Online (Sandbox Code Playgroud)

您必须更改id为表的主键myapp_testmodel名称和表的名称。