Многие из многих поисков в Django
Это, вероятно, оскорбительно просто и достойно смеха Нельсона Мунца, но у меня есть настоящий момент braindead, который пытается сделать много разных связей между различными отношениями модели.
У меня есть следующие модели (упрощенные для вашего удовольствия!):
class Document(models.Model):
title = models.CharField(max_length=200)
author = models.ForeignKey(User, blank=True)
content = models.TextField(blank=True)
private = models.BooleanField(default=False)
class UserProfile(models.Model):
user = models.ForeignKey(User, unique=True)
friends = models.ManyToManyField(User, symmetrical=False,
related_name='user_friends')
ignored = models.ManyToManyField(User, symmetrical=False,
related_name='user_ignored')
Отображение следующих пользователей:
- У Алисы есть 3 документа, из которых 1
частный (это означает, что только друзья могут видеть
Это). Она дружит с Бобом,
игнорируя Мэллори и апатично
к Еве (это означает, что не сохранено
отношения).
- У Мэллори есть 2 документа, оба
и является апатичным для всех.
- У Боба есть 1 документ, открытый
и также апатично относится к
все.
- Ева игнорирует Алису и
апатичный для Мэллори и Боба
Пользователи, которые ищут документы, должны иметь следующее:
- Боб, ищущий документы, должен
см. 6, поскольку Алиса сделала его другом
и он может просматривать ее личные
документы.
- Алиса, ищущая документы, должна
см. 4, Боб 1 и ее 3. Она не
см. общедоступные документы Мэллори в качестве
Алиса игнорирует Мэллори.
- Мэллори, ищущие документы, видит
5 - Алиса публичная, ее собственная 2
и Бобс 1. Алиса, игнорирующая ее, не имеет
учитывая то, что Мэллори может видеть, просто
что Алиса не видит Мэллори
документы.
- Ева ищет документы видит 3 -
Мэллори и Боб публичные документы как
она проигнорировала Алису.
В принципе, у меня есть умственная борьба, выясняя фильтры, чтобы возвращать запрошенные мною запросы, описанные выше. У кого-нибудь есть идеи?
ИЗМЕНИТЬ
Благодаря Фердинандам ответ ниже, я смог досконально дойти до того, что хотел с самого начала, что он мне дал.
Во-первых, мы хотим получить список людей, которые меня соприкасались с обратным просмотром через отношения "Множество-много":
friendly_authors = self.user.user_friends.all()
Получить всех людей, которых я проигнорировал:
my_ignored = UserProfile.objects.get(user=self.user).ignored.all()
Получить список документов, которые я могу просмотреть, - документы, которые можно просмотреть, мои или написаны людьми, которые меня дружили, но которых я не игнорировал:
docs = Document.objects.filter(
(Q(viewable=True) | Q(author=self.user) | Q(author__in=friendly_authors))
& ~Q(author__in=my_ignored)
)
Ответы
Ответ 1
Немного сложно, может быть, вы ищете что-то вроде этого:
>>> from django.db.models import Q
>>> me = User.objects.get(pk=1)
>>> my_friends = UserProfile.objects.get(user=me).friends.all()
>>> docs = Document.objects.filter(
... Q(author=me) | (
... Q(author__in=my_friends)
... & ~Q(author__userprofile__ignored=me)
... )
... )
Это генерирует следующий SQL (я сделал некоторое форматирование на исходном выходе):
SELECT "myapp_document".*
FROM "myapp_document" WHERE (
"myapp_document"."author_id" = %s
OR (
"myapp_document"."author_id" IN (
SELECT U0."id" FROM "myapp_user" U0
INNER JOIN "myapp_userprofile_friends" U1
ON (U0."id" = U1."user_id")
WHERE U1."userprofile_id" = %s
)
AND NOT (
"myapp_document"."author_id" IN (
SELECT U2."user_id" FROM "myapp_userprofile" U2
INNER JOIN "myapp_userprofile_ignored" U3
ON (U2."id" = U3."userprofile_id")
WHERE U3."user_id" = %s
)
AND "myapp_document"."author_id" IS NOT NULL
)
)
)