Files
ormar/docs/queries.md

4.7 KiB

Queries

QuerySet

Each Model is auto registered with a QuerySet that represents the underlaying query and it's options.

Given the Models like this

--8<-- "../docs_src/relations/docs001.py"

we can demonstrate available methods to fetch and save the data into the database.

create(**kwargs)

Creates the model instance, saves it in a database and returns the updates model (with pk populated). The allowed kwargs are Model fields names and proper value types.

malibu = await Album.objects.create(name="Malibu")
await Track.objects.create(album=malibu, title="The Bird", position=1)

The alternative is a split creation and persistence of the Model.

malibu = Album(name="Malibu")
await malibu.save()

load()

By default when you query a table without prefetching related models, the ormar will still construct your related models, but populate them only with the pk value.

track = await Track.objects.get(name='The Bird')
track.album.pk # will return malibu album pk (1)
track.album.name # will return None

# you need to actually load the data first
await track.album.load()
track.album.name # will return 'Malibu'

get(**kwargs)

Get's the first row from the db meeting the criteria set by kwargs.

If no criteria set it will return the first row in db.

Passing a criteria is actually calling filter(**kwargs) method described below.

track = await Track.objects.get(name='The Bird')
track2 = track = await Track.objects.get()
track == track2 # True since it's the only row in db

all()

Returns all rows from a database for given model

tracks = await Track.objects.select_related("album").all()
# will return a list of all Tracks

filter(**kwargs)

Allows you to filter by any Model attribute/field as well as to fetch instances, with a filter across an FK relationship.

track = Track.objects.filter(name="The Bird").get()
# will return a track with name equal to 'The Bird'
 
tracks = Track.objects.filter(album__name="Fantasies").all()
# will return all tracks where the related album name = 'Fantasies'

You can use special filter suffix to change the filter operands:

  • exact - like album__name__exact='Malibu' (exact match)
  • iexact - like album__name__iexact='malibu' (exact match case insensitive)
  • contains - like album__name__conatins='Mal' (sql like)
  • icontains - like album__name__icontains='mal' (sql like case insensitive)
  • in - like album__name__in=['Malibu', 'Barclay'] (sql in)
  • gt - like position__gt=3 (sql >)
  • gte - like position__gte=3 (sql >=)
  • lt - like position__lt=3 (sql <)
  • lte - like position__lte=3 (sql <=)

!!!note filter(), select_related(), limit() and offset() returns a QueySet instance so you can chain them together.

Something like `Track.object.select_related("album").filter(album__name="Malibu").offset(1).limit(1).all()`

select_related(*args)

Allows to prefetch related models.

To fetch related model use ForeignKey names.

To chain related Models relation use double underscore.

album = await Album.objects.select_related("tracks").all()
# will return album will all related tracks

You can provide a string or a list of strings

classes = await SchoolClass.objects.select_related(
["teachers__category", "students"]).all()
# will return classes with teachers and teachers categories
# as well as classes students

!!!warning If you set ForeignKey field as not nullable (so required) during all queries the not nullable Models will be auto prefetched, even if you do not include them in select_related.

!!!note filter(), select_related(), limit() and offset() returns a QueySet instance so you can chain them together.

Something like `Track.object.select_related("album").filter(album__name="Malibu").offset(1).limit(1).all()`

limit(int)

You can limit the results to desired number of rows.

tracks = await Track.objects.limit(1).all()
# will return just one Track

!!!note filter(), select_related(), limit() and offset() returns a QueySet instance so you can chain them together.

Something like `Track.object.select_related("album").filter(album__name="Malibu").offset(1).limit(1).all()`

offset(int)

You can also offset the results by desired number of rows.

tracks = await Track.objects.offset(1).limit(1).all()
# will return just one Track, but this time the second one

!!!note filter(), select_related(), limit() and offset() returns a QueySet instance so you can chain them together.

Something like `Track.object.select_related("album").filter(album__name="Malibu").offset(1).limit(1).all()`