在Django中从对象_meta动态获取外键的详细名称

时间:2018-09-19 16:30:02

标签: django django-models meta

为简单起见,请使用以下模型:

 class Plan(models.Model)
     name = models.CharField(max_length=255, verbose_name="Phone Plan Name")
     monthly_charge = models.FloatField()
 class Company(models.Model):
     name = models.CharField(max_length=255, verbose_name="Company Full Name")
     phone_plan = models.ForeignKey(Plan)
 class Client(models.Model):
     name = models.CharField(max_length=255, verbose_name="Client Full Name")
     company = models.ForeignKey(Company)

给出一个字符串,我想知道是否存在一种简单的方法来检索模型属性的详细名称,即使该字符串通过外键遍历也是如此。

我知道我可以通过

获得Client属性的详细名称
Client._meta.get_field("name").verbose_name 

这将导致“客户端全名”。

但是如果我有字符串“ company__phone_plan__name”,该怎么办呢?

Client._meta.get_field("company__phone_plan__name").verbose_name

到达“电话计划名称”,因为它会产生错误。

这些字符串将是动态的,所以我想知道即使遍历模型,最简单的方法是得出属性的适当冗长名称吗?

这种特殊情况是使用Django 1.11

2 个答案:

答案 0 :(得分:3)

这不是一个很好的答案,但是如果您需要什么,可以使用此功能:

def get_verbose_name(model, string):
    fields = string.split('__')

    for field_name in fields[:-1]:
        field = model._meta.get_field(field_name)

        if field.many_to_one:
            model = field.foreign_related_fields[0].model
        elif field.many_to_many or field.one_to_one or field.one_to_many:
            model = field.related_model
        else:
            raise ValueError('incorrect string')

    return model._meta.get_field(fields[-1]).verbose_name

此函数获取模型名称和字符串并返回详细名称

您可以像这样使用它:

get_verbose_name(Client, 'company__phone_plan__name')

答案 1 :(得分:1)

如果您正在使用模型的实例,则可以尝试以下方法:

c = Client.objects.first()

# c._meta.get_field('company').verbose_name
# c.company._meta.get_field('phone_plan').verbose_name
c.company.phone_plan._meta.get_field('name').verbose_name

如果仅使用类,那么它会更复杂:

field_company = Client._meta.get_field('company')
field_phone_plan = field_company.rel.to._meta.get_field('phone_plan')
field_name = field_phone_plan.rel.to._meta.get_field('name')
field_name.verbose_name

# or one long line
s = Client._meta.get_field('company') \
    .rel.to._meta.get_field('phone_plan') \
    .rel.to._meta.get_field('name') \
    .verbose_name

编辑: 用户@AndreyBerenda指出,第二个选项在Django 2.1中对他不起作用;我仅在问题中指定的1.11中进行了测试。