Django Models Part 3 (Model Manager,  QuerySet,  Lookups)

Django Models Part 3 (Model Manager, QuerySet, Lookups)

ยท

5 min read

Model Manager

  • A Manager is the interface through which we perform ORMs in Django models
  • By Default, Django automatically adds a Manager with a name of objects. This is the reason we are able to use objects and query to our Models eg: Model.objects.all()
  • We can always create a new Manager and add to our model. We can customize ORM methods or add some more functionality in our Manager for data query
  • Atleast one Manager should exist in every models

Example to change rename default objects in our model

from django.db import models

class Info(models.Model):
    name = models.CharField(max_length=100)

    data = models.Manager()

# Info.objects.all() will not work but Info.data.all() will work

QuerySet

  • QuerySet can be defined as a collection of Objects (model objects)
  • Until and unless you do something to evaluate a QuerySet (loop, slice with increments,...), it doesn't hit your database. So, we call it by saying QuerSet is Lazy

Let's take an example of basic model which we will be using in this tutorial

  • All, methods, customizations will be done on basis of this model below
from django.db import models

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

QuerySet Methods

  1. filter()

    • Returns a new QuerySet, list of objects that matches the given lookup criteria
    • To return list of users whose age=10, we can do User.objects.filter(age=10);
      qs = User.objects.filter(age=10)
      for u in qs:
      print(u.name, u.age)
      
    • Multiple arguments are joined by AND clause when crafting an SQL query
    • So, User.objects.filter(age=10, name="John") will return list of users whose age is 10 AND whose name is John
    • If you need to join arguments with OR you can use Q objects. e.g. This example will return list of users whose name is John OR Harry
      from django.db.models import Q
      qs = User.objects.filter(Q(name='John') | Q(name='Harry'))
      
  2. exclude()

    • Returns a new Queryset, list of objects that do not match the given lookup criteria
    • Same like filter() multiple arguments/parameters are joined by AND clause
    • User.objects.exclude(age=20) will return list of users whose age is not 20
  3. order_by()

    • Used to perform some ordering for the return QuerySet list
    • If you have set default ordering for your models, you don't even have to use this method to order your QuerySet, because the results returned by QuerySet are ordered automatically by the ordering tuple given by the ordering option in models Meta

      class User(models.Model):
        name = models.CharField(max_length=100)
        age = models.IntegerField()
      
        class Meta:
            ordering = ['-age'] # - negative sign for descending order and
                            # no sign for asc order
      
    • User.objects.filter(age=10) on this model will return the list of users whose age is 10 in descending order of age
    • User.objects.filter(age=10).order_by('age') on this model will return the list of users whose age is 10 in ascending order of age
    • User.objects.order_by('-name') will return list of users in descending order
  1. none()

    • Calling none() will create a QuerySet that will never return any objects
    • This doesn't return any data, so this can be used in place where we need a valid QuerySet but no data
    • calling none() will not hit database
    • e.g User.objects.none()
  2. all()

    • This method is the simplest way to retrieve all objects from the model
    • User.objects.all() will return list of every users/objects

Database ORM methods which do not return a QuerySet

  1. get()
    • User.objects.get(id=1) will return the row/object whose id is 1
  2. create()
    • User.objects.create(name="Peter",age=25) will create a new object/record in database and return that object
  3. first()
    • User.objects.filter(id=10).first() will return the first row/object whose id is 10
  4. last()
    • User.objects.filter(id=10).last() will return the last row/object whose id is 10
  5. delete()
    • User.objects.filter(id=10).delete() will delete objects/rows whose id is 10. This works like a bulk delete
    • You can also perform delete() on model single objects like the objects obtained from get() first() last() methods. This works like a single object delete
  6. count()
    • User.objects.filter(id=10).count() will return total number of users/objects whose id is 10

Field Lookups

  • Field lookups are used to specify meaning to the SQL WHERE clause
  • These lookups are crafted and attached with the fields when performing an ORM queries
  • It looks like
    • field_[LookupType]=value [note the double underscores]

Lookups Types

  1. exact (also a default lookup)

    • An exact Match
    • User.objects.filter(name__exact="Peter") would generate SQL: select .... where name="Peter" and returns the objects/rows whose name is Peter

      If we do not provide a lookup like in the above QuerySet method examples, Django automatically uses exact lookup. This is the reason our ORMs were working even when we didn't pass any lookups

    • Thus, User.objects.filter(name__exact="Peter") and User.objects.filter(name="Peter") QuerySet is practically the same
  2. iexact

    • Case insensitive match
    • User.objects.filter(name__iexact="peter") would return QuerySet of the list of users whose name is peter(case insensitive) i.e: peter, Peter, PeTeR, peteR e.t.c
  3. contains

    • Case sensitive containment
    • User.objects.filter(name__contains="a") would generate SQL: select ..... where name like '%a%' and would return QuerySet of list of users whose name contains/includes a
  4. icontains

    • Similar to contains but case-insensitive
  5. gt

    • greater than
    • User.objects.filter(age_gt=10) would return QuerySet of list of users whose age is greater than 10 i.e 11,12,13,.......
  6. gte

    • greater than or equal to
      • User.objects.filter(age_gte=10) would return QuerySet of list of users whose age is greater than or equals to 10 i.e 10,11,12,13,.......
  7. lt

    • less than
    • User.objects.filter(age_lt=10) would return QuerySet of list of users whose age is less than 10 i.e 9,8,7,......
  8. lte

    • less than or equal to
      • User.objects.filter(age_lte=10) would return QuerySet of list of users whose age is less than or equals to 10 i.e 10,9,8,7,.....

There are other plenty of inbuilts lookups. To name some of them; in startswith istartswith range