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