When querying data, for ORM entities, add fields that do not include
jiangzik opened this issue · 6 comments
jiangzik commented
For example, I want to query users, but the user password does not want to be included. I want all other fields. It is a bit cumbersome to just use only. Is there a way to exclude only the password field?
waketzheng commented
https://tortoise.github.io/examples/pydantic.html
from tortoise import Model
from tortoise.contrib.pydantic import pydantic_model_creator
class User(Model):
...
class PydanticMeta:
exclude = ["password"]
User_Pydantic = pydantic_model_creator(User)
jiangzik commented
In order to make the code more concise, I did not use pydantic, but directly returned the orm entity
waketzheng commented
Demo:
from tortoise import Model, fields, run_async
from tortoise.contrib.test import init_memory_sqlite
class User(Model):
id = fields.IntField(pk=True)
name = fields.CharField(max_length=10)
password = fields.CharField(max_length=10)
def model_dump(self) -> dict:
data = dict(self)
data.pop("password")
return data
@init_memory_sqlite
async def main():
user = await User.create(name="haha", password="123")
print(user.model_dump())
# {'id': 1, 'name': 'haha'}
await User(name="hello", password="").save()
users = await User.filter()
print([i.model_dump() for i in users])
# [{'name': 'haha', 'id': 1}, {'name': 'hello', 'id': 2}]
if __name__ == "__main__":
run_async(main())
jiangzik commented
I understand that writing a method in the base class and letting other ORM entities inherit it was the earliest way to do this. In fact, from the query database, all fields are still queried. I want to fundamentally solve this problem.
waketzheng commented
How about this:
from typing import List
from tortoise import fields, Model, run_async
from tortoise.contrib.test import init_memory_sqlite
class User(Model):
id = fields.IntField(primary_key=True)
name = fields.CharField(max_length=20)
password = fields.TextField()
@classmethod
def expose_fields(cls) -> List[str]:
attr = "_expose_fields"
if fs := getattr(cls, attr, None):
return fs
fields = [i for i in cls._meta.fields if i != "password"]
setattr(cls, attr, fields)
return fields
@init_memory_sqlite
async def run() -> None:
await User(name="els", password="").save()
users = await User.filter().values(*User.expose_fields())
print(users)
user = await User.get(id=1).only(*User.expose_fields())
print({i: getattr(user, i) for i in User.expose_fields()})
if __name__ == "__main__":
run_async(run())
jiangzik commented
Things are getting more troublesome, I'll try something else, anyway, thank you