python / expert
Snippet
Django Q-Objekte für Komplexe Datenbankabfragen
Django Q-Objekte ermöglichen komplexe OR/AND-Datenbankabfragen, die mit einfachen filter()-Aufrufen nicht erreicht werden können. Dieses Beispiel demonstriert den Aufbau dynamischer Suchabfragen mit mehreren optionalen Filtern, Kombinieren von Lookups mit bitweisen Operatoren und Verwendung bedingter Annotationen zur Berechnung von Rabattpreisen. Die verwandten Produkte-Abfrage zeigt erweiterte Übereinstimmung mit Annotation und zufälliger Sortierung.
snippet.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
from django.db.models import Q, Count, F, Case, When, IntegerFieldfrom django.db.models.functions import Concatfrom.models import Product, Categoryclass ProductManager(models.Manager):def search_products(self, query, category=None, min_price=None, max_price=None, in_stock=None, is_featured=None):"""Complex product search with multiple filter conditions."""queryset = self.get_queryset()search_query = Q(name__icontains=query) | \Q(description__icontains=query) | \Q(sku__iexact=query)if category:search_query &= Q(category__slug=category)price_query = Q()if min_price is not None:price_query &= Q(price__gte=min_price)if max_price is not None:price_query &= Q(price__lte=max_price)stock_query = Q()if in_stock is True:stock_query = Q(stock_quantity__gt=0)elif in_stock is False:stock_query = Q(stock_quantity=0)featured_query = Q(is_featured=True) if is_featured else Q()combined_query = search_query & price_query & stock_query & featured_queryreturn queryset.filter(combined_query).select_related('category').annotate(category_product_count=Count('category__products'),discounted_price=Case(When(discount__gt=0, then=F('price') * (1 - F('discount') / 100)),default=F('price'),output_field=IntegerField())).order_by('-is_featured', '-created_at')def get_related_products(self, product, limit=5):"""Find related products using category and tag matching."""return self.get_queryset().filter(Q(category=product.category) | Q(tags__in=product.tags.all()),Q(is_active=True) & ~Q(pk=product.pk)).annotate(matching_criteria=Count('category') + Count('tags')).order_by('-matching_criteria', '?')[:limit]
django
Erklärung
1
from django.db.models import Q, Count, F, Case, When, IntegerField
Importiere Q-Objekte und Aggregations-/Bedingungshelfer
2
search_query = Q(name__icontains=query) | Q(description__icontains=query)
Erstelle OR-Abfrage mit Pipe-Operator und case-insensitive contains
3
if category: search_query &= Q(category__slug=category)
Füge AND-Bedingung zu bestehender Query mit &= Operator hinzu
4
price_query = Q() if min_price is None and max_price is None else Q(price__gte=min_price) & Q(price__lte=max_price)
Baue Preisbereichsabfrage bedingt auf
5
combined_query = search_query & price_query & stock_query & featured_query
Kombiniere alle Query-Komponenten mit AND-Logik
6
discounted_price=Case(When(discount__gt=0, then=F('price') * (1 - F('discount') / 100)), default=F('price'))
Verwende Case/When für bedingte Annotations-Berechnung
7
matching_criteria=Count('category') + Count('tags')
Annotiere mit Anzahl der übereinstimmenden Kriterien für Ranking
8
order_by('-matching_criteria', '?')
Sortiere nach Relevanz dann randomisiere innerhalb gleicher Rang