在生成 django 管理 URL 时覆盖查询集过滤器

Posted

技术标签:

【中文标题】在生成 django 管理 URL 时覆盖查询集过滤器【英文标题】:Override queryset filters while generating django admin URLs 【发布时间】:2014-07-17 23:43:43 【问题描述】:

我的 models.py 看起来像这样:

class Person(models.Model):
    Name = models.CharField(max_length=100)

class Lecture(models.Model):
    Speaker = model.ForeignKey(Person)
    Topic = models.CharField(max_length=100)
    Choices = ((1,"Upcoming"),(2,"In Progress",),(3,"Completed"))
    Status = models.SmallIntegerField(choices=Choices, default=1, max_length=1)

我的 admin.py 看起来像这样:

class LectureAdmin(admin.ModelAdmin):
    def get_queryset(self):
        return Lecture.objects.exclude(Status='Completed')

因此,我在 django 管理员中的 Lecture 模型更改列表视图仅显示处于“即将到来”和“进行中”状态的 Lectures。这很好用。

现在我需要获取所有讲座列表的 URL,以将其作为视图传递到其他地方。在 django 管理员中执行此操作的标准方法是反转 URL,所以我这样做:

urlresolvers.reverse('admin:%s_%s_changelist' % (app_label, model_name))

但是,当我这样做时,我得到了过滤后的查询集,其中 Lectures 处于“已完成”状态。如何构造一个 url 反向函数来获取整个 Lecture 查询集而不是过滤后的查询集?

【问题讨论】:

【参考方案1】:

这是一个解决方法,看起来很难看,我明白。

all GET 参数添加到changelist url:

url = urlresolvers.reverse('admin:%s_%s_changelist' % (app_label, model_name))
url += '?all'

super() 上调用get_queryset(),仅当request.GET 中没有all 时才排除Completed 状态:

class LectureAdmin(admin.ModelAdmin):
    def get_queryset(self, request):
        qs = super(LectureAdmin, self).get_queryset(request) 
        if 'all' not in request.GET:
            qs = qs.exclude(Status='Completed')
        return qs

UPD(应用来自request.GET 的其他过滤器):

from xadmin.plugin.related import RELATE_PREFIX  # or just set RELATE_PREFIX = '_rel_'

qs = qs.filter(**key[len(RELATE_PREFIX):]: value 
                  for key, value in request.GET.iteritems() 
                  if key.startswith(RELATE_PREFIX))

** 将字典解包为关键字参数。

希望它对你有用。

【讨论】:

这与我使用的查询集方法有什么不同 @Amistad 我已经更新了答案。试一试。谢谢。 这是一个聪明的 hack..为我工作..美丽在于旁观者的眼中..对我来说很漂亮!! @alecxe..我还有一个问题..我正在使用 urlresolvers 专门查找 URL,在我的情况下,这将为我提供与演讲者相关的讲座列表..我的 url have is college/lectures/?_rel_Speaker__id__exact=1 其中,college 是应用程序名称,id 是 Django 自动生成的主键。如何将您的解决方案与此设置结合起来。如果不清楚,我可以编辑我的原始问题.. 我玩了一点..这工作..qs = super(ChangeAdmin, self).queryset() if any([key for key in self.request.GET.keys() if '_rel_' in key.lower()]): qs = qs.filter(Change_status='Completed') return qs ...感谢您的帮助..【参考方案2】:

get_queryset() 是管理列表中使用的基本查询集,因此如果您以这种方式覆盖它,您将无法获取所有记录。

可能的解决方案:

使用过滤器 (https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.filter_vertical) 排除不需要的记录(这些带有 Status='Completed'

Lecture 创建代理模型,在管理员中注册并在给定列表中使用修改后的get_queryset()。代理模型是必需的,因为每个模型只能注册一个 AdminModel

models.py

class IncompletedLecture(Lecture):

    class Meta:
        proxy = True

admin.py

class IncompletedAdmin(admin.ModelAdmin):
    def get_queryset():
        return Lecture.query.exclude(Status='Completed')

admin.site.register(IncompletedLecture, IncompletedAdmin)

【讨论】:

我在管理员中使用 django reversion 来获取对象历史记录和 reversion..Reversion 不适用于代理模型..

以上是关于在生成 django 管理 URL 时覆盖查询集过滤器的主要内容,如果未能解决你的问题,请参考以下文章

输入 Django 管理员添加页面后的 URL 重新路由

如何动态覆盖 Html.ActionLink 生成的 URL?

Django:当它们已经被覆盖时不能覆盖管理模板?

Django:覆盖保存(模型或管理部分)

url查询中的Django自定义排序

如何从视图生成 Django 管理站点中特定项目的 url?