예제 #1
0
파일: tests.py 프로젝트: zoryamba/django
    def test_aggregate(self):
        """
        filtered_relation() not only improves performance but also creates
        correct results when aggregating with multiple LEFT JOINs.

        Books can be reserved then rented by a borrower. Each reservation and
        rental session are recorded with Reservation and RentalSession models.
        Every time a reservation or a rental session is over, their state is
        changed to 'stopped'.

        Goal: Count number of books that are either currently reserved or
        rented by borrower1 or available.
        """
        qs = Book.objects.annotate(is_reserved_or_rented_by=Case(
            When(reservation__state=Reservation.NEW,
                 then=F('reservation__borrower__pk')),
            When(rental_session__state=RentalSession.NEW,
                 then=F('rental_session__borrower__pk')),
            default=None,
        )).filter(
            Q(is_reserved_or_rented_by=self.borrower1.pk)
            | Q(state=Book.AVAILABLE)).distinct()
        self.assertEqual(qs.count(), 1)
        # If count is equal to 1, the same aggregation should return in the
        # same result but it returns 4.
        self.assertSequenceEqual(
            qs.annotate(total=Count('pk')).values('total'), [{
                'total': 4
            }])
        # With FilteredRelation, the result is as expected (1).
        qs = Book.objects.annotate(active_reservations=FilteredRelation(
            'reservation',
            condition=Q(
                reservation__state=Reservation.NEW,
                reservation__borrower=self.borrower1,
            )), ).annotate(active_rental_sessions=FilteredRelation(
                'rental_session',
                condition=Q(
                    rental_session__state=RentalSession.NEW,
                    rental_session__borrower=self.borrower1,
                )), ).filter((Q(active_reservations__isnull=False)
                              | Q(active_rental_sessions__isnull=False))
                             | Q(state=Book.AVAILABLE)).distinct()
        self.assertEqual(qs.count(), 1)
        self.assertSequenceEqual(
            qs.annotate(total=Count('pk')).values('total'), [{
                'total': 1
            }])
예제 #2
0
    def filter_related(self, name: str, *, include_all=False, **conditions) -> 'HQuerySet':
        """ 利用 FilteredRelation 优化 Query 的方法
        官方文档参见: https://docs.djangoproject.com/en/2.1/ref/models/querysets/#filteredrelation-objects

        还有一种写法是 Manager.from_queryset, 不过那样就没有 Pycharm Django 的补全和提示了,很不好
        https://docs.djangoproject.com/en/2.1/topics/db/managers/#calling-custom-queryset-methods-from-the-manager

        Examples::

            queryset = account.followers.filter(tags__name='rap', tags__deactivated_at__isnull=True)

        Equals to::

            queryset = account.followers.filter_related('tags', name='rap')

        :param name: Django related name
        :param include_all: True to include deactivated instances
        :param conditions: real filters
        """
        filtered_name = f'filtered_{name}'
        key, value = conditions.popitem()
        condition = {f'{filtered_name}__{key}': value}
        if not include_all:
            conditions.setdefault('deactivated_at__isnull', True)
        conditions = {f'{name}__{k}': v for k, v in conditions.items()}
        return self._queryset.annotate(**{filtered_name: FilteredRelation(name, condition=Q(**conditions))}) \
            .filter(**condition)
예제 #3
0
파일: views.py 프로젝트: khc196/newmeet_api
    def get(self, request, *args, **kwargs):
        print(request.user)
        try:
            now = datetime.datetime.today()
            queryset = Party.objects.prefetch_related('place')
            if request.user.is_authenticated:
                queryset = queryset.filter(
                    Q(start_datetime__gte=now)
                    | Q(end_datetime__gte=now)).annotate(
                        party_like1=FilteredRelation(
                            'party_like',
                            condition=Q(party_like__user_id=request.user.id)),
                        is_liked=Case(When(Q(party_like1__isnull=True),
                                           then=False),
                                      When(Q(party_like1__isnull=False),
                                           then=F('party_like1__like')),
                                      output_field=BooleanField()))
            else:
                queryset = queryset.filter(
                    Q(start_datetime__gte=now)
                    | Q(end_datetime__gte=now)).annotate(is_liked=Value(
                        False, BooleanField()), )
            queryset = queryset.order_by('start_datetime', '-like_count')
            page = self.paginate_queryset(queryset)

            if page is not None:
                serializer = self.serializer_class(page, many=True)
                return self.get_paginated_response(serializer.data)
        except Party.DoesNotExist as e:
            raise Http404
예제 #4
0
    def _entry_profile(self) -> None:
        in_query = self.base_query.values('qa__id')

        results = (QualificationAim.objects.filter(
            id__in=Subquery(in_query)).annotate(
                default_address=FilteredRelation(
                    'student__address',
                    condition=Q(student__address__is_default=True)),
                postcode=F('default_address__postcode'),
            ).select_related(
                'student__domicile',
                'student',
            ).order_by('id').distinct())

        for row in results:
            models.EntryProfile.objects.create(
                batch=self.batch,
                instanceid_fk=self._instance_id(row.id),
                domicile=row.student.domicile.hesa_code,
                qualent3=row.entry_qualification_id,
                postcode=_correct_postcode(row.student.termtime_postcode
                                           or row.postcode or '')
                if row.student.domicile.hesa_code in ('XF', 'XG', 'XH', 'XI',
                                                      'XK', 'XL', 'GG', 'JE',
                                                      'IM') else None,
            )
예제 #5
0
def annotate_dataset(queryset, c_filter, bbl_values):
    model_name = list(
        filter(lambda x: c_filter['model'].lower() == x.lower(),
               settings.ACTIVE_MODELS))
    model = getattr(ds, model_name[0])

    queryset = queryset.annotate(
        **{
            c_filter['related_annotation_key']:
            FilteredRelation(c_filter['model'],
                             condition=Q(
                                 construct_and_q(c_filter['query1_filters'])))
        })

    if c_filter['count_annotation_key']:
        serializer_count_key = model_name[0].lower() + 's__count'
        queryset = queryset.annotate(
            **{
                c_filter['count_annotation_key']:
                Count(c_filter['related_annotation_key'], distinct=True)
            })
        # double annotate with a normal key ie: filter_0_hpdviolations__count becomes hpdviolations__count
        queryset = queryset.annotate(
            **{
                serializer_count_key:
                Count(c_filter['related_annotation_key'], distinct=True)
            })

    return queryset
예제 #6
0
 def test_nested_m2m_filtered(self):
     qs = Book.objects.annotate(favorite_book=FilteredRelation(
         'author__favorite_books',
         condition=Q(
             author__favorite_books__title__icontains='book by')), ).values(
                 'title',
                 'favorite_book__pk',
             ).order_by('title', 'favorite_book__title')
     self.assertSequenceEqual(qs, [
         {
             'title': self.book1.title,
             'favorite_book__pk': self.book2.pk
         },
         {
             'title': self.book1.title,
             'favorite_book__pk': self.book3.pk
         },
         {
             'title': self.book4.title,
             'favorite_book__pk': self.book2.pk
         },
         {
             'title': self.book4.title,
             'favorite_book__pk': self.book3.pk
         },
         {
             'title': self.book2.title,
             'favorite_book__pk': None
         },
         {
             'title': self.book3.title,
             'favorite_book__pk': None
         },
     ])
예제 #7
0
 def _assignable_people(self, user):
     return (
         Person.objects.get_queryset().filter(is_vol_prospect=True).filter(
             suppressed_at__isnull=True)
         # Exclude any person already assigned to this user.
         .annotate(my_assignments=FilteredRelation(
             "vol_prospect_assignments",
             condition=Q(vol_prospect_assignments__user=user),
         )).filter(my_assignments=None)
         # Exclude any person with a live (not suppressed, not expired) assignment.
         .annotate(live_assignments=FilteredRelation(
             "vol_prospect_assignments",
             condition=Q(
                 vol_prospect_assignments__suppressed_at__isnull=True)
             & Q(vol_prospect_assignments__expired_at__isnull=True),
         )).filter(live_assignments=None))
예제 #8
0
파일: tests.py 프로젝트: tbbug/django
 def test_deep_nested_foreign_key(self):
     qs = (
         Book.objects.annotate(
             author_favorite_book_editor=FilteredRelation(
                 "author__favorite_books__editor",
                 condition=Q(author__favorite_books__title__icontains="Jane A"),
             ),
         )
         .filter(
             author_favorite_book_editor__isnull=False,
         )
         .select_related(
             "author_favorite_book_editor",
         )
         .order_by("pk", "author_favorite_book_editor__pk")
     )
     with self.assertNumQueries(1):
         self.assertQuerysetEqual(
             qs,
             [
                 (self.book1, self.editor_b),
                 (self.book4, self.editor_b),
             ],
             lambda x: (x, x.author_favorite_book_editor),
         )
예제 #9
0
파일: tests.py 프로젝트: tbbug/django
 def test_nested_m2m_filtered(self):
     qs = (
         Book.objects.annotate(
             favorite_book=FilteredRelation(
                 "author__favorite_books",
                 condition=Q(author__favorite_books__title__icontains="book by"),
             ),
         )
         .values(
             "title",
             "favorite_book__pk",
         )
         .order_by("title", "favorite_book__title")
     )
     self.assertSequenceEqual(
         qs,
         [
             {"title": self.book1.title, "favorite_book__pk": self.book2.pk},
             {"title": self.book1.title, "favorite_book__pk": self.book3.pk},
             {"title": self.book4.title, "favorite_book__pk": self.book2.pk},
             {"title": self.book4.title, "favorite_book__pk": self.book3.pk},
             {"title": self.book2.title, "favorite_book__pk": None},
             {"title": self.book3.title, "favorite_book__pk": None},
         ],
     )
예제 #10
0
파일: models.py 프로젝트: freak-js/ofd
 def get_product(self, product_id):
     if self.is_user():
         filtered_user = self.parent
     else:
         filtered_user = self
     products = Product.objects.annotate(by_user=FilteredRelation('productuserrel', condition = Q(productuserrel__user=filtered_user))).filter(Q(by_user__isnull = True) | Q(by_user__user=filtered_user)).filter(product_is_active=True).filter(product_id=product_id).values_list('product_id', 'product_name', 'product_cost', 'by_user__cost', named=True).order_by('product_name')
     return products[0] if len(products) > 0 else None
 def test_as_subquery(self):
     inner_qs = Author.objects.annotate(book_alice=FilteredRelation(
         'book',
         condition=Q(book__title__iexact='poem by alice')), ).filter(
             book_alice__isnull=False)
     qs = Author.objects.filter(id__in=inner_qs)
     self.assertSequenceEqual(qs, [self.author1])
예제 #12
0
파일: tests.py 프로젝트: guyi2020/blog
 def test_reverse_related_validation_with_filtered_relation(self):
     fields = 'userprofile, userstat, relation'
     with self.assertRaisesMessage(FieldError,
                                   self.invalid_error % ('foobar', fields)):
         list(
             User.objects.annotate(relation=FilteredRelation(
                 'userprofile')).select_related('foobar'))
예제 #13
0
 def test_with_m2m(self):
     qs = Author.objects.annotate(
         favorite_books_written_by_jane=FilteredRelation(
             'favorite_books', condition=Q(favorite_books__in=[self.book2]),
         ),
     ).filter(favorite_books_written_by_jane__isnull=False)
     self.assertSequenceEqual(qs, [self.author1])
예제 #14
0
파일: tests.py 프로젝트: tbbug/django
 def test_nested_foreign_key(self):
     qs = (
         Author.objects.annotate(
             book_editor_worked_with=FilteredRelation(
                 "book__editor",
                 condition=Q(book__title__icontains="book by"),
             ),
         )
         .filter(
             book_editor_worked_with__isnull=False,
         )
         .select_related(
             "book_editor_worked_with",
         )
         .order_by("pk", "book_editor_worked_with__pk")
     )
     with self.assertNumQueries(1):
         self.assertQuerysetEqual(
             qs,
             [
                 (self.author1, self.editor_a),
                 (self.author2, self.editor_b),
                 (self.author2, self.editor_b),
             ],
             lambda x: (x, x.book_editor_worked_with),
         )
예제 #15
0
 def test_with_condition_as_expression_error(self):
     msg = 'condition argument must be a Q() instance.'
     expression = Case(
         When(book__title__iexact='poem by alice', then=True), default=False,
     )
     with self.assertRaisesMessage(ValueError, msg):
         FilteredRelation('book', condition=expression)
예제 #16
0
 def test_with_join(self):
     self.assertSequenceEqual(
         Author.objects.annotate(
             book_alice=FilteredRelation('book', condition=Q(book__title__iexact='poem by alice')),
         ).filter(book_alice__isnull=False),
         [self.author1]
     )
예제 #17
0
 def test_values(self):
     self.assertSequenceEqual(
         Author.objects.annotate(
             book_alice=FilteredRelation('book', condition=Q(book__title__iexact='poem by alice')),
         ).filter(book_alice__isnull=False).values(),
         [{'id': self.author1.pk, 'name': 'Alice', 'content_type_id': None, 'object_id': None}]
     )
예제 #18
0
 def test_select_for_update(self):
     self.assertSequenceEqual(
         Author.objects.annotate(
             book_jane=FilteredRelation('book', condition=Q(book__title__iexact='the book by jane a')),
         ).filter(book_jane__isnull=False).select_for_update(),
         [self.author2]
     )
예제 #19
0
 def test_with_m2m_multijoin(self):
     qs = Author.objects.annotate(
         favorite_books_written_by_jane=FilteredRelation(
             'favorite_books', condition=Q(favorite_books__author=self.author2),
         )
     ).filter(favorite_books_written_by_jane__editor__name='b').distinct()
     self.assertSequenceEqual(qs, [self.author1])
예제 #20
0
 def test_values_list(self):
     self.assertSequenceEqual(
         Author.objects.annotate(
             book_alice=FilteredRelation('book', condition=Q(book__title__iexact='poem by alice')),
         ).filter(book_alice__isnull=False).values_list('book_alice__title', flat=True),
         ['Poem by Alice']
     )
예제 #21
0
 def test_multiple_times(self):
     self.assertSequenceEqual(
         Author.objects.annotate(
             book_title_alice=FilteredRelation('book', condition=Q(book__title__icontains='alice')),
         ).filter(book_title_alice__isnull=False).filter(book_title_alice__isnull=False).distinct(),
         [self.author1]
     )
예제 #22
0
 def test_with_m2m_deep(self):
     qs = Author.objects.annotate(
         favorite_books_written_by_jane=FilteredRelation(
             'favorite_books', condition=Q(favorite_books__author=self.author2),
         ),
     ).filter(favorite_books_written_by_jane__title='The book by Jane B')
     self.assertSequenceEqual(qs, [self.author1])
예제 #23
0
 def test_exclude_relation_with_join(self):
     self.assertSequenceEqual(
         Author.objects.annotate(
             book_alice=FilteredRelation('book', condition=~Q(book__title__icontains='alice')),
         ).filter(book_alice__isnull=False).distinct(),
         [self.author2]
     )
 def test_with_multiple_filter(self):
     self.assertSequenceEqual(
         Author.objects.annotate(book_editor_a=FilteredRelation(
             'book',
             condition=Q(book__title__icontains='book',
                         book__editor_id=self.editor_a.pk),
         ), ).filter(book_editor_a__isnull=False), [self.author1])
 def test_with_foreign_key_on_condition_error(self):
     msg = ("FilteredRelation's condition doesn't support nested relations "
            "(got 'book__editor__name__icontains').")
     with self.assertRaisesMessage(ValueError, msg):
         list(
             Author.objects.annotate(book_edited_by_b=FilteredRelation(
                 'book', condition=Q(book__editor__name__icontains='b')), ))
예제 #26
0
파일: tests.py 프로젝트: tbbug/django
 def test_nested_foreign_key_nested_field(self):
     qs = (
         Author.objects.annotate(
             book_editor_worked_with=FilteredRelation(
                 "book__editor", condition=Q(book__title__icontains="book by")
             ),
         )
         .filter(
             book_editor_worked_with__isnull=False,
         )
         .values(
             "name",
             "book_editor_worked_with__name",
         )
         .order_by("name", "book_editor_worked_with__name")
         .distinct()
     )
     self.assertSequenceEqual(
         qs,
         [
             {
                 "name": self.author1.name,
                 "book_editor_worked_with__name": self.editor_a.name,
             },
             {
                 "name": self.author2.name,
                 "book_editor_worked_with__name": self.editor_b.name,
             },
         ],
     )
예제 #27
0
 def test_relation_name_lookup(self):
     msg = ("FilteredRelation's relation_name cannot contain lookups (got "
            "'book__title__icontains').")
     with self.assertRaisesMessage(ValueError, msg):
         Author.objects.annotate(book_title=FilteredRelation(
             "book__title__icontains",
             condition=Q(book__title="Poem by Alice"),
         ), )
예제 #28
0
 def test_with_generic_foreign_key(self):
     self.assertSequenceEqual(
         Book.objects.annotate(generic_authored_book=FilteredRelation(
             "generic_author",
             condition=Q(generic_author__isnull=False)), ).filter(
                 generic_authored_book__isnull=False),
         [self.book1],
     )
예제 #29
0
 def test_internal_queryset_alias_mapping(self):
     queryset = Author.objects.annotate(
         book_alice=FilteredRelation('book', condition=Q(book__title__iexact='poem by alice')),
     ).filter(book_alice__isnull=False)
     self.assertIn(
         'INNER JOIN {} book_alice ON'.format(connection.ops.quote_name('filtered_relation_book')),
         str(queryset.query)
     )
 def test_only_not_supported(self):
     msg = 'only() is not supported with FilteredRelation.'
     with self.assertRaisesMessage(ValueError, msg):
         Author.objects.annotate(book_alice=FilteredRelation(
             'book',
             condition=Q(book__title__iexact='poem by alice')), ).filter(
                 book_alice__isnull=False).select_related(
                     'book_alice').only('book_alice__state')