iducam
iducam

Reputation: 79

Django model field clashes with other model field that doesn't exist?

I'm getting this error:

ERRORS:
pokollector.CustomPokemon.poke_id: (models.E006) The field 'poke_id' clashes with the field 'poke_id' from model 'pokollector.pokemon'.

Here's the relevant code:

class Pokemon(models.Model):
    poke_name = models.CharField(max_length=30)
    poke_type = models.ManyToManyField(PokeType)
    evolves_from = False
    evolves_into = False
    gen_added = models.PositiveIntegerField(validators=[min(1), max(gen)])

    class Meta:
        verbose_name_plural = 'Pokemon'

    def __str__(self):
        return self.poke_name


class CustomPokemon(Pokemon):
    #Add name and level for user's specific Pokemon
    poke_id = models.ForeignKey(Pokemon, on_delete=models.CASCADE, 
        related_name='poke_id', verbose_name='Pokemon ID')
    name = models.CharField(max_length=30, blank=True)
    level = models.PositiveIntegerField(blank=True, null=True)
    #add owner attr

    class Meta:
        verbose_name_plural = 'Custom Pokemon'

    def save(self):
        if not self.name:
            self.name = self.poke_name
        super().save()

    def __str__(self):
        return self.name

As you can see, I have two models, one of which inherits from the other. The error in question relates to the poke_id field in CustomPokemon. I thought this might be some weird conflict caused by inheritance, but if I change the field name to pokemon_id, the issue is resolved.

While a workaround like that gets my code running, I'm curious what the underlying principle is here; Why does the exact same code run after adding those three letters?

Upvotes: 1

Views: 1091

Answers (1)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 476659

The related_name=… parameter [Django-doc] is the name of the relation in reverse. So it access the related CustomPokemon objects for a given Pokemon. This thus means that Pokemon has an "impliciet field" if you want that is here named poke_id. Since CustomPokemon inherits from Pokemon, there are now two poke_id fields, hence the clash.

It however does not make much sense to specify related_name='poke_id'. You can for example use custompokemons` instead:

class CustomPokemon(Pokemon):
    poke_id = models.ForeignKey(
        Pokemon,
        on_delete=models.CASCADE, 
        related_name='custompokemons',
        verbose_name='Pokemon ID'
    )
    # …

Note: Normally one does not add a suffix _id to a ForeignKey field, since Django will automatically add a "twin" field with an _id suffix. Therefore it should be pokemon, instead of poke_id.

Upvotes: 1

Related Questions