【问题标题】:How to decorate a class so that i could be able to change the attribute of a class in run time如何装饰一个类,以便我能够在运行时更改类的属性
【发布时间】:2020-08-19 18:17:52
【问题描述】:
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)

【问题讨论】:

    标签: python flask flask-sqlalchemy python-decorators python-class


    【解决方案1】:

    这似乎不是装饰器的合适用例...在我看来,您可以只使用继承并在__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})"
    

    【讨论】:

    • 嗨@cosmic_inquiry 我正在探索装饰类的可能性。我知道我应该提供API 来计算密码的哈希值和密码验证。但我想知道在这种情况下是否可以装饰类因为我想用加密函数装饰类,该函数计算 ssid 的哈希值并将其存储在名为密码的类的新属性中。
    【解决方案2】:

    如果你坚持使用装饰器:

    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)
    

    【讨论】:

    • 我想装饰从flask-sqlalchemy的db.Model类继承的类。无论如何我都无法访问包装器中类的变量。
    • 嗨@cosmic_inquiry 我正在与您分享文件的位置,请查看。 github repo link。回购中也提出了一个问题。如果你能解决它,那对我来说将是很大的帮助。
    • 这不是真的- sqlalchemy 模型是 python 类和其他任何类一样。您可以定义或覆盖方法,包括 initrepr。您还可以添加属性。 “将属性映射到 db 列部分”来自 db.Column 中的 Descriptormagic - 不是 db.Column 的字段就像普通字段一样。
    【解决方案3】:

    在装饰器中定义一个属性是否足以满足您的用例?

    例如:

    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)
    

    【讨论】:

    • 是的,它有效,你能帮我做一件事吗?是 db 之类的扩展对象,用于 flask-sqlalchemy db=SQLAlchemy(app)。存储在应用程序上下文中,以便可以从包中的任何位置访问对象。如果是,那么我应该如何访问这些对象。
    • 请查看我想做的事情的要点。(gist.github.com/princekrroshan01/…)
    【解决方案4】:

    在评论中,您说实际目标是在进出课堂的路上加密密码。 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 进行比较)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-09
      • 1970-01-01
      • 2016-12-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多