tortoise / tortoise/tortoise-orm
Why I can't get pk value after Model create ?
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 5.6k
- Forks
- 516
- Avg merge
- 2d 21h
- Merged PRs (30d)
- 9
Description
Describe the bug
I'm write a BaseModel and rewrite the create method, because I want auto create audit record after I create a new record. but I found I can't get instance's pk after I create it. It's will be null ever for my audit record id field. even stranger is I can print instance's id before I create audit instance. why and what should I do ?
To Reproduce
This is a simple case:
# model.py
class BaseModel(models.Model):
"""
基础模型, 所有的模型都应该继承自该模型
"""
audit_model = None
all_objects = models.Manager()
id = BigIntField(pk=True, description="主键ID")
create_time = StrDatetimeField(auto_now_add=True, description="创建时间")
update_time = StrDatetimeField(auto_now=True, description="更新时间")
delete_time = StrDatetimeField(null=True, description="删除时间")
class Meta:
abstract = True
auditable = False
manager = AuditGenerateManager()
@classmethod
async def create(cls: Type[MODEL], using_db: Optional[BaseDBAsyncClient] = None, **kwargs: Any) -> MODEL:
instance = await super().create(**kwargs)
if cls.audit_model:
await cls.audit_model.create(
**kwargs,
id=instance.pk,
operation="create",
operation_user="system",
operation_ip="localhost",
operation_device="system script",
)
return instance
this is auditModel generate file:
# modelAudit.py
from copy import deepcopy
from tortoise.fields.relational import ForeignKeyFieldInstance, ManyToManyFieldInstance, OneToOneFieldInstance
from . import modelApplication, modelAuth
from .model import BaseAuditModel
from .model import CharField
for model_module in [modelAuth, modelApplication]:
for model in model_module.__dict__.values():
if meta := getattr(model, "Meta", None):
if getattr(meta, "auditable", False) and not getattr(model, 'abstract', False):
class_args, meta_class_args = {}, {}
audit_name, meta_name = f'Audit{model.__name__}', f'Audit{model.__name__}Meta'
meta_table, meta_table_description = f"tortoise_audit_{model._meta.db_table}", f"{model._meta.table_description}'s audit model"
meta_class_args.update({'table': meta_table, 'table_description': meta_table_description})
for name, field in model._meta.fields_map.items():
new_field = deepcopy(field)
new_field.unique, new_field.index, new_field.pk, new_field.null = False, False, False, True
if isinstance(field, (ForeignKeyFieldInstance, ManyToManyFieldInstance, OneToOneFieldInstance)) or name == "password":
new_field = CharField(max_length=255, default="", description=f"{field.description}")
class_args.update({name: new_field})
meta_class = type(meta_name, (), meta_class_args)
class_args.update({'Meta': meta_class})
audit_model = type(audit_name, (BaseAuditModel,), class_args)
model.audit_model = audit_model
globals().update({audit_name: audit_model})
at last, this is my business logic Model :
# modelAuth.py
class AuthUser(BaseModel):
name = CharField(max_length=16, default="", description="用户姓名")
email = CharField(max_length=128, null=True, description="用户邮箱")
mobile = CharField(max_length=16, null=True, description="用户手机号")
password = PasswordField(max_length=255, null=True, description="用户密码")
is_super = BooleanField(default=False, description="是否为超级管理员")
last_login = DatetimeField(null=True, description="最后登录时间")
class Meta:
table = 'tortoise_auth_user'
table_description = "用户表, 用于记录用户信息"
auditable = True
constraints = ["CHECK (email IS NOT NULL OR mobile IS NOT NULL)"]
unique_together = [("mobile", "delete_time"), ("email", "delete_time")]
# ... more other models
Expected behavior
In my mind, after I await super create instance, I should got this pk, and pass it to my audit model.
Additional context
python version: 3.11.4
system os : MacOS
tortoise-orm version: 0.20.0
database: mysql 8.0
I really need help, look forward your response, thanks!
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the BaseModel.create override in model.py, then trace the generated audit models in modelAudit.py and AuthUser in modelAuth.py. Reproduce the reported behavior with Tortoise ORM 0.20.0 and MySQL 8.0, focusing on the values passed to audit_model.create after super().create. Done means the primary-key behavior is explained and the supported create/audit flow is verified or documented.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- mysql, python
- Domain
- backend, database
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 25/100