Как моделировать симметричные отношения с django?
Используйте классический пример друзей.
class Friendship(models.Model):
user1 = models.ForeignKey(User, related_name='friends1')
user2 = models.ForeignKey(User, related_name='friends2')
handshakes = models.PositiveIntegerField()
hugs = models.PositiveIntegerField()
# other silly data
Двое друзей в дружбе (user1 и user2) должны быть полностью равны. Я должен быть в состоянии сказать, что (user1, user2) уникальны, и не нужно беспокоиться о (user2, user1), случайно появляющемся. Я должен был бы легко получить всех друзей данного пользователя, но вместо этого мне пришлось бы написать собственный менеджер или создать другой способ получения всех Друзей, в которых этот пользователь является user1 в отношениях, и всех Друзей, где этот пользователь является пользователем2.
Я подумываю о попытке написать свой собственный SymmetricKey. Кто-то, пожалуйста, остановите меня.
Ответы
Ответ 1
Проверьте symmetrical
параметр ManyToManyField
в документы - похоже, что он может делать то, что вы хотите.
Для конкретного способа, которым вы это делаете, я бы сделал что-то вроде
class LameUserExtension(User):
friends = ManyToManyField("self", through=Friendship)
class Friendship(models.Model):
# the stuff you had here
Ответ 2
Я нашел хорошую статью, обсуждая, что некоторое время назад основы были следующими:
class Person(models.Model):
name = models.CharField(max_length=100)
relationships = models.ManyToManyField('self', through='Relationship',
symmetrical=False,
related_name='related_to+')
RELATIONSHIP_FOLLOWING = 1
RELATIONSHIP_BLOCKED = 2
RELATIONSHIP_STATUSES = (
(RELATIONSHIP_FOLLOWING, 'Following'),
(RELATIONSHIP_BLOCKED, 'Blocked'),
)
class Relationship(models.Model):
from_person = models.ForeignKey(Person, related_name='from_people')
to_person = models.ForeignKey(Person, related_name='to_people')
status = models.IntegerField(choices=RELATIONSHIP_STATUSES)
Обратите внимание на знак плюса в конце связанного_имя. Это указывает на Django, что обратное отношение не должно быть раскрыто. Поскольку отношения являются симметричными, это желаемое поведение, в конце концов, если я дружу с человеком A, тогда человек A дружит со мной. Django не будет создавать симметричные отношения для вас, поэтому немного нужно добавить в методы add_relationship и remove_relationship, чтобы явно обрабатывать другую сторону отношения:
def add_relationship(self, person, status, symm=True):
relationship, created = Relationship.objects.get_or_create(
from_person=self,
to_person=person,
status=status)
if symm:
# avoid recursion by passing `symm=False`
person.add_relationship(self, status, False)
return relationship
def remove_relationship(self, person, status, symm=True):
Relationship.objects.filter(
from_person=self,
to_person=person,
status=status).delete()
if symm:
# avoid recursion by passing `symm=False`
person.remove_relationship(self, status, False)
Теперь, когда мы создаем отношения, идущие в одну сторону, его дополнение создается (или удаляется). Поскольку отношения идут в обоих направлениях, мы можем просто использовать:
def get_relationships(self, status):
return self.relationships.filter(
to_people__status=status,
to_people__from_person=self)
Источник: Самостоятельная привязка многих ко многим через