В 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')