[Fixed]-Django Abstract Models setting related_name with underscores

13👍

A solution might be not to specify the related_name for habitat and define a default_related_name for all children:

class Animal(models.Model):

    class Meta:
        abstract = True

    habitat = models.ForeignKey(Habitats, on_delete=models.CASCADE)


class DogAnimal(Animal):

    class Meta:
        default_related_name = 'dog_animal'


class CatAnimal(Animal):

    class Meta:
        default_related_name = 'cat_animal'

2👍

It requires a little tweak, but I think you can do this by overriding the ForeignKey class:

from django.utils.text import camel_case_to_spaces


class MyForeignKey(models.ForeignKey):
    def contribute_to_class(self, cls, *args, **kwargs):
        super().contribute_to_class(cls, *args, **kwargs)

        if not cls._meta.abstract:
            related_name = self.remote_field.related_name
            related_query_name = self.remote_field.related_query_name
            underscore_name = camel_case_to_spaces(cls.__name__).replace(" ", "_")
            if related_name:
                self.remote_field.related_name = related_name.format(
                    underscore_name=underscore_name
                )
            if related_query_name:
                self.remote_field.related_query_name = related_query_name.format(
                    underscore_name=underscore_name
                )


class Animal(models.Model):
    class Meta:
        abstract = True

    habitat = MyForeignKey(
        Habitats, on_delete=models.CASCADE, related_name="{underscore_name}"
    )

Leave a comment