Flask使用笔记

request.files.getlist()的原理

request.files.getlist()
request.files 调用BaseRequest的files()cache_property属性
flies()的内容中调用_load_from_data()给BaseRequest添加files属性, 
_load_from_data()中会调用parameter_storage_class而
parameter_storage_class = ImmutableMultiDict
ImmutableMultiDict又继承子MulitDict, MultiDict中包含getlist方法.
该方法可以取出所有的值

jinja2 macro中关键字参数的传递

关于jinja2中的macros
macro中可以传递键值参数
直接在需要的地方加上**kwargs就可以了
举个例子:
<!-- 定义 -->
{% macro form_field(field) %}
    field
    field(**kwargs)
{% endmacro%}

<!-- 定义 -->
{% macro form_field(field) %}
    {{ field.label }}<br>
    {% if field.flags.required %}
        {{ field(required='required', **kwargs) }}<br>
    {% else %}
        {{ field(**kwargs) }}<br>
    {% endif %}
    {% if field.errors %}
        {% for error in field.errors %}
            <small class="error">{{ error }}</small><br>
        {% endfor %}
    {% endif %}
{% endmacro %}

<!-- 调用 -->
{{ form_field(form.body, rows=5, cols=50) }}

flask 添加shell上下文

注册shell上下文处理函数
@app.shell_context_processor
def make_shell_context()
    return dict(db=db, Note=Note)

shell_context_processor会将函数的返回值添加到shell_context_processors中, shell_context_processors是一个包含shel上下文的字典列表,
只包含由shell_context_processor注册的上下文函数

SQLAlchemy中的一对多的class示例

class Author(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(70), unique=True)
    phone = db.Column(db.String(20))
    articles = db.relationship('Article')

    def __repr__(self):
        return '<Author %r>' % self.name


class Article(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(50), index=True)
    body = db.Column(db.Text)
    author_id = db.Column(db.Integer, db.ForeignKey('author.id'))

    def __repr__(self):
        return '<Article %r>' % self.title


class Writer(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(70), unique=True)
    books = db.relationship('Book', back_populates='writer')

    def __repr__(self):
        return '<Writer %r>' % self.name


class Book(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.Integer, index=True)
    writer_id = db.Column(db.Integer, db.ForeignKey('writer.id'))
    writer = db.relationship('Writer', back_populates='books')

    def __repr__(self):
        return '<Book %r>' % self.name


class Singer(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(70), unique=True)
    songs = db.relationship('Song', backref='singer')
    # songs = db.relationship('Song', backref=db.backref('singer', uselist=False))

    def __repr__(self):
        return '<Singer %r>' % self.name


class Song(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(50), index=True)
    singer_id = db.Column(db.Integer, db.ForeignKey('singer.id'))

    def __repr__(self):
        return '<Song %s>' % self.name
# flask shell 上下文注册
@app.shell_context_processor
def make_shell_context():
    return dict(db=db, Note=Note, Author=Author, Article=Article, Writer=Writer, Book=Book, Singer=Singer, Song=Song)
  • sqlalchemy中的matesata()中的naming_convention:

https://docs.sqlalchemy.org/en/latest/core/metadata.html#sqlalchemy.schema.MetaData.params.naming_convention

* %(table_name)s - the name of the Table object associated with the constraint.
* %(referred_table_name)s - the name of the Table object associated with the referencing target of a ForeignKeyConstraint.
* %(column_0_name)s - the name of the Column at index position “0” within the constraint.
* %(column_0N_name)s - the name of all Column objects in order within the constraint, joined without a separator.
* %(column_0_N_name)s - the name of all Column objects in order within the constraint, joined with an underscore as a separator.
* %(column_0_label)s, %(column_0N_label)s, %(column_0_N_label)s - the label of either the zeroth Column or all Columns, separated with or without an underscore
* %(column_0_key)s, %(column_0N_key)s, %(column_0_N_key)s - the key of either the zeroth Column or all Columns, separated with or without an underscore
* %(referred_column_0_name)s, %(referred_column_0N_name)s %(referred_column_0_N_name)s, %(referred_column_0_key)s, %(referred_column_0N_key)s, … column tokens which render the names/keys/labels of columns that are referenced by a ForeignKeyConstraint.
* %(constraint_name)s - a special key that refers to the existing name given to the constraint. When this key is present, the Constraint object’s existing name will be replaced with one that is composed from template string that uses this token. When this token is present, it is required that the Constraint is given an explicit name ahead of time.
* user-defined: any additional token may be implemented by passing it along with a fn(constraint, table) callable to the naming_convention dictionary.
  • MetaData()中的name_convention:

    column_0_label 即为第一个column第0个位置的标签, 一般为表名加字段名
    column_0_name 为column的0位参数的name -> 字段名
    column_0_key 和上面的一样
    

    例子:

    "ix": 'ix_%(column_0_label)s',
    "uq": "uq_%(table_name)s_%(column_0_name)s",
    "ck": "ck_%(table_name)s_%(constraint_name)s",
    "fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s",
    "pk": "pk_%(table_name)s"
    

    “fk”, “pk”, “ix”, “ck”, “uq”
    基本上所有的名称

    table_name
    referred_table_name
    
    column_0_name
    column_0N_name
    column_0_N_name
    
    column_0_label
    column_0N_label
    column_0_N_label
    
    column_0_key
    column_0N_key
    column_0_N_key
    
    
    referred_column_0_name
    referred_column_0N_name
    referred_column_0_N_name
    
    referred_column_0_label
    referred_column_0N_label
    referred_column_0_N_label
    
    referred_column_0_key
    referred_column_0N_key
    referred_column_0_N_key
    

relationship中的部分参数

  • secondary: 作用: 多对多的环境下指定第三张参考的表
  • priamryjoin的作用
    class IPA(Base):
        __tablename__ = 'ip_address'
    
        id = Column(Integer, primary_key=True)
        v4address = Column(INET)
    
        network = relationship("Network",
                            # 指定连接条件
                            primaryjoin="IPA.v4address.op('<<', is_comparison=True)(foreign(Network.v4representation))",
                            viewonly=True
                        )
    class Network(Base):
        __tablename__ = 'network'
    
        id = Column(Integer, primary_key=True)
        v4representation = Column(CIDR)
    
  • primaryjoin和secondaryjoin的作用:
    from sqlalchemy import Integer, ForeignKey, String, Column, Table
    from sqlalchemy.ext.declarative import declarative_base
    from sqlalchemy.orm import relationship
    
    Base = declarative_base()
    
    node_to_node = Table("node_to_node", Base.metadata,
        Column("left_node_id", Integer, ForeignKey("node.id"), primary_key=True),
        Column("right_node_id", Integer, ForeignKey("node.id"), primary_key=True)
    )
    
    class Node(Base):
        __tablename__ = 'node'
        id = Column(Integer, primary_key=True)
        label = Column(String)
        right_nodes = relationship("Node",
                            secondary=node_to_node,
                            primaryjoin=id==node_to_node.c.left_node_id,
                            secondaryjoin=id==node_to_node.c.right_node_id,
                            backref="left_nodes"
        )
    
  • 参数也可以使用字符串的格式
    class Node(Base):
        __tablename__ = 'node'
        id = Column(Integer, primary_key=True)
        label = Column(String)
        right_nodes = relationship("Node",
                            secondary="node_to_node",
                            primaryjoin="Node.id==node_to_node.c.left_node_id",
                            secondaryjoin="Node.id==node_to_node.c.right_node_id",
                            backref="left_nodes"
        )
    
  • cascade
    cascsde设置为cascade='all', 与cascade='all delete-orphan'的区别:
    all: 删除父级内容, 子级内容跟着删除, 解除关系的话就能救一命.
    all orphan 删除父及内容, 子集跟着删除.同时, 在父级解除关系的时候也会删除自己内容.
    

flask-Migrate的使用

默认情况下使用下面的迁移代码:

def upgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.add_column('author', sa.Column('email', sa.String(length=20), nullable=True))
    # ### end Alembic commands ###


def downgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.drop_column('author', 'email')
    # ### end Alembic commands ###

不过也可以修改成这个样子(可用于sqlite, move and copy 工作流, 创建, 转移, 删除):
注意要自己修改呦!!!

def upgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    with op.batch_alter_table('note') as branch_op:
        branch_op.add_column(sa.Column('timestemp', sa.DateTime(), nullable=True))
        # branch_op.add_column(...) 如此继续下去
    # ### end Alembic commands ###


def downgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    with op.batch_alter_table('note') as branch_op:
        branch_op.drop_column('timestemp')
        # branch_op.drop_column('...') 同理
    # ### end Alembic commands ###

SQLAlchemy中的event事件:

append:

@event.listens_for(SomeClass.some_attribute, 'append')
def receive_append(target, value, initiator):
    """
    target
    value
    initiator
    """
    pass
 
@event.listens_for(SomeClass.some_attribute, 'bulk_replace')
def receive_bulk_replace(target, values, initiator):

@db.event.listens_for(Draft.body, 'set')
def increment_edit_time(target, value, oldvalue, initiator):
    if target.edit_time is not None:
        target.edit_time += 1

注册app控制命令

使用装饰器@app.cli.commend()注册命令, 使用@click.option()添加选项
option的部分参数:\

  • is_flag: forces this option to act as a flag. The default is auto detection.
    is_flag设置为True可以将这个选项声明为boolean flag
  • prompt: if set to True or a non empty string then the user will be prompted for input.If set to True the prompt will be the option name capitalized. 将选项设置为必须参数, 如果没有提供通过终端获取
  • default: click自动识别参数类型, 添加到help文档中, 可以使用()设置位置参数,

commend的部分参数:

  • name: 指定控制命令的名称.

What does it look like? Here is an example of a simple Click program:

import click

@click.command()
@click.option('--count', default=1, help='Number of greetings.')
@click.option('--name', prompt='Your name', help='The person to greet.')
def hello(count, name):
    """Simple program that greets NAME for a total of COUNT times."""
    for x in range(count):
        click.echo('Hello %s!' % name)

if __name__ == '__main__':
    hello()

And what it looks like when run:

$ python hello.py --count=3
Your name: John
Hello John!
Hello John!
Hello John!

$ python help.py 
Your name: 张三
Hello 张三!

It automatically generates nicely formatted help pages:

$ python hello.py --help
Usage: hello.py [OPTIONS]

  Simple program that greets NAME for a total of COUNT times.

Options:
  --count INTEGER  Number of greetings.
  --name TEXT      The person to greet.
  --help           Show this message and exit.

使用itsdangerous创建token签名:

generate_token()
params中最好包含有操作类型, 我的意思是生成token的目的,这个目的最好量化成一些固定值
并保存起来, 然后按照目的传入generate_token()中, 其次要有需要验证的信息, 比如对于给注册用户发
送的邮箱验证的token需要添加用户的id.
validate_token() 根据上面的描述, 验证函数必然包含的参数就清楚明了了, 应该有的内容是生成的token, 以及token中包含的信息, 还是已上一个例子来说明, 即应该包含id

serializer中的验证的部分的过期时间不需要在校验的序列化器中使用.

login_required装饰器如何起作用:

  • 对于使用了login(user=user, remember=remember…)的用户, 即为已登陆的用户:

login_user方法将user_id remember保存到session中
并将user添加到_request_ctx_stack.top.user中
然后当使用current_user时就会从_request_ctx_stack.top中读取到user
判断user的is_authenticated(所有用户的这个值都为True)
这里的语句是:

  if not current_user.is_authenticated:
      return current_app.login_manager.unauthorized()
  return func()

显然就会调用视图函数

  • 对于没有登陆的用户

同样的调用这次会执行 current_app.login_mamager.unauthorized()
这个方法返会登陆视图, 如果没有指定, 会抛出401的网页错误

current_user = LocalProxy(lambda: _get_user())
_get_user

    if has_request_context() and not hasattr(_request_ctx_stack.top, 'user'):
        current_app.login_manager._load_user()

    return getattr(_request_ctx_stack.top, 'user', None)

_load_user

    config = current_app.config
    if config.get('SESSION_PROTECTION', self.session_protection):
        deleted = self._session_protection()
        if deleted:
            return self.reload_user()

    is_missing_user_id = 'user_id' not in session
    if is_missing_user_id:
        cookie_name = config.get('REMEMBER_COOKIE_NAME', COOKIE_NAME)
        header_name = config.get('AUTH_HEADER_NAME', AUTH_HEADER_NAME)
        has_cookie = (cookie_name in request.cookies and
                        session.get('remember') != 'clear')
        if has_cookie:
            return self._load_from_cookie(request.cookies[cookie_name])
        elif self.request_callback:
            return self._load_from_request(request)
        elif header_name in request.headers:
            return self._load_from_header(request.headers[header_name])

    return self.reload_user()

_load_from_cookie
_load_from_header
_load_from_request

    def _load_from_cookie(self, cookie):
        user_id = decode_cookie(cookie)
        if user_id is not None:
            session['user_id'] = user_id
            session['_fresh'] = False

        self.reload_user()

        if _request_ctx_stack.top.user is not None:
            app = current_app._get_current_object()
            user_loaded_from_cookie.send(app, user=_get_user())

    def _load_from_header(self, header):
        user = None
        if self.header_callback:
            user = self.header_callback(header)
        if user is not None:
            self.reload_user(user=user)
            app = current_app._get_current_object()
            user_loaded_from_header.send(app, user=_get_user())
        else:
            self.reload_user()

    def _load_from_request(self, request):
        user = None
        if self.request_callback:
            user = self.request_callback(request)
        if user is not None:
            self.reload_user(user=user)
            app = current_app._get_current_object()
            user_loaded_from_request.send(app, user=_get_user())
        else:
            self.reload_user()

reload_user(self, user=None)

    ctx = _request_ctx_stack.top
    if user is None:
        user_id = session.get('user_id')
        if user_id is None:
            ctx.user = self.anonymous_user()
        else:
            if self.user_callback is None:
                raise Exception(
                    "No user_loader has been installed for this "
                    "LoginManager. Refer to"
                    "https://flask-login.readthedocs.io/"
                    "en/latest/#how-it-works for more info.")
            user = self.user_callback(user_id)
            if user is None:
                ctx.user = self.anonymous_user()
            else:
                ctx.user = user
    else:
        ctx.user = user

self.user_callback

    def user_loader(self, callback):
        self.user_callback = callback
        return callback
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值