اگر با Django کار می کنید و نمایش داده شد ، احتمالاً شما در شرایطی قرار گرفته اید که باید فیلترها را به روشی ترکیب کنید که فقط … ساده نیست.

شاید شما در حال تلاش برای جستجوی کاربران با نام کاربری هستید یا ایمیلی که با چیزی مطابقت دارد. یا شاید شما سعی می کنید نتایج را فیلتر کنید که یک شرط صحیح باشد اما دیگری نادرست است.

این جایی است که Q وارد می شود

من اولین باری را که به این مشکل رسیدم – به یاد می آورم – سعی کردم از آن استفاده کنم or در الف .filter() و درک سریع آن منطق معمولی پایتون در آنجا خوب بازی نمی کند.

پیام های خطا گیج کننده بود و اسناد به خیلی کمک نمی کردند. بنابراین بگذارید آن را برای شما به روشی ساده و عملی تجزیه کنم.

با پایان این راهنما ، دقیقاً می فهمید که چه چیزی Q این است که چگونه کار می کند ، و چگونه می تواند نمایش داده های Django شما را تمیز تر ، قدرتمندتر و بسیار انعطاف پذیر تر کند.

فهرست مطالب

  • q همه در مورد چیست؟

  • روش استفاده از Q در جنگو

    • مثال 1: یا منطق

    • مثال 2: و منطق (هنوز هم با Q مفید است)

    • مثال 3: منطقی نیست

  • چه زمانی باید از Q استفاده کنید؟

  • مخلوط کردن Q و فیلترهای منظم

  • مثال در دنیای واقعی: فیلتر کردن محصولات

  • gotchas (چیزهایی که باید مراقب آن باشید)

  • سوالات متداول

    • آیا استفاده از Q کندتر از یک فیلتر معمولی () است؟

    • آیا می توانم از Q با حاشیه نویسی () یا کل () استفاده کنم؟

    • آیا می توانم اشیاء Q را به صورت پویا بسازم؟

  • منابع بیشتر

  • پیچیدن

q همه در مورد چیست؟

در جنگو ، Q شی (از django.db.models) به شما امکان می دهد با استفاده از پرس و جوهای پیچیده استفاده کنید یابا وتوت نه منطق – کاری که فقط با استفاده از آن به طور منظم انجام می شود .filter() تماس ها

به طور معمول ، هنگام استفاده .filter() در Django ، آن را اضافه می کند و منطق مانند این:

MyModel.objects.filter(name='Alice', age=30)

این همه ردیف ها را به دست می آورد name است ، 'Alice' وت در age است ، 30بشر اما اگر بخواهید چه می کنید:

همه ردیف ها را در جایی که نام “آلیس” است دریافت کنید یا سن 30 سال است؟

شما فقط نمی توانید این کار را انجام دهید:

MyModel.objects.filter(name='Alice' or age=30)  # ❌ This won't work!

این جایی است که Q وارد می شود

روش استفاده از Q در جنگو

در اینجا اساسی است import:

from django.db.models import Q

اکنون می توانید استفاده کنید Q برای ایجاد شرایط و ترکیب آنها با استفاده از | (یا) ، & (و) ، و ~ (نه) اپراتورها.

بیایید بگوییم شما مدلی مانند این دارید:

from django.db import models

class Person(models.Model):
    name = models.CharField(max_length=100)
    age = models.IntegerField()
    city = models.CharField(max_length=100)

مثال 1: یا منطق

from django.db.models import Q

people = Person.objects.filter(Q(name='Alice') | Q(age=30))

این هر کسی را که نامش “آلیس” است باز می گرداند یا سن 30 سالگی است. این تمیز و قابل خواندن است ، درست است؟

مثال 2: و منطق (هنوز هم با Q مفید است)

people = Person.objects.filter(Q(name='Alice') & Q(age=30))

این افراد را به کجا باز می گرداند هر دو شرایط درست است از نظر فنی ، این همان نتیجه را با استفاده از:

Person.objects.filter(name='Alice', age=30)

پس چرا در اینجا با Q زحمت می کشیم؟

قدرت واقعی Q با AND وقتی شروع می کنید لانه سازی شرایط پیچیده تربشر به عنوان مثال ، فرض کنید می خواهید افرادی را پیدا کنید که آلیس نامگذاری شده اند و یا در پاریس زندگی می کنند یا زیر 25 سال هستند. در اینجا روش نوشتن آن آمده است:

people = Person.objects.filter(
    Q(name='Alice') & (Q(city='Paris') | Q(age__lt=25))
)

بدون Q، این منطق بیان سخت (و کثیف) خواهد بود. Q به شما امکان می دهد شرایط را به صورت منطقی گروه بندی کنید و نمایش داده های قابل خواندن و قابل خواندن را بنویسید.

مثال 3: منطقی نیست

اگر همه را بخواهید چه می کنید جز افرادی به نام آلیس؟

people = Person.objects.filter(~Q(name='Alice'))

در ~ اپراتور این وضعیت را می چرخاند – این می گوید “نه این”.

چه زمانی باید از Q استفاده کنید؟

شما می توانید به آن دسترسی پیدا کنید Q چه زمانی:

  • شما نیاز دارید یا شرایط

  • شما می خواهید فیلترها را به صورت پویا ترکیب کنید (به عنوان مثال ، ساختن یک پرس و جو مبتنی بر روی ورودی کاربر)

  • شما باید منطق مشروط پیچیده ای بنویسید

  • شما می خواهید موارد خاصی را با استفاده از آن حذف کنید ~Q(...)

اما آیا مواقعی وجود دارد که نباید از Q استفاده کنید؟

بله – اگر در حال نوشتن یک فیلتر مستقیم و فقط با منطق هستید (مانند name="Alice" وت age=30) ، استفاده Q ارزش زیادی اضافه نمی کند. این می تواند کد شما را غیر ضروری ایجاد کند. با دشت بچسبانید .filter() مگر اینکه به انعطاف پذیری بیشتری احتیاج داشته باشید.

مخلوط کردن Q و فیلترهای منظم

می توانید مخلوط کنید Q اشیاء با آرگومان های کلمات کلیدی عادی در یک فیلتر. فقط با پرانتز و نظم مراقب باشید.

Person.objects.filter(Q(name='Alice') | Q(city='Paris'), age__gte=25)

این ترجمه به:

(name = “alice” یا city = ‘paris “) و سن> = 25

اما اینجا کجا است پرانتز تفاوت بزرگی ایجاد کنید

این مثال نادرست را بگیرید:

Person.objects.filter(Q(name='Alice') | Q(city='Paris') & Q(age__gte=25))

با توجه به برتری اپراتور ، این ارزیابی می شود:

name = “آلیس” یا (شهر = ‘پاریس’ و سن> = 25)

چیزی نیست که احتمالاً در نظر گرفته اید!

بنابراین وقتی شک دارید ، از پرانتز استفاده کنید منطق خود را به وضوح تعریف کنید:

# Correct: (name="Alice" OR city = 'Paris') AND age >= 25
Person.objects.filter((Q(name='Alice') | Q(city='Paris')) & Q(age__gte=25))

مثال در دنیای واقعی: فیلتر کردن محصولات

بگو Product مدل با priceبا in_stockوت categoryبشر

شما می خواهید تمام محصولاتی که وجود دارند:

  • ارزان تر از 20 دلار و در انبار
    یا

  • در دسته “کتاب ها”

در اینجا چگونه ممکن است به نظر برسد:

Product.objects.filter(
    (Q(price__lt=20) & Q(in_stock=True)) | Q(category='Books')
)

بدون Qشما باید نمایش داده های جداگانه بنویسید و آنها را ادغام کنید ، یا از منطق پیچیده تری استفاده کنید. این روش سریعتر و کارآمدتر است.

چیزهایی که باید مراقب باشید

  • از پرانتز استفاده کنید: دقیقاً مانند ریاضیات ، آنها کنترل می کنند که چگونه اوضاع ترکیب می شود. به اولویت اپراتور پیش فرض اعتماد نکنید مگر اینکه آن را به خوبی بدانید.

  • استفاده نکنید or/and کلمات کلیدی: اپراتورهای منطقی پایتون با نمایش داده های Django ORM کار نمی کنند. استفاده کردن | وت & در عوض

  • اختلاط Q با .exclude()؟ مراقب باشید چرا؟ چون .exclude() معکوس کردن منطق کل فیلتر. این بدان معنی است که اگر می نویسید:

      Person.objects.exclude(Q(name='Alice') & Q(city='Paris'))
    

    این می گوید: هر کسی را که آلیس نامگذاری شده است ، محروم کنید وت در پاریس زندگی می کند.

    اما اگر نوشتید ، چه می کنید:

      Person.objects.exclude(Q(name='Alice') | Q(city='Paris'))
    

    اکنون هر کسی به نام آلیس را حذف می کند یا چه کسی در پاریس زندگی می کند – یک محرومیت بسیار گسترده تر! بنابراین همیشه آنچه را که استثنا می کنید ، دو بار بررسی کنید.

  • ممکن است لازم باشد با استفاده از بخش های خاصی از منطق خود را معکوس کنید ~Q(...) پیش از انتقال آنها به .exclude() به جای حذف کل بیان.

سوالات متداول

استفاده از Q کندتر از یک معمولی است filter()؟

نه در زیر کاپوت ، جنگو پرس و جو شما را به SQL بهینه تبدیل می کند. آیا شما استفاده می کنید filter(name="Alice") یا filter(Q(name="Alice"))عملکرد تقریباً یکسان است. آنچه بیشتر است این است چقدر پیچیده پرس و جو شما است.

آیا می توانم از Q استفاده کنم annotate() یا aggregate()؟

بله می توانید استفاده کنید Q با annotate() برای استفاده از منطق شرطی برای مواردی مانند شمارش یا فیلتر در حاشیه نویسی.

from django.db.models import Count

# Count users with more than one blog post
User.objects.annotate(
    post_count=Count('posts', filter=Q(posts__published=True))
)

آیا می توانم اشیاء Q را به صورت پویا بسازم؟

کاملا این یکی از بهترین قسمت ها است! شما می توانید لیستی از Q() اشیاء و آنها را با این حال که می خواهید ترکیب کنید:

filters = Q()
if search_name:
    filters |= Q(name__icontains=search_name)
if search_city:
    filters |= Q(city__icontains=search_city)

results = Person.objects.filter(filters)

این امر به ویژه برای فرم های جستجو یا API مفید است که کاربران می توانند ترکیب های مختلفی از فیلترها را منتقل کنند.

پیچیدن

پس Q در جنگو این یک مفهوم ترسناک و انتزاعی نیست – این فقط یک روش قدرتمند برای کنترل روش رفتار پرس و جوهای شما است.

هنگامی که به استفاده از آن عادت کردید Q، کد شما تمیز تر ، خواندن آسان تر و انعطاف پذیر تر هنگام استفاده از فیلترهای پیچیده است.

راستش ، من نمی توانم تصور کنم که دیگر نمایش داده های Django را بدون آن بنویسم.

منابع بیشتر

می خواهید عمیق تر بروید؟

  • Django q Object Docs رسمی

  • راهنمای واقعی پایتون برای اشیاء Q

  • کتاب آشپزی Django Orm – نمونه های عملی جامد