4

Here is my model:

class Item(models.Model):
    name = models.CharField(max_length=30)
    ...
    choices = (
        ('weapon', 'weapon'),
        ('shield', 'shield'),
    )
    typeOf = models.CharField(max_length=15, choices=choices)



class Character(models.Model):
    name = models.CharField(max_length=30, unique=True)
    ...
    weapon = models.ForeignKey(Inventory) // **THIS IS WHAT I WANT TO DE BUT DOES'NT WORK**
    shield = models.ForeignKey(Inventory) // **THIS IS WHAT I WANT TO DE BUT DOES'NT WORK**
    inventory = models.ManyToManyField(Item, through='Inventory')




class Inventory(models.Model):
    character = models.ForeignKey('Character')
    item = models.ForeignKey('Item')

I know how to add item to inventory but now I want to equip them. How do I do the foreign key? I want to be able to equip weapon from my inventory

Machavity
  • 30,841
  • 27
  • 92
  • 100
TotuDoum
  • 137
  • 2
  • 11
  • Possible duplicate of [How can I have two foreign keys to the same model in Django?](https://stackoverflow.com/questions/543377/how-can-i-have-two-foreign-keys-to-the-same-model-in-django) – Aaron McMillin Aug 14 '17 at 14:30

3 Answers3

12

You need to add related_name to the field definition

...
weapon = models.ForeignKey(Inventory, related_name='weapons') 
shield = models.ForeignKey(Inventory, related_name='shields')
...

Without the related_name, django will try to create character_set attribute in Inventory model, but it will fail for 2nd.

Rohan
  • 52,392
  • 12
  • 90
  • 87
1

If you did want to do this, you would need a related_name on each FK, as the error message would have made clear. However, you don't want to do this, as it makes no sense.

You don't want to have both the many-to-many relationship for Item, and the specific Inventory relationships. You need one or the other. Can a character have more inventory items than just a single weapon and shield? If not, then drop the many-to-many; but the ForeignKeys should point directly at Item:

class Character(models.Model):
    ...
    weapon = models.ForeignKey(Item, related_name="weapon_players")
    shield = models.ForeignKey(Item, related_name="shield_players")

Otherwise, you should drop the two foreign keys and just use the many-to-many. You can add methods or properties to your Character model to get the inventory item that is the weapon or shield. Also, since you're not doing anything extra on the through table, you can remove it; Django will provide one automatically.

class Character(models.Model):
    ...
    inventory = models.ManyToManyField(Item)

    @property
    def shield(self):
        return self.inventory.filter(typeOf='shield').first()

    @property
    def shield(self):
        return self.inventory.filter(typeOf='weapon').first()
Daniel Roseman
  • 588,541
  • 66
  • 880
  • 895
0

This is an old question but I'd like to add something I learned today that may be helpful:

https://pypi.python.org/pypi/django-composite-foreignkey http://django-composite-foreignkey.readthedocs.io/en/latest/quickstart.html

Before making multiple foreign keys you have to declare a composite primary key by adding unique_togther attribute in meta. By following the provided guide you can declare mutiple columns as foreign keys in your django projects

Anthony L
  • 2,159
  • 13
  • 25