Как написать модель Django с отношением ManyToMany к себе через Модель - PullRequest
11 голосов
/ 07 октября 2010

Я хочу иметь модель с ManyToMany отношением к себе, я не знаю, как это написать, но я попытаюсь написать некоторый код, чтобы проиллюстрировать, что я хочу сделать.

class Person(models.Model):
   name = models.CharField()
   occupation = models.CharField()

   friends = models.ManyToManyField('self', through = PersonFriends)

Моя модель, которую я хочу, чтобы друзья прошли через

class PersonFriends(models.Model)
   ???
   comment = models.CharField()

В поле ManyToMany с через отношения , если имя другой модели было "Домашнее животное", например, я 'Назовите мои поля в этом классе person и pet и сделайте их моделями.ForeignKey(Person) и Pet например

Что я могу назвать моей fields в моей PersonFriends модели для двух полей человека теперь, когда они являются одной и той же моделью?

Ответы [ 4 ]

14 голосов
/ 07 октября 2010

Вы можете сделать что-то вроде этого:

class Person(models.Model):
    name = models.CharField(max_length = 255)
    occupation = models.CharField(max_length = 255)
    friends = models.ManyToManyField('self', through = 'PersonFriends', 
          symmetrical = False)
    #     ^^^^^^^^^^^
    # This has to be false when using `through` models. Or else your 
    # model will not validate.

class PersonFriends(models.Model):
    source = models.ForeignKey(Person, related_name = 'source')
    #                                  ^^^^^^^^^^^^
    # You need different `related_name` for each when you have 
    # multiple foreign keys to the same table. 

    target = models.ForeignKey(Person, related_name = 'target')
    comment = models.CharField(max_length = 255)
2 голосов
/ 18 декабря 2014

Не предполагая, что дружба симметрична. Потому что Базз Лайтер может быть другом Вуди, но Вуди не дружит с Базз Лайтер до конца фильма. Вы можете упростить обе модели и при этом иметь разумные имена для поиска. Вам, конечно, нужно убедиться, что вы определяете двух PersonFriends, если это хорошая дружба.

class Person(models.Model):
   name = models.CharField()
   occupation = models.CharField()

class PersonFriends(models.Model):
    from_person = models.ForeignKey(Person, related_name='friends_with')
    to_person = models.ForeignKey(Person, related_name='friends')
    comment = models.CharField()
    class Meta:
        unique_together = ('from_person', 'to_person')

Это имеет дополнительный бонус комментария для каждого направления дружбы. то есть Тирион думает, что Санса - милая и умная, но потерянная девушка. Принимая во внимание, что Санса может подумать, что Тирион - уродливый, но умный и добрый парень.

1 голос
/ 07 октября 2010
class PersonFriends(models.Model):
    from_person = models.ForeignKey(Person, related_name='from_person')
    to_person = models.ForeignKey(Person, related_name='to_person')

это из структуры таблицы базы данных отношения ManyToMany к себе из моей структуры модели. Джанго определяет это так ...

0 голосов
/ 01 июля 2017

Все описано в официальных документах для ManyToManyField.through_fields (вы можете найти фразу «рекурсивные отношения» там, чтобы быстро найти то, что вам нужно):

для django 1.11 у вас естьуказать аргументы through и (!) through_fields:

class Person(models.Model):
    name = models.CharField(max_length=50)

    # note the additional arguments here
    friends = models.ManyToManyField(
        'self',

        # recursive relationships to self with intermediary
        # through model are always defined as non-symmetrical
        symmetrical=False,

        through='PersonFriend',

        # this argument is required to define a custom
        # through model for many to many relationship to self
        # position matters: 1 - source (from), 2 - target (to)
        through_fields=('person', 'friend'),        
    )


class PersonFriend(models.Model):
    # required relationship-defining foreign keys
    # (note that the order does not matter, it matters
    # in 'through_fields' argument in 'friends' field of the 'Person' model)
    person = models.ForeignKey(Person, on_delete=models.CASCADE)
    friend = models.ForeignKey(Person, on_delete=models.CASCADE)

    # additional fields
    comment = models.CharField()
...