TotuDoum
TotuDoum

Reputation: 137

django how to have multiple foreignkey from the same model

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

Upvotes: 4

Views: 7923

Answers (3)

user8724871
user8724871

Reputation:

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

Upvotes: 0

Daniel Roseman
Daniel Roseman

Reputation: 599600

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()

Upvotes: 1

Rohan
Rohan

Reputation: 53326

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.

Upvotes: 12

Related Questions