Home > Software design >  Can't set postgresql foreign key using django between two tables
Can't set postgresql foreign key using django between two tables

Time:10-29

Trying to find out the best way to model my data.

I have one table for pokemon types:

class PokemonTypesTest2(models.Model):
    name = models.CharField(max_length=25, unique=True)

It just has an ID and name, it will have 18 rows in it. I want to be able to relate multiple tables to it, for example base Pokemon model below ( i cleared out most of the data to be easier to follow:

class BasePokemonTest2(models.Model):
    #other data hidden #
    type1 = models.ForeignKey(PokemonTypesTest2, on_delete=models.CASCADE, default=1)
    type2 = models.ForeignKey(PokemonTypesTest2, on_delete=models.CASCADE, default=1)
    type3 = models.ForeignKey(PokemonTypesTest2, on_delete=models.CASCADE, default=1)


    weaknessResistanceImmune = models.ManyToManyField(PokemonTypesTest2, through='WeakResistImmune2')

I want to be able to relate a pokemon typing to a pokemon from base pokemon table.

The problem is I get this error from Django:

ERRORS:
battlefield.BasePokemonTest2.type1: (fields.E304) Reverse accessor 'PokemonTypesTest2.basepokemontest2_set' for 'battlefield.BasePokemonTest2.type1' clashes with reverse accessor for 'battlefield.BasePokemonTest2.type2'.
        HINT: Add or change a related_name argument to the definition for 'battlefield.BasePokemonTest2.type1' or 'battlefield.BasePokemonTest2.type2'.

I see the hint but don't understand what it means?

CodePudding user response:

With a ForeignKey, If you do not override the default by specifying an argument of "related_name" then Django will use a name made up from the source model name (PokemonTypesTest2) lowercased and appended with "_set". This gives you access to a Manager that returns all instances of PokemonTypesTest2 related to your BasePokemonTest2 instance. e.g.

>>> p = BasePokemonTest2.objects.get(id=1)
>>> p.pokemontypestest2_set.all()  # Returns all PokemonTypesTest2 objects related to BasePokemonTest2 instance

Django Docs: Following Relationships "backward"

So your type1, type2 and type3 assignments in your BasePokemonTest2 model are all attempting to have a name of "basepokemontest2_set". This is not allowed as each related_name (in one model definition) has to be unique of course. Hence the hint from Django recommending you use related_name to resolve the clash.

So, to work as you wanted in your code above, you would need something like:

type1 = models.ForeignKey(PokemonTypesTest2, on_delete=models.CASCADE, default=1, related_name="type1")
type2 = models.ForeignKey(PokemonTypesTest2, on_delete=models.CASCADE, default=1, related_name="type2")
type3 = models.ForeignKey(PokemonTypesTest2, on_delete=models.CASCADE, default=1, related_name="type3")

However, I don't think this is really what you want? I suspect you probably just want:

type = models.ForeignKey(PokemonTypesTest2, on_delete=models.CASCADE, default=1)

(You can also still add related_name above (setting it to whatever you want) if you don't want the default _set name.)

You can then access all PokemonTypesTest2 related to one BasePokemonTest2 as mentioned above.

  • Related