5

我试图从一个模型中显示一个实例(db 行),其中几个实例共享多行的相同字段(列)值。为了澄清这一说法,我有以下情况:

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

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

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

虽然第 1 行和第 2 行有不同的 pk,但它们有相同的 slug,但我只想要其中一个,后面的时间......

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

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

但那是因为我正在寻找一个特定的蛞蝓实例。如果不是,我也可以使用 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'

然后我正在阅读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()]

我是我的模特

objects = ModelManager()

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

'long' object has no attribute '__getitem__'

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

#

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

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

4

1 回答 1

6

如果您将 Django 1.4+ 与 PostgreSQL 一起使用,则可以将queryset.distinct()与 *fields 参数一起使用。如果您使用的是旧版本的 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 子句如何,按 slug 分组都会为您提供 ID 1、2 和 4。我们实际上想要 id 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

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

于 2013-06-30T18:39:03.487 回答