慕课网 python微电影项目 小知识点整理

项目视频下载地址

链接: https://pan.baidu.com/s/11ROsvoKukAUAiEnztvS55A 密码: qsj2

项目代码github地址

链接: https://github.com/cafeUncle/movie-mooc.git

mysql命令

mysql命令行下,\s命令可以查看简单信息


pip操作

pip 下载时如果很慢,可以使用-i命令指定下载源 使用--trusted-host指定信任的主机
pip install -i http://pypi.douban.com/simple/ --trustrt-host pypi.douban.com virtualenv


pip description
freeze Output installed packages in requirements format.
list List installed packages.

pip安装包的方式中,有如下两种安装方式:

pip install flask
pip install -r requirements.txt
  • 文件requirement.txt里面内容的格式和pip freeze的格式完全一样。因此我们可以将pip freeze的内容输出至requirements.txt。其他机器可以根据导出的requirements.txt进行包安装。
pip freeze > requirements.txt # 输出本地包环境至文件
pip install -r requirements.txt # 根据文件进行包安装
  • pip freeze 为什么比 pip list 的包少几个呢?
    因为pip , wheel , setuptools 等包,是自带的而无法(un)install的。考虑到pip freeze的用途,所以这些包并没有显示。
    如果一定要用pip freeze来显示所有包,可以加上参数-all,即pip freeze -all

蓝图

flask blueprint

  1. 定义蓝图
    app/admin/__init__.py
    from flask import Blueprint
    admin = Blueprint('admin', name)
    import views
  2. 调用蓝图
    app/admin/views.py
    from . import admin
    @admin.route("/")
  3. 注册蓝图
    app/__init__.py
    from flask import admin as admin_blueprint
    app.register_blueprint(admin_blueprint, url_prefix="/admin")
    必须先调用蓝图设置好路由,然后再注册蓝图

前台布局搭建

  1. 静态文件引入: {{ url_for('static', filename='文件路径') }}
  2. 定义路由: {{ url_for('模块名.视图名',变量=参数) }}
    模块名.视图名对应view.py中的方法名,而不是html文件名,个人认为写"/login"这样的路径更方便,学到后面如果发现url_for的特别用法,再来更新
  3. 定义数据块: {% block 数据块名称 %} ... {% endblock %}
    一般定义在base页面中,类似freemarker中的macro,可以在子模板中引用同名block块。
  1. 一般首先定义一个base模板,在内容中允许定义多个block块,由子模板引用,子模板决定替换哪些block块,没有定义的块即不替换,直接使用父模板的block块 。
  1. 通过{{ block.super }},可以引用上级代码块并在其基础上进行一些修改
{% block name%}
    {{ block.super }}
    <p>...
{% endblock %}
  1. 引用时首先要在子模板中{% extends "base.html" %}

extends只能写在子模板第一行,参数一般为字符串,也可为变量,可带路径或相对路径,以TEMPLATE_DIRS的模板目录为基准

  1. 其它
  1. {% include 'includes/nav.html' %}

可带路径或相对路径,以TEMPLATE_DIRS的模板目录为基准
也可以使用变量名 {% include template_name %},包含的变量都会统一处理,不区分是第几层模板
被包含在(include)的页面里面不能用{%block%},类似jsp的静态导入<%@ include file="fileurl" %>和动态导入<jsp:include page="menu.jsp"/>的区别

  1. {% import 'ui/page_admin.html' as pg %}

引用后可以使用别名调用。
page_admin.html 内容如下,类似freemarker的macro

{% macro page(data, url) %}
{% if data %}
<ul class="pagination pagination-sm no-margin pull-right">
    <li><a href="{{url_for(url, page=1)}}">首页</a></li>

    {% if data.has_prev %}
    <li><a href="{{url_for(url, page=data.prev_num)}}">上一页</a></li>
    {% else %}
    <li><a class="disabled">上一页</a></li>
    {% endif %}

    {% for v in data.iter_pages() %}
    {% if v == data.page %}
    <li class="active"><a href="#">{{ v }}</a></li>
    {% else %}
    <li><a href="{{url_for(url, page=v)}}">{{ v }}</a></li>
    {% endif %}
    {% endfor %}

    {% if data.has_next %}
    <li><a href="{{url_for(url, page=data.next_num)}}">下一页</a></li>
    {% else %}
    <li><a class="disabled">下一页</a></li>
    {% endif %}
    <li><a href="{{url_for(url, page=data.pages)}}">尾页</a></li>
</ul>
{% endif %}
{%- endmacro %}

调用时

<div class="box-footer clearfix">
        {{ pg.page(page_data, 'admin.tag_list') }}
</div>
  1. {% for x in range(1,5)%}{{x}}{% endfor %}
<div class="box-body">
{% for msg in get_flashed_messages(category_filter=['ok']) %}   # 过滤显示flashed信息
        <h4><i class="icon fa fa-warning"></i> 操作成功!</h4>
                {{msg}}
        </div>
{% endfor %}
{% for msg in get_flashed_messages(category_filter=['err']) %}
        <h4><i class="icon fa fa-warning"></i> 操作失败!</h4>
                {{msg}}
        </div>
{% endfor %}
<div class="form-group">
        <label for="input_title">{{form.title.label}}</label>
        {{form.title}}
        {% for err in form.title.errors %}   # 显示validators的错误信息
              <div class="col-md-12">
                    <font style="color: red;">{{err}}</font>
              </div>
         {% endfor %}
</div>

后台

  1. 编写wtforms.validators的ValidationError自定义验证器时,方法名后缀一定要和参数名相同,否则不会触发该验证



FlaskForm

from flask_wtf import FlaskForm

class RoleForm(FlaskForm):   # 继承FlaskForm类
    name = StringField(   # 表单类型 StringField, PasswordField, SubmitField, FileField, TextAreaField, SelectField, SelectMultipleField
        label="角色名称",   # {{form.label}}
        validators=[   # 验证器
            DataRequired("请输入角色名称")
        ],
        description="角色名称",
        render_kw={   # 元素属性
            "class": "form-control",
            "id": "input_name",
            "placeholder": "请输入角色名称!"
        }
    )
star = SelectField(
        label="星级",
        validators=[
            DataRequired("请选择星级!")
        ],
        description="星级",
        coerce=int,
        choices=[(1, "1星"), (2, "2星"), (3, "3星"), (4, "4星"), (5, "5星")],
        render_kw={
            "class": "form-control"
        }
    )
    auths = SelectMultipleField(
        label="权限列表",
        validators=[
            DataRequired("请选择权限")
        ],
        coerce=int,
        choices=[(v.id, v.name) for v in auth_list],
        description="权限列表",
        render_kw={
            "class": "form-control"
        }
    )
    submit = SubmitField(
        "编辑",
        render_kw={
            "class": "btn btn-primary"
        }
    )
    def validate_account(self, field):   # 自定义验证器,第一个参数必须是self,方法名称必须是validate_变量名,否则无法匹配生效
        account = field.data
        admin = Admin.query.filter_by(name=account).count()
        if admin == 0:
            raise ValidationError("账号不存在!")
    def __repr__(self):   #  打印方法
        return "<Admin %r>" % self.name
  1. 登录验证装饰器
def admin_login_req(f):
    @wraps(f)
    def decorated_function(*args, **kwargs):
        if 'admin' not in session:
            return redirect(url_for('admin.login', next=request.url))
        return f(*args, **kwargs)

    return decorated_function

使用时将@admin_login_req注解写在方法上

  1. 权限控制装饰器
def admin_auth(f):
    @wraps(f)
    def decorated_function(*args, **kwargs):
        admin = Admin.query.join(
            Role
        ).filter(
            Admin.role_id == Role.id,
            Admin.id == session['admin_id']
        ).first()
        auths = admin.role.auths
        auths = list(map(lambda v: int(v), auths.split(',')))
        auth_list = Auth.query.all()
        urls = [v.url for v in auth_list for val in auths if val == v.id]
        rule = request.url_rule
        print(urls)
        print(rule)
        if str(rule) not in urls:
            abort(404)
        return f(*args, **kwargs)
    return decorated_function

使用时将@admin_auth注解写在方法上

  1. 上下文应用处理器 封装全局变量,展现到模板中
@admin.context_processor
def tpl_extra():
    data = dict(
        online_time=datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    )
    return data

使用时在模板中用{{online_time}}调用

  1. 获取当前日期并格式化,及生成uuid
  1. werkzeug库
    from werkzeug.security import generate_password_hash
    from werkzeug.security import check_password_hash
    def check_pwd(self, pwd): # 检查密码
    from werkzeug.security import check_password_hash
    return check_password_hash(self.pwd, pwd)

  2. Gists

Gist 作用
request.url_rule 获取请求url
request.remote_addr 获取请求地址
Auth.query.all() 查询数据
Admin.query.filter_by(name=data['account']).first() 查询数据
db.session.add(admin_log) 插入数据
db.session.delete(movie) 删除数据
db.session.commit() 提交数据
session.pop('admin', None) 删除session
Tag.query.filter_by(name=data['name']).count() 统计
page_data = Tag.query.order_by(Tag.add_time.desc()).paginate(page=page, per_page=10) 排序 分页
Tag.query.filter_by(id=id).first_or_404() 找不到则返回404
@admin.route('/tag/del/<int:id>/', methods=['GET']) 路径参数
flash('添加电影成功', 'ok') {% for msg in get_flashed_messages(category_filter=['ok']) %}
page_data = Movie.query.join(Tag).filter(Movie.tag_id == Tag.id).order_by(Movie.add_time.desc()).paginate(page=page, per_page=10) 多表关联,排序分页
Movie.query.filter_by(title=data['title']).count() 筛选查询
if form.validate_on_submit() 用自定义的验证器验证表单
json.dumps({"t": str(datetime.datetime.now()), 'action': 'getJson'}) 格式化为json
request.args.get("next") 获取转发链接
page_data = MovieCol.query.join(Movie).join(User).filter(Movie.id == MovieCol.movie_id,User.id == 1).filter_by(Movie.title == '战狼').order_by(Movie.add_time.desc()).paginate(page=1,per_page=10) N个表关联
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,716评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,558评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,431评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,127评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,511评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,692评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,915评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,664评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,412评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,616评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,105评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,424评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,098评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,096评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,869评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,748评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,641评论 2 271