prisma-client-py
prisma-client-py copied to clipboard
Support defining the Prisma Schema using python models
Problem
One potential source of conflict when transitioning to use Prisma Client Python from other ORMs is that models must be defined in a separate Prisma Schema file.
We should support defining models using a python module.
It should then be possible to query directly from these models.
Suggested solution
Notes:
-
prisma.schema.BaseModel
is a re-export ofpydantic.BaseModel
Example:
from typing import List
from prisma.schema import BaseModel, Field, Default, Relation, render
class User(BaseModel):
id: str = Field(is_id=True, default=Default.cuid)
name: str
posts: List['Post']
class Post(BaseModel):
id: str = Field(is_id=True, default=Default.cuid)
title: str
author: Optional[User] = Relation('author_id', references=['id'])
author_id: str
User.update_forward_refs()
if __name__ == '__main__':
render('schema.prisma', models=[User, Post])
Equivalent Prisma Schema file:
model User {
id String @id @default(cuid())
name String
posts Post[]
}
model Post {
id String @id @default(cuid())
title String
author User @relation(fields: [author_id], references: [id])
author_id String
}
Features still to be implemented:
- Datasources (we could make these configurable on the client level?)
- Generators
Implementation notes:
- Error early if a relation is not typed as
Optional
(or automatically include them once #19 is merged)
Potential difficulties:
- Making these models query-able will be difficult. Solution is still a work in progress.
- Integrating this schema with the standard Prisma commands
Querying
The key for making these models queryable is replacing code during generation time.
Looks like the solution for this is to dynamically resolve base class to inherit from and use literal overloads to type it post-generation. However, mypy does not support this :/
class User(models.BaseUser):
pass
Where:
# pre-generation
class _Models:
def __getattr__(self, attr: str) -> BaseModel:
...
models = _Models()
# post-generation
class _Models:
BaseUser: QueryableUser
models = _Models()
The only disadvantage to this is that it is very magic and could be potentially confusing, maybe a different naming schema could help?
Additional questions
- Is it even worth making these models queryable?