Query Operations - Prisma Client Python (2024)

In lieu of more extensive documentation, this page documents query operations on the prisma client such ascreating, finding, updating and deleting records.

Schema

The examples use the following prisma schema models:

datasource db { provider = "postgresql" url = env("DATABASE_URL")}model User { id String @id @default(cuid()) name String points Float @default(0) meta Json @default("{}") number Decimal @default(0) emails String[] posts Post[] profile Profile?}model Profile { id Int @id @default(autoincrement()) user User @relation(fields: [user_id], references: [id]) user_id String @unique bio String image Bytes? city String? country String? views Int @default(0)}model Post { id String @id @default(cuid()) created_at DateTime @default(now()) updated_at DateTime @updatedAt title String published Boolean views Int @default(0) description String? author User? @relation(fields: [author_id], references: [id]) author_id String? categories Category[]}model Category { id Int @id @default(autoincrement()) posts Post[] name String}

Creating

Single Record

user = await db.user.create( data={ 'name': 'Robert', },)

Many Records

Warning

create_many is not available for SQLite

users = await db.user.create_many( data=[ {'name': 'Tegan'}, {'name': 'Alfie'}, {'name': 'Robert'}, ])
users = await db.user.create_many( data=[ {'id': 'abc', 'name': 'Tegan'}, {'id': 'def', 'name': 'Alfie'}, {'id': 'ghi', 'name': 'Robert'}, ], skip_duplicates=True,)

Relational Records

user = await db.user.create( data={ 'name': 'Robert', 'profile': { 'create': { 'bio': 'My very cool bio!', } } })
user = await db.user.create( data={ 'name': 'Robert', 'posts': { 'create': [ { 'title': 'My first post!', 'published': True, }, { 'title': 'My draft post!', 'published': False, }, ] } })

Finding

Unique Records

There are two different methods you can use here to find a unique record. Which one you use depends on the context surrounding the query:

  • Use find_unique if it is expected for the record to not exist in the database
  • Use find_unique_or_raise if it is unexpected for the record to not exist in the database
user = await db.user.find_unique( where={ 'id': '1', })
user = await db.user.find_unique_or_raise( where={ 'id': '2', }, include={ 'posts': True, },)

A Single Record

There are two different methods you can use here to find a single record. Which one you use depends on the context surrounding the query:

  • Use find_first if it is expected for the record to not exist in the database
  • Use find_first_or_raise if it is unexpected for the record to not exist in the database
post = await db.post.find_first( where={ 'title': {'contains': 'Post'}, },)post = await db.post.find_first_or_raise( where={ 'title': {'contains': 'Post'}, },)
post = await db.post.find_first( skip=2, where={ 'title': { 'contains': 'Post' }, }, cursor={ 'id': 'abcd', }, include={ 'author': True, }, order={ 'id': 'asc', })

Multiple Records

posts = await db.post.find_many( where={ 'published': True, },)
posts = await db.post.find_many( take=5, skip=1, where={ 'published': True, }, cursor={ 'id': 'desc', }, include={ 'categories': True, }, order={ 'id': 'desc', })

Distinct Records

The following query will find all Profile records that have a distinct city field.

profiles = await db.profiles.find_many( distinct=['city'],)# [# { city: 'Paris' },# { city: 'Lyon' },# ]

You can also filter by distinct combinations, for example the following query will return all records that have a distinct city and country combination.

profiles = await db.profiles.find_many( distinct=['city', 'country'],)# [# { city: 'Paris', country: 'France' },# { city: 'Paris', country: 'Denmark' },# { city: 'Lyon', country: 'France' },# ]

You can currently only use distinct with find_many() and find_first() queries.

Filtering by Relational Fields

Within the filter you can query for everything you would normally query for, like it was a find_first() call on the relational field, for example:

post = await db.post.find_first( where={ 'author': { 'is': { 'name': 'Robert', }, }, },)user = await db.user.find_first( where={ 'name': 'Robert', },)

One to One

post = await db.post.find_first( where={ 'author': { 'is': { 'name': 'Robert', }, 'is_not': { 'name': 'Tegan', }, }, },)

One to Many

Excluding
post = await db.post.find_first( where={ 'categories': { 'none': { 'name': 'Exclude Category', }, }, },)
At Least One
post = await db.post.find_first( where={ 'categories': { 'some': { 'name': { 'contains': 'Special', }, }, }, },)
Every
post = await db.post.find_first( where={ 'categories': { 'every': { 'name': { 'contains': 'Category', }, }, }, },)

Filtering by Field Values

Note

The examples for filtering fields are simply to showcase possible arguments, all the argumentspassed together will result in either an invalid query or no records being found.

String Fields

Warning

Case insensitive filtering is only available on PostgreSQL and MongoDB

post = await db.post.find_first( where={ 'description': 'Must be exact match', # or 'description': { 'equals': 'example_string', 'not_in': ['ignore_string_1', 'ignore_string_2'], 'lt': 'z', 'lte': 'y', 'gt': 'a', 'gte': 'b', 'contains': 'string must be present', 'startswith': 'must start with string', 'endswith': 'must end with string', 'in': ['find_string_1', 'find_string_2'], 'mode': 'insensitive', 'not': { # recursive type 'contains': 'string must not be present', 'mode': 'default', ... }, }, },)

Integer Fields

post = await db.post.find_first( where={ 'views': 10, # or 'views': { 'equals': 1, 'in': [1, 2, 3], 'not_in': [4, 5, 6], 'lt': 10, 'lte': 9, 'gt': 0, 'gte': 1, 'not': { # recursive type 'gt': 10, ... }, }, },)

Float Fields

user = await db.user.find_first( where={ 'points': 10.0, # or 'points': { 'equals': 10.0, 'in': [1.2, 1.3, 1.4], 'not_in': [4.7, 53.4, 6.8], 'lt': 100.5, 'lte': 9.9, 'gt': 0.0, 'gte': 1.2, 'not': { # recursive type 'gt': 10.0, ... }, }, },)

DateTime Fields

from datetime import datetimepost = await db.post.find_first( where={ 'updated_at': datetime.now(), # or 'updated_at': { 'equals': datetime.now(), 'not_in': [datetime.now(), datetime.utcnow()], 'lt': datetime.now(), 'lte': datetime.now(), 'gt': datetime.now(), 'gte': datetime.now(), 'in': [datetime.now(), datetime.utcnow()], 'not': { # recursive type 'equals': datetime.now(), ... }, }, },)

Boolean Fields

post = await db.post.find_first( where={ 'published': True, # or 'published': { 'equals': True, 'not': False, }, },)

Json Fields

Note

Json fields must match exactly.

Warning

Json fields are not supported on SQLite

from prisma import Jsonuser = await db.user.find_first( where={ 'meta': Json({'country': 'Scotland'}) # or 'meta': { 'equals': Json.keys(country='Scotland'), 'not': Json(['foo']), } })

Bytes Fields

Note

Bytes fields are encoded to and from Base64

from prisma import Base64profile = await db.profile.find_first( where={ 'image': Base64.encode(b'my binary data'), # or 'image': { 'equals': Base64.encode(b'my binary data'), 'in': [Base64.encode(b'my binary data')], 'not_in': [Base64.encode(b'my other binary data')], 'not': Base64(b'WW91IGZvdW5kIGFuIGVhc3RlciBlZ2chIExldCBAUm9iZXJ0Q3JhaWdpZSBrbm93IDop'), }, },)

Decimal Fields

from decimal import Decimaluser = await db.user.find_first( where={ 'number': Decimal(1), # or 'number': { 'equals': Decimal('1.23823923283'), 'in': [Decimal('1.3'), Decimal('5.6')], 'not_in': [Decimal(10), Decimal(20)], 'gte': Decimal(5), 'gt': Decimal(11), 'lt': Decimal(4), 'lte': Decimal(3), 'not': Decimal('123456.28'), # or 'not': { # recursive type ... } }, },)

Lists fields

Warning

Scalar list fields are only supported on PostgreSQL, co*ckroachDB and MongoDB

Every scalar type can also be defined as a list, for example:

user = await db.user.find_first( where={ 'emails': { # only one of the following fields is allowed at the same time 'has': 'robert@craigie.dev', 'has_every': ['email1', 'email2'], 'has_some': ['email3', 'email4'], 'is_empty': True, }, },)

Combining arguments

All of the above mentioned filters can be combined with other filters using AND, NOT and OR.

AND

The following query will return the first post where the title contains the words prisma and test.

post = await db.post.find_first( where={ 'AND': [ { 'title': { 'contains': 'prisma', }, }, { 'title': { 'contains': 'test', }, }, ], },)

OR

The following query will return the first post where the title contains the word prisma or is published.

post = await db.post.find_first( where={ 'OR': [ { 'title': { 'contains': 'prisma', }, }, { 'published': True, }, ], },)

NOT

The following query will return the first post where the title is not My test post

post = await db.post.find_first( where={ 'NOT' [ { 'title': 'My test post', }, ], },)

Deleting

Unique Record

post = await db.post.delete( where={ 'id': 'cksc9m7un0028f08zwycxtjr1', },)
post = await db.post.delete( where={ 'id': 'cksc9m1vu0021f08zq0066pnz', }, include={ 'categories': True, })

Multiple Records

total = await db.post.delete_many( where={ 'published': False, })

Updating

Unique Record

post = await db.post.update( where={ 'id': 'cksc9lp7w0014f08zdkz0mdnn', }, data={ 'views': { 'increment': 1, } }, include={ 'categories': True, })

Multiple Records

total = await db.post.update_many( where={ 'published': False }, data={ 'views': 0, },)

Creating On Not Found

post = await db.post.upsert( where={ 'id': 'cksc9ld4z0007f08z7obo806s', }, data={ 'create': { 'title': 'This post was created!', 'published': False, }, 'update': { 'title': 'This post was updated', 'published': True, }, }, include={ 'categories': True, })

Updating Atomic Fields

If a field is an int or float type then it can be atomically updated, i.e. mathematical operations can be applied without knowledge of the previous value.

Integer Fields

post = await db.post.update( where={ 'id': 'abc', }, data={ 'views': 1, # or 'views': { 'set': 5, 'increment': 1, 'decrement': 2, 'multiply': 5, 'divide': 10, }, },)

Float Fields

user = await db.user.update( where={ 'id': 'abc', }, data={ 'points': 1.0, # or 'points': { 'set': 1.0, 'increment': 1.5, 'decrement': 0.5, 'multiply': 2.5, 'divide': 3.0, }, },)

Updating List Fields

Warning

Scalar list fields are only supported on PostgreSQL, co*ckroachDB and MongoDB

Warning

The push operation is not supported on co*ckroachDB

user = await db.user.update( where={ 'id': 'cksc9lp7w0014f08zdkz0mdnn', }, data={ 'email': { 'set': ['robert@craigie.dev', 'robert@example.com'], # or 'push': ['robert@example.com'], }, })

Aggregrating

Counting Records

total = await db.post.count( where={ 'published': True, },)
total = await db.post.count( take=10, skip=1, where={ 'published': True, }, cursor={ 'id': 'cksca3xm80035f08zjonuubik', },)

Grouping Records

Warning

You can only order by one field at a time however this is not possibleto represent with python types

results = await db.profile.group_by(['country'])# [# {'country': 'Denmark'},# {'country': 'Scotland'},# ]results = await db.profile.group_by(['country'], count=True)# [# {'country': 'Denmark', '_count': {'_all': 20}},# {'country': 'Scotland', '_count': {'_all': 1}},# ]results = await db.profile.group_by( by=['country', 'city'], count={ '_all': True, 'city': True, }, sum={ 'views': True, }, order={ 'country': 'desc', }, having={ 'views': { '_avg': { 'gt': 200, }, }, },)# [# {# 'country': 'Scotland',# 'city': 'Edinburgh',# '_sum': {'views': 250},# '_count': {'_all': 1, 'city': 1}# },# {# 'country': 'Denmark',# 'city': None,# '_sum': {'views': 6000},# '_count': {'_all': 12, 'city': 0}# },# {# 'country': 'Denmark',# 'city': 'Copenhagen',# '_sum': {'views': 8000},# '_count': {'_all': 8, 'city': 8}# },# ]

Batching Write Queries

async with db.batch_() as batcher: batcher.user.create({'name': 'Robert'}) batcher.user.create({'name': 'Tegan'})

Raw Queries

Note

SQL queries are sent directly to the database so you must use the syntax for your specific database provider

Warning

Raw query results are raw dictionaries unless the model argument is specified

Write Queries

total = await db.execute_raw( ''' SELECT * FROM User WHERE User.id = ? ''', 'cksca3xm80035f08zjonuubik')

Selecting Multiple Records

posts = await db.query_raw( ''' SELECT * FROM Post WHERE Post.published IS TRUE ''')

Type Safety

from prisma.models import Postposts = await db.query_raw( ''' SELECT * FROM Post WHERE Post.published IS TRUE ''', model=Post,)

Selecting a Single Record

post = await db.query_first( ''' SELECT * FROM Post WHERE Post.published IS TRUE LIMIT 1 ''')

Type Safety

from prisma.models import Postpost = await db.query_first( ''' SELECT * FROM Post WHERE Post.views > 50 LIMIT 1 ''', model=Post)
Query Operations - Prisma Client Python (2024)

References

Top Articles
Latest Posts
Article information

Author: Nathanael Baumbach

Last Updated:

Views: 6411

Rating: 4.4 / 5 (55 voted)

Reviews: 94% of readers found this page helpful

Author information

Name: Nathanael Baumbach

Birthday: 1998-12-02

Address: Apt. 829 751 Glover View, West Orlando, IN 22436

Phone: +901025288581

Job: Internal IT Coordinator

Hobby: Gunsmithing, Motor sports, Flying, Skiing, Hooping, Lego building, Ice skating

Introduction: My name is Nathanael Baumbach, I am a fantastic, nice, victorious, brave, healthy, cute, glorious person who loves writing and wants to share my knowledge and understanding with you.