В Django Admin, как мне ссылаться на обратные отношения внешних ключей для `list_display`?

В моем приложении в любой момент могут появиться новые языки или диалекты языков, и текст, написанный на одном языке или диалекте, может потребоваться перевести на другой. Поэтому мы работаем с текстом, объединяя тексты на разных языках в "семейства" (т. е. набор переводов на разные языки).

class StringFamily(models.Model):
    id = models.AutoField(primary_key=True)
    # plus some other fields


class String(models.Model):
    id = models.AutoField(primary_key=True)

    # the reference to StringFamily
    family = models.ForeignKey(StringFamily, null=False, on_delete=models.CASCADE)

    # other important stuff
    language = models.ForeignKey(Language, on_delete=models.DO_NOTHING)
    dialect = models.ForeignKey(Dialect, null=True, on_delete=models.SET_NULL)
    text = models.TextField(null=False)

К сожалению, это усложняет использование Django ORM. Когда мы сталкиваемся с проблемой в приложении, нас обычно спасает использование необработанного SQL для работы с этой настройкой. Но я также хочу использовать админку Django, и я не вижу никакого обходного пути для SQL.

В частности, есть всевозможные модели, в которых есть текст, который может отображаться на нескольких языках, например, так:

class Element(models.Model):
    id = models.AutoField(primary_key=True)
    element_role = models.ForeignKey(ElementRole, null=False, on_delete=models.RESTRICT)
    string_family = models.ForeignKey(StringFamily, null=True, on_delete=models.SET_NULL)
    # plus more fields

Я хочу иметь возможность сделать что-то вроде этого (здесь все работает, кроме "display_english_string"):

class ElementAdmin(admin.ModelAdmin):
    list_display = ("element_role", "display_element_type", "display_english_string")

Это работает (используя внешний ключ, как обычно):

class Element(models.Model):
    # first model definition, then...
    def display_element_type(self) -> str:
        return str(self.element_role.element_type)

    display_element_type.short_description = 'Element Type'

Я тоже хочу иметь что-то вроде этого:

class Element(models.Model):
    # first above code, then...
    def display_english_string(self) -> str:
        strings = self.string_family.strings # this is the reference I would like to work but doesn't
        english_string = strings.filter(language="eng").values("text")[0]
        return english_string

    display_english_string.short_description = 'English Text'

Если уж на то пошло, то вышеприведенное дает мне AttributeError: 'StringFamily' object has no attribute 'string'.

Есть ли способ добиться этого?

По умолчанию Django создает обратное отношение с помощью class_name_set, поэтому, скорее всего, обратным будет string_set. Если это не срабатывает, я обычно делаю print(dir(self.string_family)), чтобы увидеть все атрибуты, и обычно мне удается найти нужный.

Если вы хотите получить доступ к экземплярам String, связанным с StringFamily, через атрибут strings, вам нужно изменить определение ForeignKey, добавив related_name, например, так:

family = models.ForeignKey(StringFamily, null=False, on_delete=models.CASCADE, related_name='strings')
Вернуться на верх