在Django ModelAdmin中列出相关字段

16

我在Django的后台通过TabularInline列出一个模型。在这个内联(inline)中,我想使用Django的模型遍历语法来列出通过外键引用该模型的其他模型中的数据。例如:

class MyRelatedModel(models.Model):
    name = models.CharField(max_length=50)
    created = models.DateField(auto_now_add=True)
    other = models.ForeignKey('MyOtherRelatedModel')

class MyOtherRelatedModel(models.Model):
    name = models.CharField(max_length=50)
    created = models.DateField(auto_now_add=True)
        
class MyRelatedModelInline(admin.TabularInline):
    model = MyRelatedModel
    fields = ['name', 'created', 'other__name']
    #readonly_fields = ['name', 'created', 'other__name']

然而,使用 'other__name' 会抛出 ImproperlyConfigured 错误:

'MyRelatedModelInline.fields' refers to field 'other__name' that is missing from the form

模型遍历语法在ModelAdmin实例中是否不受支持?如果支持,那么我做错了什么?

编辑:如果我取消注释readonly_fields,错误会变成:

Caught AttributeError while rendering: 'MyMainModelAdmin' object has no attribute '__name__'

3
可能是在Django管理页面中显示ForeignKey数据的重复问题。 - Daniel Roseman
请看我对那个问题的回答。 - Daniel Roseman
@Roseman,不是的,那是一个不同的问题。请看我的编辑。 - Cerin
由于某些原因,人们似乎对我回答那个问题有疑问。很简单:定义一个方法来返回该值(使用标准的点语法),并在readonly_fields中使用该方法的名称。这样是行得通的。 - Daniel Roseman
2个回答

32
根据Roseman先生的建议,您可以使用内联管理模型以只读方式显示相关(一对一或多对一)数据。以下是一个小例子,以确保我们都在同一页上。如下所示,有三种方式实现您的目标(如果我正确理解了该目标)。

models.py:

class Company(models.Model):
    name = models.CharField(max_length=50)

class Employee(models.Model):
    name = models.CharField(max_length=50)
    company = models.ForeignKey('Company')
    car = models.ForeignKey('Car')

    def model_callable(self):
        return self.car.rego

class Car(models.Model):
    rego = models.CharField(max_length=50)

管理员.py:

def unbound_callable(emp):
    return emp.car.rego

class EmployeeInline(admin.TabularInline):
    model = Employee
    fields = ('name', 'model_callable', 'model_admin_callable', unbound_callable)
    readonly_fields = ('model_callable', 'model_admin_callable', unbound_callable)

    def model_admin_callable(self, emp):
        return emp.car.rego

class CompanyAdmin(admin.ModelAdmin):
    model = Company
    inlines = (EmployeeInline,)

admin.site.register(Company, CompanyAdmin)

根据Django的contrib.admin文档(从1.2版本开始),可以看出'readonly_fields'与'list_display'被同等对待。

在上面的示例中,当您编辑公司时,您将会看到其员工被嵌入其中。每一行将有一个可编辑文本框中的员工姓名,而在姓名旁边,您将看到一个只读的文本位于员工汽车的注册号(emp.car.rego)处。

回到您最初的问题,您想要用'other__name'来引用相关数据。这是行不通的。像other__namecar__rego这样的表达式仅在运行Django查询时作为关键字参数具有特殊意义。例如,在获取具有特定注册号的汽车的员工时:

Employee.objects.filter(car__rego='111')
希望这能帮到你。

2

检查这个示例,它可能会清除你在管理网站上呈现相关字段时的疑惑。

from django.contrib import admin
from . import models


@admin.register(models.Profile)  #Decorator
class ProfileAdmin(admin.ModelAdmin):
    list_display = ['first_name', 'last_name', 'membership', 'phone', 'birth_date']  # Columns to display
    list_select_related = ['user']  # To avoid extra queries

    def first_name(self, profile):
        return profile.user.first_name  # Foreign key relationship
    
    def last_name(self, profile):
        return profile.user.last_name  # Foreign key relationship

在这个例子中,我正在渲染个人资料模型,其中用户是用户模型的外键,用户模型包含名字和姓氏。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接