Django Q object
- Encapsulates keywords
- Accept | (OR), & (AND), ~ (NOT)
models.py
xclass Address(models.Model):
city = models.CharField(max_length=60)
postcode = models.CharField(max_length=5)
class Meta:
db_table = 't_address'
def __str__(self) -> str:
return f"<Address> {self.city}"
class Person(models.Model):
firstname = models.CharField(max_length=120)
lastname = models.CharField(max_length=120)
birthdate = models.DateField()
address = models.ForeignKey("Address", on_delete=models.CASCADE)
class Meta:
db_table = 't_person'
def __str__(self) -> str:
return f"<Person> {self.firstname} {self.lastname}"
python manage.py shell
x
# Define a filter with Q that helps to find firstnames startswith Ali
In [13]: filter_ali = Q(firstname__startswith="Ali")
# Using specific filter described with Q
In [14]: Person.objects.filter(filter_ali)
Out[14]: <QuerySet [<Person: <Person> Ali Akkaya>, <Person: <Person> Ali Veli>, <Person: <Person> Alican Veli>]>
# Define a filter to find firstname startswith Ali AND lastname startswith Veli
In [15]: filter_first_and_last = Q(firstname__startswith="Ali") & Q(lastname__startswith="Veli")
In [16]: Person.objects.filter(filter_first_and_last)
Out[16]: <QuerySet [<Person: <Person> Ali Veli>, <Person: <Person> Alican Veli>]>
# Define a filter to find firstname contains Ali OR lastname contains Kaya
In [17]: filter_first_ali_or_last_kaya = Q(firstname__contains="Ali") | Q(lastname__contains="Kaya")
In [18]: Person.objects.filter(filter_first_ali_or_last_kaya)
Out[18]: <QuerySet [<Person: <Person> Adnan Kaya>, <Person: <Person> Murat Kaya>, <Person: <Person> Davud Kayace>, <Person: <Person> Ali Akkaya>, <Person: <Person> Ali Veli>, <Person: <Person> Alican Veli>]>
# See all Person data
In [19]: [print(p.firstname, p.lastname, p.birthdate) for p in Person.objects.all()]
Adnan Kaya 1992-01-01
Murat Kaya 1996-01-01
Davud Kayace 1991-02-03
Ali Akkaya 1991-02-03
Ali Veli 1988-04-01
Alican Veli 1977-01-11
Out[19]: [None, None, None, None, None, None]
# Define a filter to find lastname contains kaya AND birth day is NOT 1
In [20]: filter_last_kaya_and_not_birthday_01 = Q(lastname__contains="kaya") & ~Q(birthdate__day=1)
In [21]: Person.objects.filter(filter_last_kaya_and_not_birthday_01)
Out[21]: <QuerySet [<Person: <Person> Davud Kayace>, <Person: <Person> Ali Akkaya>]>
# get all persons and addresses
In [22]: [print(p.firstname, p.lastname, p.birthdate, p.address) for p in Person.objects.all()]
Adnan Kaya 1992-01-01 <Address> Istanbul
Murat Kaya 1996-01-01 <Address> Kahramanmaras
Davud Kayace 1991-02-03 <Address> Ankara
Ali Akkaya 1991-02-03 <Address> Istanbul
Ali Veli 1988-04-01 <Address> Kahramanmaras
Alican Veli 1977-01-11 <Address> Ankara
Out[22]: [None, None, None, None, None, None]
# get persons whom birth year range between 1992-1996 OR 1970-1980 AND person address city is Istanbul, Ankara
In [24]: Person.objects.filter(
...: Q( Q(birthdate__year__range=(1992,1996)) | Q(birthdate__year__range=(1970,1980) ) )
...: & Q(address__city__in=['Istanbul', 'Ankara'])
...: )
Out[24]: <QuerySet [<Person: <Person> Adnan Kaya>, <Person: <Person> Alican Veli>]>
# get all persons whom birth month is 1
In [27]: Person.objects.filter(birthdate__month=1)
Out[27]: <QuerySet [<Person: <Person> Adnan Kaya>, <Person: <Person> Murat Kaya>, <Person: <Person> Alican Veli>]>
# get all persons whom birth month is 1 AND lastname contains kaya
In [31]: Person.objects.filter(Q(lastname__contains='kaya'), birthdate__month=1)
Out[31]: <QuerySet [<Person: <Person> Adnan Kaya>, <Person: <Person> Murat Kaya>]>
# Imagine you want to search somethings in your table conditinal and use Q object.
# define params
In [86]: params = {'name': 'ali', 'city': 'Istanbul', 'value': 'a'}
In [87]: value = params['value']
In [88]: value
Out[88]: 'a'
In [89]: custom_filter = Q()
Out[89]: <Q: (AND: )>
In [90]: if "name" in params: custom_filter.add( Q (firstname__contains=value), Q.OR)
In [91]: custom_filter
Out[91]: <Q: (OR: (AND: ), (AND: ('firstname__contains', 'a')))>
In [92]: Person.objects.filter(custom_filter)
Out[92]: <QuerySet [<Person: <Person> Adnan Kaya>, <Person: <Person> Murat Kaya>, <Person: <Person> Davud Kayace>, <Person: <Person> Ali Akkaya>, <Person: <Person> Ali Veli>, <Person: <Person> Alican Veli>]>
In [93]: if "city" in params: custom_filter.add(Q(address__city__istartswith=value), Q.AND)
In [94]: custom_filter
Out[94]: <Q: (AND: (OR: (AND: ), (AND: ('firstname__contains', 'a'))), (AND: ('address__city__istartswith', 'a')))>
In [95]: Person.objects.filter(custom_filter)
Out[95]: <QuerySet [<Person: <Person> Davud Kayace>, <Person: <Person> Alican Veli>]>
# to see your SQL query
In [103]: print(Person.objects.filter(custom_filter).query)
SELECT "t_person"."id", "t_person"."firstname", "t_person"."lastname", "t_person"."birthdate", "t_person"."address_id" FROM "t_person" INNER JOIN "t_address" ON ("t_person"."address_id" = "t_address"."id") WHERE ("t_person"."firstname" LIKE %a% ESCAPE '\' AND "t_address"."city" LIKE a% ESCAPE '\')
Yorumlar