Fields Lookup¶
Fields lookup is what you put into the filter
, exclude
, get
methods, or into the Q
object as keyword arguments.
For example, .filter(age__lt=18)
- here the age__lt
means:
age
is a field of the modellt
is the lookup type, which means less than
If the lookup type is not provided, e.g. .filter(name="John")
by default eq
lookup type is used.
Common field lookups¶
The “eq” lookup type¶
from models.user.person import Person
from amsdal_utils.query.utils import Q
Person.objects.filter(Q(gender__eq="male"), name__eq="John")
# that is equal to
Person.objects.filter(Q(gender="male"), name="John")
The “neq” lookup type¶
Opposite of the eq
:
from models.user.person import Person
# get all persons with gender != male
Person.objects.filter(gender__neq="male")
# get customer that are not admin
Customer.objects.filter(is_admin__neq=True)
The “gt” lookup type¶
Greater than:
from models.user.person import Person
# get all persons with age > 18
Person.objects.filter(age__gt=18)
The “gte” lookup type¶
Greater than or equal to.
from models.user.person import Person
# get all persons with age >= 18
Person.objects.filter(age__gte=18)
The “lt” lookup type¶
Less than.
The “lte” lookup type¶
Less than or equal to.
The “in” lookup type¶
In a given iterable:
from models.user.person import Person
# get all persons with ages either 20, 30 or 40
Person.objects.filter(age__in=[20, 30, 40])
The “contains” lookup type¶
Case-sensitive containment test.
from models.user.person import Person
# find persons whose name contains "har"
Person.objects.filter(name__contains="har")
The query above can return “Charles”, “Charlie”, but will not return “Harry" coz it has the capital “H”.
The “icontains” lookup type¶
Case-insensitive containment test.
from models.user.person import Person
# find persons whose name contains "har"
Person.objects.filter(name__icontains="har")
The query above can return “Charles”, “Charlie”, and “Harry" as well.
The “startswith” lookup type¶
Case-sensitive starts-with.
The “istartswith” lookup type¶
Case-insensitive starts-with.
The “endswith” lookup type¶
Case-sensitive ends-with.
The “iendswith” lookup type¶
Case-insensitive ends-with.
The “isnull” lookup type¶
Takes eitherTrue
orFalse
, which correspond to SQL queries ofIS NULL
andIS NOT NULL
, respectively.
Nested fields lookup¶
By default, every nested lookup that is not a common field lookup, is treated as a JSON nested field lookup.
from models.user.person import Person
Person.objects.filter(json_field__nested_field__eq="value").execute()
from models.user.person import Person
await Person.objects.filter(json_field__nested_field__eq="value").aexecute()
There are two special cases of nested lookup: _metadata
and _address
.
You can also filter by fields of a referenced object. To do this, first do the select_related and then filter by the field of the referenced object.
from models.user.person import Person
Person.objects.select_related("company").filter(company__name="value").execute()
from models.user.person import Person
await Person.objects.select_related("company").filter(company__name="value").aexecute()
This also works with multiple levels of select_related:
from models.user.person import Person
Person.objects.select_related(
"company",
"company__location",
).filter(company__location__name="value").execute()
from models.user.person import Person
await Person.objects.select_related(
"company",
"company__location",
).filter(company__location__name="value").aexecute()
Metadata¶
Using _metadata
field name you can filter by any of Metadata fields.
For example, you can filter by is_deleted
field:
from models.user.person import Person
# Count the number of deleted persons
Person.objects.filter(_metadata__is_deleted=True).count()
You can combine it with common lookups to build more complex queries:
from datetime import datetime, timedelta
from models.user.person import Person
# Count the number of persons created during latest 24 hours
start_timestamp = int((datetime.now() - timedelta(hours=24)).timestamp())
result = Person.objects.filter(
_metadata__created_at__gt=datetime.now() - time
).count().execute()
from datetime import datetime, timedelta
from models.user.person import Person
# Count the number of persons created during latest 24 hours
start_timestamp = int((datetime.now() - timedelta(hours=24)).timestamp())
result = await Person.objects.filter(
_metadata__created_at__gt=datetime.now() - time
).count().aexecute()
Address¶
Using _address
field you can filter objects by:
- object_id
- object_version
- class_version
Note
The _address
field will work only if you have historical connection, including lakehouse connection.
For example, to get list of all possible versions of specific person with id 12345
, we can build
the following QuerySet:
from amsdal_utils.models.enums import Versions
from models.user.person import Person
result = Person.objects.filter(
_address__object_id='12345',
_address__object_version=Versions.ALL,
_address__class_version=Versions.ALL,
).execute()
from amsdal_utils.models.enums import Versions
from models.user.person import Person
result = await Person.objects.filter(
_address__object_id='12345',
_address__object_version=Versions.ALL,
_address__class_version=Versions.ALL,
).aexecute()
Filtering by objects¶
You can filter by objects using the __eq
lookup and object to filter by a pointer to the object:
from models.user.person import Person
from models.user.location import Location
new_york = Location.objects.get(name="New York").execute()
result = Person.objects.filter(location=new_york).execute()
from models.user.person import Person
from models.user.location import Location
new_york = await Location.objects.get(name="New York").aexecute()
result = await Person.objects.filter(location=new_york).aexecute()
You can also filter by a reference to the object. The equivalent of the previous example is:
Person.objects.filter(location__eq=new_york.get_metadata().reference).execute()
await Person.objects.filter(location__eq=(await new_york.aget_metadata()).reference).aexecute()