Как украсить класс, чтобы я мог изменить атрибут класса во время выполнения - PullRequest
0 голосов
/ 05 мая 2020
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 ]

0 голосов
/ 07 мая 2020

В комментарии вы сказали, что настоящая цель - зашифровать пароли на входе и выходе из класса. 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")

(так что в этом случае в базе данных хранится только хешированный пароль - чтобы проверить пароль, введите sh и сравните его с user.password)

0 голосов
/ 05 мая 2020

Если вы настаиваете на использовании декоратора:

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)
0 голосов
/ 07 мая 2020

Достаточно ли определения свойства в декораторе для вашего варианта использования?

Например:

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)
0 голосов
/ 05 мая 2020

Это не похоже на подходящий вариант использования декоратора ... мне кажется, вы можете просто использовать наследование и добавить новый атрибут в __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})"
...