gpt4 book ai didi

Django-Admin:来自 UserProfile 的 list_filter 属性

转载 作者:行者123 更新时间:2023-12-02 02:05:18 26 4
gpt4 key购买 nike

我希望允许我的网站管理员在管理网站上过滤来自特定国家/地区的用户。所以自然的做法是这样的:

#admin.py
class UserAdmin(django.contrib.auth.admin.UserAdmin):
list_filter=('userprofile__country__name',)

#models.py
class UserProfile(models.Model)
...
country=models.ForeignKey('Country')

class Country(models.Model)
...
name=models.CharField(max_length=32)

但是,由于 django 中处理用户及其用户配置文件的方式,这会导致以下错误:

'UserAdmin.list_filter[0]' refers to field 'userprofile__country__name' that is missing from model 'User'

如何绕过此限制?

最佳答案

您正在寻找的是自定义管理FilterSpecs。坏消息是,对那些可能不会很快发布的支持(您可以跟踪讨论 here )。

但是,您可以以肮脏的黑客行为为代价来解决该限制。在深入研究代码之前如何构建 FilterSpecs 的一些要点:

  • 构建要在页面上显示的 FilterSpec 列表时,Django 使用您在 list_filter 中提供的字段列表
  • 这些字段必须是模型上的真实字段,而不是反向关系,也不是自定义属性。
  • Django 维护一个 FilterSpec 类列表,每个类都与一个 test 函数关联。
  • 对于 list_filter 中的每个字段,Django 将使用第一个 FilterSpec 类,其中 test 函数返回 True 对于该领域。

好的,现在考虑到这一点,看看下面的代码。改编自a django snippet 。代码的组织由您自行决定,只需记住这应该由 admin 应用导入。

from myapp.models import UserProfile, Country
from django.contrib.auth.models import User
from django.contrib.auth.admin import UserAdmin

from django.contrib.admin.filterspecs import FilterSpec, ChoicesFilterSpec
from django.utils.encoding import smart_unicode
from django.utils.translation import ugettext_lazy as _

class ProfileCountryFilterSpec(ChoicesFilterSpec):
def __init__(self, f, request, params, model, model_admin):
ChoicesFilterSpec.__init__(self, f, request, params, model, model_admin)

# The lookup string that will be added to the queryset
# by this filter
self.lookup_kwarg = 'userprofile__country__name'
# get the current filter value from GET (we will use it to know
# which filter item is selected)
self.lookup_val = request.GET.get(self.lookup_kwarg)

# Prepare the list of unique, country name, ordered alphabetically
country_qs = Country.objects.distinct().order_by('name')
self.lookup_choices = country_qs.values_list('name', flat=True)

def choices(self, cl):
# Generator that returns all the possible item in the filter
# including an 'All' item.
yield { 'selected': self.lookup_val is None,
'query_string': cl.get_query_string({}, [self.lookup_kwarg]),
'display': _('All') }
for val in self.lookup_choices:
yield { 'selected' : smart_unicode(val) == self.lookup_val,
'query_string': cl.get_query_string({self.lookup_kwarg: val}),
'display': val }

def title(self):
# return the title displayed above your filter
return _('user\'s country')

# Here, we insert the new FilterSpec at the first position, to be sure
# it gets picked up before any other
FilterSpec.filter_specs.insert(0,
# If the field has a `profilecountry_filter` attribute set to True
# the this FilterSpec will be used
(lambda f: getattr(f, 'profilecountry_filter', False), ProfileCountryFilterSpec)
)


# Now, how to use this filter in UserAdmin,
# We have to use one of the field of User model and
# add a profilecountry_filter attribute to it.
# This field will then activate the country filter if we
# place it in `list_filter`, but we won't be able to use
# it in its own filter anymore.

User._meta.get_field('email').profilecountry_filter = True

class MyUserAdmin(UserAdmin):
list_filter = ('email',) + UserAdmin.list_filter

# register the new UserAdmin
from django.contrib.admin import site
site.unregister(User)
site.register(User, MyUserAdmin)

这显然不是万能药,但它会完成这项工作,等待更好的解决方案出现。(例如,将继承 ChangeList 并覆盖 get_filters 的解决方案)。

关于Django-Admin:来自 UserProfile 的 list_filter 属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2251851/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com