mirror of
https://gitlab.com/MoonTestUse1/AdministrationItDepartmens.git
synced 2025-08-14 00:25:46 +02:00
Проверка 09.02.2025
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
# ext/hybrid.py
|
||||
# Copyright (C) 2005-2024 the SQLAlchemy authors and contributors
|
||||
# Copyright (C) 2005-2025 the SQLAlchemy authors and contributors
|
||||
# <see AUTHORS file>
|
||||
#
|
||||
# This module is part of SQLAlchemy and is released under
|
||||
@@ -34,8 +34,9 @@ may receive the class directly, depending on context::
|
||||
class Base(DeclarativeBase):
|
||||
pass
|
||||
|
||||
|
||||
class Interval(Base):
|
||||
__tablename__ = 'interval'
|
||||
__tablename__ = "interval"
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True)
|
||||
start: Mapped[int]
|
||||
@@ -57,7 +58,6 @@ may receive the class directly, depending on context::
|
||||
def intersects(self, other: Interval) -> bool:
|
||||
return self.contains(other.start) | self.contains(other.end)
|
||||
|
||||
|
||||
Above, the ``length`` property returns the difference between the
|
||||
``end`` and ``start`` attributes. With an instance of ``Interval``,
|
||||
this subtraction occurs in Python, using normal Python descriptor
|
||||
@@ -150,6 +150,7 @@ the absolute value function::
|
||||
from sqlalchemy import func
|
||||
from sqlalchemy import type_coerce
|
||||
|
||||
|
||||
class Interval(Base):
|
||||
# ...
|
||||
|
||||
@@ -214,6 +215,7 @@ example below that illustrates the use of :meth:`.hybrid_property.setter` and
|
||||
|
||||
# correct use, however is not accepted by pep-484 tooling
|
||||
|
||||
|
||||
class Interval(Base):
|
||||
# ...
|
||||
|
||||
@@ -256,6 +258,7 @@ a single decorator under one name::
|
||||
|
||||
# correct use which is also accepted by pep-484 tooling
|
||||
|
||||
|
||||
class Interval(Base):
|
||||
# ...
|
||||
|
||||
@@ -330,6 +333,7 @@ expression is used as the column that's the target of the SET. If our
|
||||
``Interval.start``, this could be substituted directly::
|
||||
|
||||
from sqlalchemy import update
|
||||
|
||||
stmt = update(Interval).values({Interval.start_point: 10})
|
||||
|
||||
However, when using a composite hybrid like ``Interval.length``, this
|
||||
@@ -340,6 +344,7 @@ A handler that works similarly to our setter would be::
|
||||
|
||||
from typing import List, Tuple, Any
|
||||
|
||||
|
||||
class Interval(Base):
|
||||
# ...
|
||||
|
||||
@@ -352,10 +357,10 @@ A handler that works similarly to our setter would be::
|
||||
self.end = self.start + value
|
||||
|
||||
@length.inplace.update_expression
|
||||
def _length_update_expression(cls, value: Any) -> List[Tuple[Any, Any]]:
|
||||
return [
|
||||
(cls.end, cls.start + value)
|
||||
]
|
||||
def _length_update_expression(
|
||||
cls, value: Any
|
||||
) -> List[Tuple[Any, Any]]:
|
||||
return [(cls.end, cls.start + value)]
|
||||
|
||||
Above, if we use ``Interval.length`` in an UPDATE expression, we get
|
||||
a hybrid SET expression:
|
||||
@@ -412,15 +417,16 @@ mapping which relates a ``User`` to a ``SavingsAccount``::
|
||||
|
||||
|
||||
class SavingsAccount(Base):
|
||||
__tablename__ = 'account'
|
||||
__tablename__ = "account"
|
||||
id: Mapped[int] = mapped_column(primary_key=True)
|
||||
user_id: Mapped[int] = mapped_column(ForeignKey('user.id'))
|
||||
user_id: Mapped[int] = mapped_column(ForeignKey("user.id"))
|
||||
balance: Mapped[Decimal] = mapped_column(Numeric(15, 5))
|
||||
|
||||
owner: Mapped[User] = relationship(back_populates="accounts")
|
||||
|
||||
|
||||
class User(Base):
|
||||
__tablename__ = 'user'
|
||||
__tablename__ = "user"
|
||||
id: Mapped[int] = mapped_column(primary_key=True)
|
||||
name: Mapped[str] = mapped_column(String(100))
|
||||
|
||||
@@ -448,7 +454,10 @@ mapping which relates a ``User`` to a ``SavingsAccount``::
|
||||
@balance.inplace.expression
|
||||
@classmethod
|
||||
def _balance_expression(cls) -> SQLColumnExpression[Optional[Decimal]]:
|
||||
return cast("SQLColumnExpression[Optional[Decimal]]", SavingsAccount.balance)
|
||||
return cast(
|
||||
"SQLColumnExpression[Optional[Decimal]]",
|
||||
SavingsAccount.balance,
|
||||
)
|
||||
|
||||
The above hybrid property ``balance`` works with the first
|
||||
``SavingsAccount`` entry in the list of accounts for this user. The
|
||||
@@ -471,8 +480,11 @@ be used in an appropriate context such that an appropriate join to
|
||||
.. sourcecode:: pycon+sql
|
||||
|
||||
>>> from sqlalchemy import select
|
||||
>>> print(select(User, User.balance).
|
||||
... join(User.accounts).filter(User.balance > 5000))
|
||||
>>> print(
|
||||
... select(User, User.balance)
|
||||
... .join(User.accounts)
|
||||
... .filter(User.balance > 5000)
|
||||
... )
|
||||
{printsql}SELECT "user".id AS user_id, "user".name AS user_name,
|
||||
account.balance AS account_balance
|
||||
FROM "user" JOIN account ON "user".id = account.user_id
|
||||
@@ -487,8 +499,11 @@ would use an outer join:
|
||||
|
||||
>>> from sqlalchemy import select
|
||||
>>> from sqlalchemy import or_
|
||||
>>> print (select(User, User.balance).outerjoin(User.accounts).
|
||||
... filter(or_(User.balance < 5000, User.balance == None)))
|
||||
>>> print(
|
||||
... select(User, User.balance)
|
||||
... .outerjoin(User.accounts)
|
||||
... .filter(or_(User.balance < 5000, User.balance == None))
|
||||
... )
|
||||
{printsql}SELECT "user".id AS user_id, "user".name AS user_name,
|
||||
account.balance AS account_balance
|
||||
FROM "user" LEFT OUTER JOIN account ON "user".id = account.user_id
|
||||
@@ -528,15 +543,16 @@ we can adjust our ``SavingsAccount`` example to aggregate the balances for
|
||||
|
||||
|
||||
class SavingsAccount(Base):
|
||||
__tablename__ = 'account'
|
||||
__tablename__ = "account"
|
||||
id: Mapped[int] = mapped_column(primary_key=True)
|
||||
user_id: Mapped[int] = mapped_column(ForeignKey('user.id'))
|
||||
user_id: Mapped[int] = mapped_column(ForeignKey("user.id"))
|
||||
balance: Mapped[Decimal] = mapped_column(Numeric(15, 5))
|
||||
|
||||
owner: Mapped[User] = relationship(back_populates="accounts")
|
||||
|
||||
|
||||
class User(Base):
|
||||
__tablename__ = 'user'
|
||||
__tablename__ = "user"
|
||||
id: Mapped[int] = mapped_column(primary_key=True)
|
||||
name: Mapped[str] = mapped_column(String(100))
|
||||
|
||||
@@ -546,7 +562,9 @@ we can adjust our ``SavingsAccount`` example to aggregate the balances for
|
||||
|
||||
@hybrid_property
|
||||
def balance(self) -> Decimal:
|
||||
return sum((acc.balance for acc in self.accounts), start=Decimal("0"))
|
||||
return sum(
|
||||
(acc.balance for acc in self.accounts), start=Decimal("0")
|
||||
)
|
||||
|
||||
@balance.inplace.expression
|
||||
@classmethod
|
||||
@@ -557,7 +575,6 @@ we can adjust our ``SavingsAccount`` example to aggregate the balances for
|
||||
.label("total_balance")
|
||||
)
|
||||
|
||||
|
||||
The above recipe will give us the ``balance`` column which renders
|
||||
a correlated SELECT:
|
||||
|
||||
@@ -604,6 +621,7 @@ named ``word_insensitive``::
|
||||
from sqlalchemy.orm import Mapped
|
||||
from sqlalchemy.orm import mapped_column
|
||||
|
||||
|
||||
class Base(DeclarativeBase):
|
||||
pass
|
||||
|
||||
@@ -612,8 +630,9 @@ named ``word_insensitive``::
|
||||
def __eq__(self, other: Any) -> ColumnElement[bool]: # type: ignore[override] # noqa: E501
|
||||
return func.lower(self.__clause_element__()) == func.lower(other)
|
||||
|
||||
|
||||
class SearchWord(Base):
|
||||
__tablename__ = 'searchword'
|
||||
__tablename__ = "searchword"
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True)
|
||||
word: Mapped[str]
|
||||
@@ -675,6 +694,7 @@ how the standard Python ``@property`` object works::
|
||||
def _name_setter(self, value: str) -> None:
|
||||
self.first_name = value
|
||||
|
||||
|
||||
class FirstNameLastName(FirstNameOnly):
|
||||
# ...
|
||||
|
||||
@@ -684,11 +704,11 @@ how the standard Python ``@property`` object works::
|
||||
# of FirstNameOnly.name that is local to FirstNameLastName
|
||||
@FirstNameOnly.name.getter
|
||||
def name(self) -> str:
|
||||
return self.first_name + ' ' + self.last_name
|
||||
return self.first_name + " " + self.last_name
|
||||
|
||||
@name.inplace.setter
|
||||
def _name_setter(self, value: str) -> None:
|
||||
self.first_name, self.last_name = value.split(' ', 1)
|
||||
self.first_name, self.last_name = value.split(" ", 1)
|
||||
|
||||
Above, the ``FirstNameLastName`` class refers to the hybrid from
|
||||
``FirstNameOnly.name`` to repurpose its getter and setter for the subclass.
|
||||
@@ -709,8 +729,7 @@ reference the instrumented attribute back to the hybrid object::
|
||||
@FirstNameOnly.name.overrides.expression
|
||||
@classmethod
|
||||
def name(cls):
|
||||
return func.concat(cls.first_name, ' ', cls.last_name)
|
||||
|
||||
return func.concat(cls.first_name, " ", cls.last_name)
|
||||
|
||||
Hybrid Value Objects
|
||||
--------------------
|
||||
@@ -751,7 +770,7 @@ Replacing the previous ``CaseInsensitiveComparator`` class with a new
|
||||
def __str__(self):
|
||||
return self.word
|
||||
|
||||
key = 'word'
|
||||
key = "word"
|
||||
"Label to apply to Query tuple results"
|
||||
|
||||
Above, the ``CaseInsensitiveWord`` object represents ``self.word``, which may
|
||||
@@ -762,7 +781,7 @@ SQL side or Python side. Our ``SearchWord`` class can now deliver the
|
||||
``CaseInsensitiveWord`` object unconditionally from a single hybrid call::
|
||||
|
||||
class SearchWord(Base):
|
||||
__tablename__ = 'searchword'
|
||||
__tablename__ = "searchword"
|
||||
id: Mapped[int] = mapped_column(primary_key=True)
|
||||
word: Mapped[str]
|
||||
|
||||
@@ -983,6 +1002,7 @@ class hybrid_method(interfaces.InspectionAttrInfo, Generic[_P, _R]):
|
||||
|
||||
from sqlalchemy.ext.hybrid import hybrid_method
|
||||
|
||||
|
||||
class SomeClass:
|
||||
@hybrid_method
|
||||
def value(self, x, y):
|
||||
@@ -1080,6 +1100,7 @@ class hybrid_property(interfaces.InspectionAttrInfo, ORMDescriptor[_T]):
|
||||
|
||||
from sqlalchemy.ext.hybrid import hybrid_property
|
||||
|
||||
|
||||
class SomeClass:
|
||||
@hybrid_property
|
||||
def value(self):
|
||||
@@ -1096,7 +1117,7 @@ class hybrid_property(interfaces.InspectionAttrInfo, ORMDescriptor[_T]):
|
||||
self.expr = _unwrap_classmethod(expr)
|
||||
self.custom_comparator = _unwrap_classmethod(custom_comparator)
|
||||
self.update_expr = _unwrap_classmethod(update_expr)
|
||||
util.update_wrapper(self, fget)
|
||||
util.update_wrapper(self, fget) # type: ignore[arg-type]
|
||||
|
||||
@overload
|
||||
def __get__(self, instance: Any, owner: Literal[None]) -> Self: ...
|
||||
@@ -1158,6 +1179,7 @@ class hybrid_property(interfaces.InspectionAttrInfo, ORMDescriptor[_T]):
|
||||
def foobar(self):
|
||||
return self._foobar
|
||||
|
||||
|
||||
class SubClass(SuperClass):
|
||||
# ...
|
||||
|
||||
@@ -1367,10 +1389,7 @@ class hybrid_property(interfaces.InspectionAttrInfo, ORMDescriptor[_T]):
|
||||
@fullname.update_expression
|
||||
def fullname(cls, value):
|
||||
fname, lname = value.split(" ", 1)
|
||||
return [
|
||||
(cls.first_name, fname),
|
||||
(cls.last_name, lname)
|
||||
]
|
||||
return [(cls.first_name, fname), (cls.last_name, lname)]
|
||||
|
||||
.. versionadded:: 1.2
|
||||
|
||||
|
Reference in New Issue
Block a user