简体   繁体   中英

Django Models ManyToMany and Foreign Key

Trying to get a better handle on how django database relationships are handled. Any thoughts are appreciated.

Considering the following example models:

class Things(models.Model):
    name = models.CharField(max_length=20)

class Stuff(models.Model):
    name = models.CharField(max_length=20)
    information = models.ManyToManyField('Information')
    things = models.ForeignKey('Things')

class Information(models.Model):
    name = models.CharField(max_length=20)
    stuff = models.ForeignKey('Stuff')

An error results from syncdb : AttributeError: 'ManyToManyField' object has no attribute 'ForeignKey' . The error results if I include both the ManyToManyField and the Foreign Key fields in the Stuff model.

Is there a way that I can make both of these relationships exist? Thanks for any ideas.

If you want to know how many information are linked to each stuff , django will provide a default manager that will allow you to go backwards; for this you don't need a foreign key in stuff .

class Things(models.Model):
    name = models.CharField(max_length=20)

class Stuff(models.Model):
    name = models.CharField(max_length=20)
    information = models.ManyToManyField('Information')
    things = models.ForeignKey('Things')

class Information(models.Model):
    name = models.CharField(max_length=20)

This model will allow you to do queries like:

  • "What is the information for stuff X ?"
  • "For stuff Y , what information is linked?"
  • "Find me all stuff and information for thing Z "

In addition it will allow you have multiple information for each stuff and multiple stuff for each thing .

Writing down these questions at the start will help you develop accurate models without unnecessary links/relations in your database.

My version of django gives a bit more information:

Error: One or more models did not validate:
foo.stuff: Reverse query name for m2m field 'information' clashes with field 'Information.stuff'. Add a related_name argument to the definition for 'information'.
foo.information: Reverse query name for field 'stuff' clashes with m2m field 'Stuff.information'. Add a related_name argument to the definition for 'stuff'.

Which is probably enough to get you going. Define a related_name for both the ManyToManyField relationship and the ForeignKey relationship from Information to Stuff...

information = models.ManyToManyField('Information', related_name='stuff_many_set')
stuff = models.ForeignKey('Stuff', related_name = 'info_set')

then syncdb will be happy. Of course, you should be sure that you need both the relationships. With the generic entity names here it looks like there may be some confusion.

Fundamentally you would get an error like this:

$python manage.py syncdb
Error: One or more models did not validate:
t.stuff: Reverse query name for m2m field 'information' clashes with field  'Information.stuff'. Add a related_name argument to the definition for 'information'.
t.information: Reverse query name for field 'stuff' clashes with m2m field 'Stuff.information'. Add a related_name argument to the definition for 'stuff'.

why? simple you have two tables referencing each other, the problem here is that when reverse look ups are applied django will generate the same name, creating a clash.

To fix this issue, like the error states, you need to add related_name this way django knows how to distinguish the different reverse calls.

from django.db import models

class Things(models.Model):
    name = models.CharField(max_length=20)

class Stuff(models.Model):
    name = models.CharField(max_length=20)
    information = models.ManyToManyField('Information', related_name = 'information_information')
    things = models.ForeignKey('Things')

class Information(models.Model):
    name = models.CharField(max_length=20)
    stuff = models.ForeignKey('Stuff', related_name = 'information_stuff')

Sorry Im not very creative with the names, this should work.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM