Django Abstract Models使用下划线设置related_name

rti*_*dru 9 python django django-models django-related-manager

我有一个抽象基础模型和2个继承模型,我需要强制related_name采用特定格式.

class Animal(models.Model):
    legs = models.IntegerField(related_name='%(class)s')
    habitat = models.ForeignKey(Habitats, related_name='%(class)s')

class DogAnimal(BaseModel):
    name = models.CharField(max_length=20, related_name='dog_animal')

class CatAnimal(BaseModel):
    name = models.CharField(max_length=20, related_name='cat_animal')
Run Code Online (Sandbox Code Playgroud)

通常,related_name ='%(class)s'将分别导致catanimal和doganimal.

我需要像这样的强调值:dog_animal,cat_animal

以下是"为什么"我需要这样做 - 遗产.这些模型没有使用基类组织 - 因此最初指定的related_name是'dog_animal'和'cat_animal'.改变这将是很多工作.

Ant*_*ard 8

一个解决方案可能不是为所有孩子指定related_nameforhabitat并定义 a default_related_name

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'
Run Code Online (Sandbox Code Playgroud)


Ant*_*ard 2

它需要一些调整,但我认为你可以通过覆盖该类来做到这一点ForeignKey

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}"
    )
Run Code Online (Sandbox Code Playgroud)