Как украсить класс, чтобы я мог изменить атрибут класса во время выполнения
def decorator(cls):
#code
return cls
@decorator
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(20),nullable=False)
ssid = db.Column(db.String(20))
def __repr__(self):
return f"User('{self.username}',{self.password})"
Я хочу украсить класс таким образом, чтобы я мог получить доступ к значению ssid в функции декоратора и добавить новый атрибут к классу. Поскольку для нового атрибута требуется значение ssid.
user = User(username='prince',ssid='9734ait')
db.session.add(user)
4 ответа
Если вы настаиваете на использовании декоратора:
class Decorator:
def __call__(self, cls):
class Inner(cls):
cls.password = cls.ssid[::-1]
return Inner
@Decorator()
class User:
ssid = "fooo"
def __repr__(self):
return f"User({self.ssid}, {self.password})"
u = User()
print(u)
Выход:
User(fooo, ooof)
Достаточно ли определения свойства в декораторе для вашего варианта использования?
Например:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///site.db"
db = SQLAlchemy(app)
class Encryptor:
def __call__(self, cls):
class Inner(cls):
# define a getter function to return the password
def password_getter(self):
# return the calculated password here now you have access to username and ssid
return f'{self.username} - {self.ssid}'.upper()
setattr(cls, "password", property(fget=password_getter))
return Inner
@Encryptor()
class User5(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(20), nullable=False)
ssid = db.Column(db.String(20))
def __repr__(self):
return f"User('{self.username}',{self.ssid}; PASSWORD: {self.password})"
db.create_all()
user = User5(username="prince", ssid="3456ait")
db.session.add(user)
db.session.commit()
users = User5.query.all()
print(users)
В комментарии вы сказали, что настоящая цель - зашифровать пароли при входе в класс и выходе из него. Sqlalchemy предлагает это с помощью гибридных свойств. Это пример из одного из моих проектов -
class User(Base):
__tablename__ = "user"
id = Column(Integer, primary_key=True)
username = Column(String(255))
hashed_password = Column("password", String(255))
@hybrid_property
def password(self):
return self.hashed_password
@password.setter # type: ignore
def password(self, value):
rounds = 4
if not isinstance(value, bytes):
value = value.encode("utf-8")
self.hashed_password = hashpw(value, gensalt(rounds)).decode("utf-8")
(поэтому в этом случае в базе данных хранится только хешированный пароль - чтобы проверить пароль, вы хешируете ввод и сравниваете его с user.password)
Это не похоже на подходящий вариант использования декоратора... мне кажется, вы можете просто использовать наследование и добавить новый атрибут в __init__
. Например:
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(20),nullable=False)
ssid = db.Column(db.String(20))
def __init__(self, *args, password=None, your_new_attribute=None, **kwargs):
super().__init__(*args, **kwargs)
self.password = hash(ssid)
self.your_new_attribute = your_new_attribute
def __repr__(self):
return f"User('{self.username}',{self.password})"