Django ORM:通过过滤器查找获取 verbose_name 字段
Django ORM: Get verbose_name of field via filter lookup
我可以用 MyModel.objects.filter(othermodel__nr='foo')
查询我的模型。
这很好用。
我想获取字段的verbose_name
示例:
class OtherModel(models.Model):
nr=models.IntegerField(verbose_name='Number')
在上面的例子中很容易,因为我可以访问 OtherModel
,但我想做通用的。
如何获取此处 "key" 中使用的字段的详细名称?
MyModel.objects.filter(**{key: value})
我搜索了解决双下划线的方法。在这个例子中 "othermodel__nr" 到(例如)"Number".
更新
在上面的例子中我知道引用的模型是OtherModel
。但我搜索了一个适用于任何字符串的解决方案。例如像这样:
MyModel.objects.filter(**{str_containing_three_double_underscores: 'foo'})
我搜索:
get_verbose_name(str_containing_three_double_underscores) --> MyVerboseName
我不明白你为什么需要 ORM 过滤。如果我答对了你的问题,你已经知道你想要字段详细名称的 class,对吧?
如果是这样,你可以使用ModelName._meta.get_field('field_name').verbose_name
直接获取,根本不需要使用ORM。
我想你可以这样做,假设 filter_key
总是以 "model__field":
结尾
from django.contrib.contenttypes.models import ContentType
def get_verbose_name(filter_key):
model = filter_key.split("__")[-2]
field = filter_key.split("__")[-1]
content_type = ContentType.objects.get(model=model)
return content_type.model_class()._meta.get_field(field).verbose_name
为了处理您对@MoisésHiraldo 的评论,我认为最好在模型的上下文中执行此操作。
from django.db.models.constants import LOOKUP_SEP
from django.core.exceptions import FieldDoesNotExist
from django.utils.encoding import force_text
def get_verbose_name(model, lookup):
# will return first non relational field's verbose_name in lookup
for part in lookup.split(LOOKUP_SEP):
try:
f = model._meta.get_field(part)
except FieldDoesNotExist:
# check if field is related
for f in model._meta.related_objects:
if f.get_accessor_name() == part:
break
else:
raise ValueError("Invalid lookup string")
if f.is_relation:
model = f.related_model
continue
return force_text(f.verbose_name)
get_verbose_name(MyModel, str_containing_three_double_underscores)
递归方式
from django.db.models.constants import LOOKUP_SEP
def get_verbose_name(model_class, field_name: str) -> str:
if LOOKUP_SEP in field_name:
rel_model_name, field_name = field_name.split(LOOKUP_SEP, 1)
rel_model = model_class._meta.get_field(rel_model_name).related_model
return get_verbose_name(rel_model, field_name)
return model_class._meta.get_field(field_name).verbose_name
我可以用 MyModel.objects.filter(othermodel__nr='foo')
查询我的模型。
这很好用。
我想获取字段的verbose_name
示例:
class OtherModel(models.Model):
nr=models.IntegerField(verbose_name='Number')
在上面的例子中很容易,因为我可以访问 OtherModel
,但我想做通用的。
如何获取此处 "key" 中使用的字段的详细名称?
MyModel.objects.filter(**{key: value})
我搜索了解决双下划线的方法。在这个例子中 "othermodel__nr" 到(例如)"Number".
更新
在上面的例子中我知道引用的模型是OtherModel
。但我搜索了一个适用于任何字符串的解决方案。例如像这样:
MyModel.objects.filter(**{str_containing_three_double_underscores: 'foo'})
我搜索:
get_verbose_name(str_containing_three_double_underscores) --> MyVerboseName
我不明白你为什么需要 ORM 过滤。如果我答对了你的问题,你已经知道你想要字段详细名称的 class,对吧?
如果是这样,你可以使用ModelName._meta.get_field('field_name').verbose_name
直接获取,根本不需要使用ORM。
我想你可以这样做,假设 filter_key
总是以 "model__field":
from django.contrib.contenttypes.models import ContentType
def get_verbose_name(filter_key):
model = filter_key.split("__")[-2]
field = filter_key.split("__")[-1]
content_type = ContentType.objects.get(model=model)
return content_type.model_class()._meta.get_field(field).verbose_name
为了处理您对@MoisésHiraldo 的评论,我认为最好在模型的上下文中执行此操作。
from django.db.models.constants import LOOKUP_SEP
from django.core.exceptions import FieldDoesNotExist
from django.utils.encoding import force_text
def get_verbose_name(model, lookup):
# will return first non relational field's verbose_name in lookup
for part in lookup.split(LOOKUP_SEP):
try:
f = model._meta.get_field(part)
except FieldDoesNotExist:
# check if field is related
for f in model._meta.related_objects:
if f.get_accessor_name() == part:
break
else:
raise ValueError("Invalid lookup string")
if f.is_relation:
model = f.related_model
continue
return force_text(f.verbose_name)
get_verbose_name(MyModel, str_containing_three_double_underscores)
递归方式
from django.db.models.constants import LOOKUP_SEP
def get_verbose_name(model_class, field_name: str) -> str:
if LOOKUP_SEP in field_name:
rel_model_name, field_name = field_name.split(LOOKUP_SEP, 1)
rel_model = model_class._meta.get_field(rel_model_name).related_model
return get_verbose_name(rel_model, field_name)
return model_class._meta.get_field(field_name).verbose_name