Domanda

I have a model called Person and a person may or may not have several relationship; spouse, children, parents. If the Person has a spouse, but that spouse isn't a person in the database, I want to be able to keep the spouse as just a string value and not another Person. Because of that I assume I need a through model specified on the m2m relationships:

class Person(models.Model):
    spouse = models.ManyToManyField('self', through='Relationship')
    children = models.ManyToManyField('self', through='Relationship')
    parents = models.ManyToManyField('self', through='Relationship')

class Relationship(models.Model):
    personA = models.ForeignKey(Person)
    personB = models.ForeignKey(Person, blank=True, null=True)
    person_name = models.TextField(default='', blank=True)
    relationship = models.CharField(choices=(('s', 'spouse'),
                                             ('c', 'child'),
                                             ('p', 'parent')),
                                    default='s')

When I try to run the ./manage.py migrate I get the following error messages showing up:

CommandError: One or more models did not validate:
myapp.person: Many-to-many fields with intermediate tables cannot be symmetrical.
myapp.person: Many-to-many fields with intermediate tables cannot be symmetrical.
myapp.person: The model Person has two manually-defined m2m relations through the model Relationship, which is not permitted. Please consider using an extra field on your intermediary model instead.
myapp.person: Many-to-many fields with intermediate tables cannot be symmetrical.
myapp.person: The model Person has two manually-defined m2m relations through the model Relationship, which is not permitted. Please consider using an extra field on your intermediary model instead.
myapp.relationship: Accessor for field 'personA' clashes with related field 'Person.relationship_set'. Add a related_name argument to the definition for 'personA'.
myapp.relationship: Accessor for field 'personB' clashes with related field 'Person.relationship_set'. Add a related_name argument to the definition for 'personB'.

Obviously I'm doing it wrong.

How can I specify relationships between the same model with extra data associated with that relationship?

Alternatively, how else might you structure these models to keep track of the same data?

È stato utile?

Soluzione

Error creating several recursive m2m relationships seems like a related question. I realized that I could get the same effect by removing the parents, children, spouse fields from the Person model and setting the related_name to relationships on the Relationship model.

class Person(models.Model):
    [ other fields ]

class Relationship(models.Model):
    personA = models.ForeignKey(Person, related_name='relationships')
    personB = models.ForeignKey(Person, blank=True, null=True)
    person_name = models.TextField(default='', blank=True)
    relationship = models.CharField(choices=(('s', 'spouse'),
                                             ('c', 'child'),
                                             ('p', 'parent')),
                                    default='s')

I haven't tested it yet, but it does validate and doesn't throw the error messages any more. This also seems cleaner.

I imagine I could create some properties on the Person model to give me access to say Person.spouse which returns all Person.relationships where the relationship == 's'.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top