Как имитировать набор Python с Django ORM? - PullRequest
1 голос
/ 02 августа 2010

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

В настоящее время я использую set для выполнения этого расчета. Смотрите код ниже.

class Member(models.Model):
     ...

class Membership(models.Model):
    member = models.ForeignKey(Member, verbose_name=_("Member"))
    start_date = models.DateField(_("Start date"))
    end_date = models.DateField(_("End date"))

x = Member.objects.filter(Q(membership__start_date__lte=dt1) & Q(membership__end_date__gte=dt1))
y = Member.objects.filter(Q(membership__start_date__lte=dt2) & Q(membership__end_date__gte=dt2))
result = set(x) - set(y)

Я хотел бы знать, что могу сделать это только с помощью ORM django (фильтр, исключить, аннотировать, отличить ...)?

Заранее спасибо за помощь

UPDATE

На самом деле, моя модель немного сложнее. У меня также есть газета внешнего ключа.

class Member(models.Model):
     ...

class Newspaper(models.Model):
     ...

class Membership(models.Model):
    member = models.ForeignKey(Member, verbose_name=_("Member"))
    start_date = models.DateField(_("Start date"))
    end_date = models.DateField(_("End date"))
    newspaper = models.ForeignKey(Newspaper)

Я хочу получить напоминание для данной газеты. В этом случае рабочий запрос

sin = models.Membership.objects.filter(start_date__lte=dt1,
                                               end_date__gte=dt1,
                                               newspaper__id=2)

sout = models.Membership.objects.filter(start_date__lte=dt2,
                                          end_date__gte=dt2,
                                          newspaper__id=2)
result = models.Member.objects.filter(membership__in=sin).exclude(membership__in=sout)

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

Спасибо S.Lott и KillianDS за очень ценные ответы и извините за не очень ясный вопрос:)

Ответы [ 3 ]

6 голосов
/ 02 августа 2010

Разве это не просто отрицание второго выражения и помещение его в тот же фильтр?Таким образом, у вас есть что-то вроде! (A & b), равное (! A) | (! B), в данном случае:

result = Member.objects.filter(membership__start_date__lte=dt1, membership__end_date__gte=dt1, ~Q(membership__start_date__lte=dt2) | ~Q(membership__end_date__gte=dt2))

обратите внимание на то, что для простых поисков и простых поисков вам не нужноОбъекты Q, как я показал с первыми двумя параметрами поиска.Anding происходит, просто передавая несколько аргументов, объекты Q необходимы для отрицания и поиска OR.

3 голосов
/ 02 августа 2010

Таблица реляционной базы данных - это набор - по определению. Установите - равным where not exists в SQL, что равно exclude в ORM Джанго.

Похоже (без тестирования), что вы делаете это.

result = Member.objects.filter(
    Q(membership__start_date__lte=dt1) & Q(membership__end_date__gte=dt1)
).exclude(
    Q(membership__start_date__lte=dt2) & Q(membership__end_date__gte=dt2)
)
1 голос
/ 02 августа 2010

Вы должны попробовать:

result = Member.objects.\
    filter(
        membership__start_date__lte = dt1,
        membership__end_date__gte=dt1).\
    exclude(
        pk__in = \
            Member.objects.filter(
                membership__start_date__lte = dt2,
                membership__end_date__gte = dt2).\
    values_list('pk')
...