In my app, we may have new languages or dialects of languages appear at any time, and text written in one language or dialect may need to be translated into another. That's why we handle text by relating text in different languages into "families" (i.e. the translation set into different languages).
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)
Unfortunately this complicates using the Django ORM. When we hit a problem with the app, we're generally saved by using raw SQL to deal with this setup. But I also want to use the Django admin, and I don't see any SQL workaround there.
In particular, there are all sorts of models that have some text that may appear in multiple languages, like so:
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
What I want is to be able to something like this (everything here works except "display_english_string"
):
class ElementAdmin(admin.ModelAdmin):
list_display = ("element_role", "display_element_type", "display_english_string")
This works (using foreign key, as normal):
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'
I want to have something like this also:
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'
For what it's worth, the above gives me AttributeError: 'StringFamily' object has no attribute 'string'
.
Is there a way I can achieve this?
By default Django will create a reverse relation with class_name_set
, so most likely the reverse will be string_set
. If that doesn't work, what I usually do is print(dir(self.string_family))
to see all attributes and usually I'm able to find the correct one.