使用模型 属性 的 Django 管理列表过滤器
Django admin list filter using a model property
我有如下模型:
class Order(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
number = models.CharField(max_length=36, blank=True, null=True)
external_number = models.CharField(default=None, blank=True, null=True, max_length=250)
@property
def is_external(self) -> bool:
return self.external_number is not None
然后我像下面这样注册我的模型:
@admin.register(Order)
class OrderAdmin(ReadOnlyIDAdminClass):
list_filter = ["number", "is_external"]
list_display = ["id", "is_external"]
但由于 is_external
不是数据库字段,我得到以下错误:
(admin.E116) The value of 'list_filter[1]' refers to 'is_external', which does not refer to a Field
我尝试过创建自定义过滤器之类的方法:
class IsExternal(admin.FieldListFilter):
# Human-readable title which will be displayed in the
# right admin sidebar just above the filter options.
title = 'is external'
# Parameter for the filter that will be used in the URL query.
parameter_name = 'is_external'
def lookups(self, request, model_admin):
return (
('True', True),
('False', False)
)
def queryset(self, request, queryset):
if self.value():
return queryset.filter(external_number__isnull=False)
return queryset.filter(external_number__isnull=True)
然后更新我的管理员:
@admin.register(Order)
class OrderAdmin(ReadOnlyIDAdminClass):
list_filter = ["number", ("is_external", IsExternal)]
list_display = ["id", "is_external"]
但它引发了:
Order has no field named 'is_external'
我觉得有道理,但是有办法吗?我觉得我在搞砸什么。
我认为在尝试修复此问题数小时后,直到现在我才找到了可行的解决方案。
我们利用上面的自定义过滤器,但是我们直接使用它如:
@admin.register(Order)
class OrderAdmin(ReadOnlyIDAdminClass):
list_filter = ["number", IsExternal]
list_display = ["id", "is_external"]
现在应该可以了;另请注意,在我们的过滤器查询集的 self.value()
中,它返回一个字符串,因此我们应该相应地转换/解析我们的值,在我上面的过滤器中,我将获取值 True or False
作为字符串。
编辑:
我已经更新了我的自定义过滤器,使其像 Django 一样运行,我们使用值 1
和 0
来表示 True
和 False
.
class IsExternal(SimpleListFilter):
# Human-readable title which will be displayed in the
# right admin sidebar just above the filter options.
title = 'is external'
# Parameter for the filter that will be used in the URL query.
parameter_name = 'is_external'
def lookups(self, request, model_admin):
return (
(1, 'yes'),
(0, 'no')
)
def queryset(self, request, queryset):
if self.value() == "1":
return queryset.filter(external_number__isnull=False)
elif self.value() == "0":
return queryset.filter(external_number__isnull=True)
return queryset
请注意,这现在使用模型 属性 中定义的相同逻辑(但不是 属性 本身),但在数据库级别。如果有什么方法可以直接使用属性,希望能分享!
我有如下模型:
class Order(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
number = models.CharField(max_length=36, blank=True, null=True)
external_number = models.CharField(default=None, blank=True, null=True, max_length=250)
@property
def is_external(self) -> bool:
return self.external_number is not None
然后我像下面这样注册我的模型:
@admin.register(Order)
class OrderAdmin(ReadOnlyIDAdminClass):
list_filter = ["number", "is_external"]
list_display = ["id", "is_external"]
但由于 is_external
不是数据库字段,我得到以下错误:
(admin.E116) The value of 'list_filter[1]' refers to 'is_external', which does not refer to a Field
我尝试过创建自定义过滤器之类的方法:
class IsExternal(admin.FieldListFilter):
# Human-readable title which will be displayed in the
# right admin sidebar just above the filter options.
title = 'is external'
# Parameter for the filter that will be used in the URL query.
parameter_name = 'is_external'
def lookups(self, request, model_admin):
return (
('True', True),
('False', False)
)
def queryset(self, request, queryset):
if self.value():
return queryset.filter(external_number__isnull=False)
return queryset.filter(external_number__isnull=True)
然后更新我的管理员:
@admin.register(Order)
class OrderAdmin(ReadOnlyIDAdminClass):
list_filter = ["number", ("is_external", IsExternal)]
list_display = ["id", "is_external"]
但它引发了:
Order has no field named 'is_external'
我觉得有道理,但是有办法吗?我觉得我在搞砸什么。
我认为在尝试修复此问题数小时后,直到现在我才找到了可行的解决方案。 我们利用上面的自定义过滤器,但是我们直接使用它如:
@admin.register(Order)
class OrderAdmin(ReadOnlyIDAdminClass):
list_filter = ["number", IsExternal]
list_display = ["id", "is_external"]
现在应该可以了;另请注意,在我们的过滤器查询集的 self.value()
中,它返回一个字符串,因此我们应该相应地转换/解析我们的值,在我上面的过滤器中,我将获取值 True or False
作为字符串。
编辑:
我已经更新了我的自定义过滤器,使其像 Django 一样运行,我们使用值 1
和 0
来表示 True
和 False
.
class IsExternal(SimpleListFilter):
# Human-readable title which will be displayed in the
# right admin sidebar just above the filter options.
title = 'is external'
# Parameter for the filter that will be used in the URL query.
parameter_name = 'is_external'
def lookups(self, request, model_admin):
return (
(1, 'yes'),
(0, 'no')
)
def queryset(self, request, queryset):
if self.value() == "1":
return queryset.filter(external_number__isnull=False)
elif self.value() == "0":
return queryset.filter(external_number__isnull=True)
return queryset
请注意,这现在使用模型 属性 中定义的相同逻辑(但不是 属性 本身),但在数据库级别。如果有什么方法可以直接使用属性,希望能分享!