from tortoise import fields, models from tortoise.indexes import Index from tortoise.contrib.pydantic import pydantic_model_creator, pydantic_queryset_creator from tortoise.signals import post_save from typing import Type from helper.tools import genRandomStr class Hole(models.Model): id = fields.UUIDField(pk=True) number = fields.IntField(default=0, description='空位编号') traynum = fields.CharField(max_length=255, null=True, description='标品托盘编号') typetask = fields.IntField(default=1, description='1: 标准品A, 3: 标准品B, 5: 标准品C, 7: 标准品D, 9:非标准品') code = fields.CharField(null=True, max_length=255, description='二维码编号') name = fields.CharField(null=True, max_length=255, description='试剂名称') height = fields.IntField(default=0, description='瓶高') bottle = fields.IntField(default=0, description='瓶身直径') cap = fields.IntField(default=0, description='瓶盖直径') orderid = fields.CharField(max_length=255, null=True, description='托盘内孔位号对应的订单号列表') #停靠点 -> 层坐标 (最底下为第一层) -> 试剂在托盘内的编号 #where to return coordinates = fields.CharField(null=True, max_length=255, description='试剂坐标') coordinatessrc = fields.CharField(null=True, max_length=255, description='原试剂坐标') created_at = fields.DatetimeField(auto_now_add=True) updated_at = fields.DatetimeField(auto_now=True) is_valid = fields.BooleanField(default=True, description='是否取消') is_active = fields.BooleanField(default=True, description='是否删除') class PydanticMeta: # Let's exclude the created timestamp exclude = ("created_at",) class Meta: table = 'Holes' table_description = '暂存货架或接驳机空位编号表' ordering = ["number"] indexes = [ Index(fields={"traynum"}, name="traynumidx"), Index(fields={"number"}, name="numberidx"), Index(fields={"orderid"}, name="orderididx"), Index(fields={"is_valid"}, name="is_valididx"), Index(fields={"is_active"}, name="is_activeidx"), ] def __str__(self): return f'Hole(id={self.id} number={self.number}, orderid={self.orderid}, created_at={self.created_at})' def as_json(self): return dict(id="{}".format(self.id), number=self.number, orderid=self.orderid, created_at="{}".format(self.created_at)) Hole_Pydantic = pydantic_model_creator(Hole, name="Hole") Hole_Pydantic_List = pydantic_queryset_creator(Hole) class Vacancy(models.Model): id = fields.UUIDField(pk=True) number = fields.CharField(max_length=255, null=True, description='空位编号') traynum = fields.CharField(max_length=255, null=True, description='非标品托盘编号') orderids = fields.JSONField(null=True, description='托盘编号对应的订单号列表') coordinatessrc = fields.CharField(null=True, max_length=255, description='原试剂坐标') typetask = fields.IntField(default=1, description='1: 标准品A, 3: 标准品B, 5: 标准品C, 7: 标准品D, 9:非标准品') holes = fields.ManyToManyField('models.Hole', related_name='warehouseholes') memo = fields.JSONField(null=True, description='备忘录') is_shelf = fields.BooleanField(default=False, description='是货架库存') is_connect = fields.BooleanField(default=False, description='是接驳区库存') is_empty = fields.BooleanField(default=False, description='是空位') created_at = fields.DatetimeField(auto_now_add=True) updated_at = fields.DatetimeField(auto_now=True) is_valid = fields.BooleanField(default=True, description='是否取消') is_active = fields.BooleanField(default=True, description='是否删除') class PydanticMeta: # Let's exclude the created timestamp exclude = ("created_at",) class Meta: table = 'Vacancys' table_description = '暂存货架或接驳机空位编号表' ordering = ["number", "created_at"] indexes = [ Index(fields={"number"}, name="numberidx"), Index(fields={"traynum"}, name="traynumidx"), Index(fields={"is_shelf"}, name="is_shelfidx"), Index(fields={"is_connect"}, name="is_connectidx"), Index(fields={"is_empty"}, name="is_emptyidx"), Index(fields={"is_valid"}, name="is_valididx"), Index(fields={"is_active"}, name="is_activeidx"), ] def __str__(self): return f'Vacancy(id={self.id} number={self.number}, traynum={self.traynum}, created_at={self.created_at})' def as_json(self): return dict(id="{}".format(self.id), number=self.number, traynum=self.traynum, created_at="{}".format(self.created_at)) Vacancy_Pydantic = pydantic_model_creator(Vacancy, name="Vacancy") Vacancy_Pydantic_List = pydantic_queryset_creator(Vacancy) class Connection(models.Model): id = fields.UUIDField(pk=True) num = fields.CharField(null=True, max_length=255, description='短编号') name = fields.CharField(null=True, max_length=255, description='接驳台编号') vacancies = fields.ManyToManyField('models.Vacancy', related_name='connectionvacancies') memo = fields.JSONField(null=True, description='备忘录') created_at = fields.DatetimeField(auto_now_add=True) updated_at = fields.DatetimeField(auto_now=True) is_valid = fields.BooleanField(default=True, description='是否取消') is_active = fields.BooleanField(default=True, description='是否删除') class PydanticMeta: # Let's exclude the created timestamp exclude = ("created_at",) allow_cycles = True max_recursion = 4 class Meta: table = 'Connections' table_description = '暂存货架库存表' ordering = ["name", "created_at"] indexes = [ Index(fields={"name"}, name="nameidx"), Index(fields={"num"}, name="numidx"), Index(fields={"is_valid"}, name="is_valididx"), Index(fields={"is_active"}, name="is_activeidx"), ] def __str__(self): return f'Connection(id={self.id}, num={self.num}, name={self.name}, created_at={self.created_at})' def as_json(self): return dict(id="{}".format(self.id), num=self.num, name=self.name, created_at="{}".format(self.created_at)) Connection_Pydantic = pydantic_model_creator(Connection, name="Connection") @post_save(Connection) async def connection_post_save( sender: "Type[Connection]", instance: Connection, created, using_db, update_fields, ) -> None: if not instance.num or "null" == instance.num: # print("instance.num: ", instance.num) # check duplicated num async def checkNum(): num = genRandomStr(4) # print("new num: ", num) if await Connection.filter(num = num).exists(): # print("num exist, ", num) checkNum() else: # print("num not exist, ", num) instance.num = num await instance.save() await checkNum()