Python Flask框架学习31:orm操作及序列化/更规范的文件格式

32 篇文章 3 订阅

文件树如下:

è¿éåå¾çæè¿°

首先是utils包:
functions.py配置代码如下:

from flask_sqlalchemy import SQLAlchemy
from flask_debugtoolbar import DebugToolbarExtension
from flask_restful import Api
from flask_marshmallow import Marshmallow

db = SQLAlchemy()

debugtoolbar = DebugToolbarExtension()

api = Api()

ma = Marshmallow()

def get_db_uri(DATABASE):

    user = DATABASE.get('USER')
    password = DATABASE.get('PASSWORD')
    host = DATABASE.get('HOST')
    port = DATABASE.get('PORT')
    name = DATABASE.get('NAME')
    db = DATABASE.get('DB')
    driver = DATABASE.get('DRIVER')



    return '{}+{}://{}:{}@{}:{}/{}'.format(db, driver, user, password, host, port, name)


def init_ext(app):

    # 对app进行初始化SQLALCHEMY
    db.init_app(app=app)
    # 对app进行初始化debugtoolbar
    debugtoolbar.init_app(app=app)
    # 对app进行初始化restful.Api
    api.init_app(app=app)
    # 对app进行初始化Marshmallow
    ma.init_app(app=app)

setting.py配置代码如下:


import os

from utils.functions import get_db_uri
# 基础路径
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# 页面模板
templates_dir = os.path.join(BASE_DIR, 'templates')
# 静态模板
static_dir = os.path.join(BASE_DIR, 'static')

DATABASE = {
    # 用户
    'USER':'root',
    # 密码
    'PASSWORD':'123456789',
    # 地址
    'HOST':'localhost',
    # 端口
    'PORT':'3306',
    # 数据库
    'DB':'mysql',
    # 驱动
    'DRIVER':'pymysql',
    # 数据表名称
    'NAME':'flask3'
}

# 以下执行的函数正确的去拼接成了flask识别的配置格式, 结果为字符串,方便给App.py里面的app.config['SQLALCHEMY_DATABASE_URI']调用
SQLALCHEMY_DATABASE_URI = get_db_uri(DATABASE)

App.py配置代码如下:

from flask import Flask

from Stu.views import stu
from Grade.views import grade
from utils.functions import init_ext

from utils.setting import templates_dir, static_dir, SQLALCHEMY_DATABASE_URI


def create_app():


    app = Flask(__name__,
                template_folder=templates_dir,
                static_folder=static_dir)

    app.debug = True

    app.register_blueprint(blueprint=stu, url_prefix='/stu')
    app.register_blueprint(blueprint=grade, url_prefix='/grade')

    app.config['SQLALCHEMY_DATABASE_URI'] = SQLALCHEMY_DATABASE_URI
    #上面调用函数得到的结果: app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:123456789@localhost:3306/flask3'
    app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

    # 配置debugtoolbar必须填写
    app.config['SECRET_KEY'] = 'secret_key'

    # 第一种初始化方法
    # SQLAlchemy(app=app)

    # 第二种初始化方法, 此方法调用函数init_ext(app)同时对app进行了SQLAlchemy和debugtoolbar的初始化
    init_ext(app)

    # 最重要的操作都是对app进行初始化的, db=SQLALCHEMY()这个对象并没有被改变
    return app

manage.py项目文件配置如下:

from utils.App import create_app
from flask_script import Manager

# 此为项目启动文件, 越精简越好!
app = create_app()

manage = Manager(app=app)

if __name__ == '__main__':

    manage.run()

定义模型映射数据库:

Stu包下的models.py:

from utils.functions import db

class Student(db.Model):
    s_id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    s_name = db.Column(db.String(20), unique=True)
    s_age = db.Column(db.Integer, default=18)
    s_g = db.Column(db.Integer, db.ForeignKey('grade.g_id'),  nullable=True)  # 指定顺序不能混乱, 必须按照这种顺序进行参数匹配



    __tablename__ = 'student'

    def __init__(self, name, age):


        self.s_name = name
        self.s_age = age

sc = db.Table('sc',
              db.Column('s_id', db.Integer, db.ForeignKey('student.s_id'), primary_key=True),
              db.Column('c_id', db.Integer, db.ForeignKey('course.c_id'), primary_key=True)
              )

class Course(db.Model):

    c_id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    c_name = db.Column(db.String(10), unique=True)
    students = db.relationship('Student',
                               secondary=sc, #定义中间表
                               backref='course')

    __tablename__ = 'course'

    def __init__(self, name):
        self.c_name = name

Grade包下的models.py:

from datetime import datetime

from utils.functions import db

class Grade(db.Model):

    g_id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    g_name = db.Column(db.String(10), unique=True)
    g_desc = db.Column(db.String(100), default=None) # 或者nullable=True
    g_time = db.Column(db.DATE, default=datetime.now())
    students = db.relationship('Student', backref='grade', lazy=True)  # 参数依次表示:模型名称, 反向加载的连接, 懒加载

    __tablename__ = 'grade'

    def __init__(self, name, desc):

        self.g_name = name
        self.g_desc = desc

在Stu下的 StuMarshmallow.py 进行序列化操作!

from utils.functions import ma

# 序列化--->serialize
# 自定义序列化对象
class StuMarsh(ma.Schema):

    class Meta:
        # 在flask里面fields必须写!!
        fields = ['s_name', 's_age']

stumarsh = StuMarsh()

Stu包下的views.py:

import random

from flask import Blueprint, render_template, request, redirect, url_for

# sqlalchemy里面的and_, or_, not_方法, app都是经过SQLAchemy()进行初始化的, 所以这里面的方法都能够被使用!
from sqlalchemy import and_, or_, not_

from Stu.models import Student, Course
from utils.functions import db

from flask_restful import Resource
from utils.functions import api

from Stu.StuMarshmallow import stumarsh


stu = Blueprint('stu', __name__)    #初始化stu

@stu.route('/')
def index():
    return render_template('index.html')

# 创建数据表
@stu.route('/createdb/')
def create_db():
    db.create_all()
    return '创建数据表成功'

# 删除数据表
@stu.route('/dropdb/')
def drop_db():
    db.drop_all()
    return '删除数据表成功'

# 创建学生信息
@stu.route('/createstu/', methods=['GET', 'POST'])
def create_stu():

    if request.method == 'GET':

        return render_template('create_stu.html')

    elif request.method == 'POST':
        username = request.form.get('username')
        age = request.form.get('age')
        stu = Student(username, age) #创建学生对象
        db.session.add(stu) # 将学生对象加入数据库中 -->缓存中
        # 处理异常
        try:
            db.session.commit() # 提交到数据库 -->执行
            return '数据库操作成功'
        except:
            db.session.rollback() # 回滚数据  -->执行
            return '数据库操作失败, 数据已经回滚'

# 批量创建学生信息
@stu.route('/createstus/', methods=['GET', 'POST'])
def create_stus():

    if request.method == 'GET':

        return render_template('create_stus.html')

    elif request.method == 'POST':
        stus_list = []

        username1 = request.form.get('username1')
        age1 = request.form.get('age1')

        username2 = request.form.get('username2')
        age2 = request.form.get('age2')

        stu1 = Student(username1, age1)
        stu2 = Student(username2, age2)

        stus_list.append(stu1)
        stus_list.append(stu2)

        db.session.add_all(stus_list)  # 将列表里面的所有学生对象添加到缓存中 --> 缓存

        db.session.commit()  # 提交到数据库

        return '创建成功'

@stu.route('/createstubyrange/')
def create_random_stus():
    stus_list = []
    for i in range(20):
        stu = Student('小明%s' % random.randrange(1000), random.randrange(30))
        stus_list.append(stu)
    db.session.add_all(stus_list)
    db.session.commit()
    return '创建成功'



@stu.route('/selectstu/')
def select_stu():

    # 年龄小于16岁的学生的信息, 用逻辑运算符方法
    # stus = Student.query.filter(Student.s_age < 16)

    # lt le用法 小于, 小于等于
    # stus = Student.query.filter(Student.s_age.__lt__(16))
    # stus = Student.query.filter(Student.s_age.__le__(16))

    #gt ge 大于, 大于等于
    # stus = Student.query.filter(Student.s_age.__gt__(16))
    # stus = Student.query.filter(Student.s_age.__ge__(16))

    # 年龄在16, 1, 20, 34, 23, 32的学生, in_方法
    # stus = Student.query.filter(Student.s_age.in_([16, 1, 20, 34, 23, 32]))

    # 获取所以学生信息  用SQL语句
    # sql = 'select * from student;'
    # stus = db.session.execute(sql)

    # 按照id降序排列  对象.query.order_by  limit取前三个 offset为跳过几个信息开始
    # stus = Student.query.order_by('-s_id').limit(3)
    # stus = Student.query.order_by('-s_age').offset(1).limit(5)
    # stus = Student.query.order_by('-s_age').offset(2)

    # 获取id等于24的学生
    stus = Student.query.filter(Student.s_id==24) # -->返回对象的列表, 可以迭代
    # stus = Student.query.get(24)   # --> 返回具体的对象,不可迭代

    # 查询多个条件, and_(并且), or_(或者), not_(非,只能写一个条件)
    # stus = Student.query.filter(Student.s_age==18, Student.s_name=='小明')
    stus = Student.query.filter(and_(Student.s_age==18, Student.s_name=='小明'))
    stus = Student.query.filter(or_(Student.s_age==18, Student.s_name=='王羲之'))
    stus = Student.query.filter(not_(Student.s_age == 18), and_(Student.s_name=='王羲之'))

    return render_template('student_list.html', stus=stus)


@stu.route('/stupage/')
def stu_page():

    page = int(request.args.get('page', 1)) # 利用?page=2在域名上可以进行赋值
    per_page = int(request.args.get('per_page', 10))    # 每页默认10条
    print(page,per_page)

    paginate = Student.query.order_by('-s_id').paginate(page=page,per_page=per_page, error_out=False) # 分页器

    stus = paginate.items   # 获取当前分页数据
    return render_template('stupage.html', paginate=paginate, stus=stus)

@stu.route('/selectgradebystu/<int:id>/')
def select_grade_by_stu(id):
    stu = Student.query.get(id)
    grade = stu.grade

    return render_template('gradepage.html', stu=stu, grade=grade)

@stu.route('/addcourse/')
def add_course():

    courses = ['高等数学', '线性代数', '大学英语', '大学物理', 'Vfox', '毛概', '建筑设计']
    course_list = []

    for course in courses:
        cou = Course(course)
        course_list.append(cou)

    db.session.add_all(course_list)
    db.session.commit()

    return '添加课程成功'

@stu.route('/selectcourse/', methods=['GET', 'POST'])   # ---> manytomany 多对多
def stu_cou():
    if request.method == 'GET':
        stus = Student.query.all()
        cous = Course.query.all()
        return render_template('stu_cou.html', stus=stus, cous=cous)
    if request.method == 'POST':
        # 第一种添加方式
        student_id = request.form.get('student')
        course_ids = request.form.getlist('course')
        # sql = 'insert into sc values(%s, %s)' % (student_id, course_id)
        # db.session.execute(sql)
        # db.session.commit()

        # 第二种添加方式
        # stu = Student.query.get(student_id)
        # cou = Course.query.get(course_id)
        # stu.course.append(cou)   # 学生去查找对应的课程然后append需要添加的课程  相反也可以通过 cou去找对应的学生, 在点上对应的学生
        # db.session.add(stu)   # -->可要可不要的步骤
        # db.session.commit()

        # 第三种添加方式, 群奶
        stu = Student.query.get(student_id)
        for course_id in course_ids:
            cou = Course.query.get(course_id)
            stu.course.append(cou)
        db.session.commit()


        return '插入成功'

@stu.route('/allstu/')
def all_stu():

    stus = Student.query.all()

    return render_template('all_stu.html', stus=stus)

@stu.route('/stutocourse/<int:id>')
def stu_to_course(id):
    stu = Student.query.get(id)
    cous = stu.course
    return render_template('stutocourse.html', cous=cous, stu=stu)

@stu.route('/deletecoursebyid/<int:s_id>/<int:c_id>/')
def delete_course_by_id(s_id, c_id):
    stu = Student.query.get(s_id)
    cou = Course.query.get(c_id)

    cou.students.remove(stu)
    db.session.commit()

    return redirect(url_for('stu.all_stu'))


class HelloStudent(Resource):

    def get(self, id):
        stu = Student.query.get(id)
        # 一. 没有经过序列化的, 必须包装成字典才能够正常的去返回
        # data = {
        #     'name':stu.s_name,
        #     'age': stu.s_age,
        #
        # }
        # return {'data': data}

        # 二. 经过序列化的
        return stumarsh.jsonify(stu)

api.add_resource(HelloStudent, '/api/stu/<int:id>/')  # api接口访问的路由是在第二个参数, 通过这个路由去访问的返回的结果必须是json格式

Grade包下的views.py


from flask import Blueprint, render_template

from utils.functions import db
from Grade.models import Grade

grade = Blueprint('grade', __name__)

@grade.route('/')
def get_grade():

    return 'xxxx'

@grade.route('/createdb/')
def create_db():

    db.create_all()
    return '创建班级成功'

@grade.route('/creategrade/')
def create_grade():
    grades = []
    dict1 = {'Java':'Java最牛批', 'Python':'Python最可爱', 'Html5':'Html5妹子多'}

    for k,v in dict1.items():
        gra1 = Grade(k, v)
        grades.append(gra1)

    db.session.add_all(grades)
    db.session.commit()
    return '添加成功'

@grade.route('/selectstubygrade/<int:id>/')
def select_stu_by_grade(id):

    grade = Grade.query.get(id)
    stus = grade.students

    return render_template('grade_student.html',
                           stus=stus,
                           grade=grade)

更多内容,可关注作者的微信公众号:胖哥真不错。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值