прокрутите вниз для tl; dr, я предоставляю контекст, который я считаю важным, но не имеет прямого отношения к заданному вопросу
Немного контекста
Я занимаюсь созданием API для веб-приложения, и некоторые значения вычисляются на основе значений других в pydanti c BaseModel
. Они используются для проверки пользователем, сериализации данных и определения документов базы данных (№ SQL).
В частности, у меня есть почти все ресурсы, унаследованные от класса OwnedResource
, который определяет среди других нерелевантных свойств, таких как Даты создания / последнего обновления:
object_key
- ключ объекта, использующий наноид длины 6 с произвольным алфавитом owner_key
- Этот ключ ссылается на пользователя, которому принадлежит этот объект - наноид длиной 10. _key
- здесь я столкнулся с некоторыми проблемами, и я объясню почему.
Итак, arangodb - база данных, которую я использую - накладывает _key
в качестве имени свойства, по которому идентифицируются ресурсы.
Поскольку в моем веб-приложении все к ресурсам имеют доступ только те пользователи, которые их создали, они могут быть идентифицированы в URL-адресах только с помощью ключа объекта (например, /subject/{object_key}
). Однако, поскольку _key
должно быть уникальным, я намерен создать значение этого поля, используя f"{owner_key}/{object_key}"
, чтобы хранить объекты каждого пользователя в базе данных и потенциально разрешить совместное использование ресурсов между пользователями в будущем.
Цель состоит в том, чтобы иметь самый короткий для каждого пользователя уникальный идентификатор, поскольку часть owner_key
полного _key
, используемая для фактического доступа и действий с документом, хранящимся в базе данных, всегда является то же самое: текущий авторизованный пользователь _key
.
Моя попытка
Тогда я задумал определить поле _key
как функцию, украшенную @property
в классе. Однако Pydanti c, похоже, не регистрирует их как поля модели.
Более того, атрибут должен иметь имя key
и использовать псевдоним (с Field(... alias="_key"
), например pydanti c обрабатывает поля с префиксом подчеркивания как внутренние и не раскрывает их .
Вот определение OwnedResource
:
class OwnedResource(BaseModel):
"""
Base model for resources owned by users
"""
object_key: ObjectBareKey = nanoid.generate(ID_CHARSET, OBJECT_KEY_LEN)
owner_key: UserKey
updated_at: Optional[datetime] = None
created_at: datetime = datetime.now()
@property
def key(self) -> ObjectKey:
return objectkey(self.owner_key)
class Config:
fields = {"key": "_key"} # [1]
[1] Since Field (.. ., alias = "...") не может использоваться, я использую это свойство подкласса Config (см. документацию pydanti c )
Однако это не работает , как показано в следующем примере:
@router.post("/subjects/")
def create_a_subject(subject: InSubject):
print(subject.dict(by_alias=True))
, где InSubject
определяет свойства, соответствующие Subject
, а Subject
является пустым классом, наследуемым от InSubject
и OwnedResource
:
class InSubject(BaseModel):
name: str
color: Color
weight: Union[PositiveFloat, Literal[0]] = 1.0
goal: Primantissa # This is just a float constrained in a [0, 1] range
room: str
class Subject(InSubject, OwnedResource):
pass
Когда я выполняю POST /subjects/
, в консоли печатается следующее:
{'name': 'string', 'color': Color('cyan', rgb=(0, 255, 255)), 'weight': 0, 'goal': 0.0, 'room': 'string'}
Как видите, _key
или key
нигде не видно.
Пожалуйста, запрашивайте подробности и разъяснения, я постарался сделать это как можно проще для понимания, но я не уверен, ясно ли это e nough.
tl; dr
Бесконтекстный и более общий пример c без глубокого контекста:
Со следующим классом:
from pydantic import BaseModel
class SomeClass(BaseModel):
spam: str
@property
def eggs(self) -> str:
return self.spam + " bacon"
class Config:
fields = {"eggs": "_eggs"}
Я бы хотел, чтобы было правдой следующее:
a = SomeClass(spam="I like")
d = a.dict(by_alias=True)
d.get("_eggs") == "I like bacon"