python笔记(flask wtform metaclass SQLAlchemy)

出自博客园yuan先生

一、简单介绍flask中的wtforms

WTForms是一个支持多个web框架的form组件,主要用于对用户请求数据进行验证。

二、简单使用wtforms组件

  1. 用户登录
    在这里插入图片描述
    .py

    from  flask import Flask,render_template,request,redirect
    from  wtforms.fields import core
    from wtforms.fields import html5
    from wtforms.fields import simple
    from wtforms import Form
    from wtforms import validators
    from wtforms import widgets
    app = Flask(__name__,template_folder="templates")
    
    class Myvalidators(object):
        '''自定义验证规则'''
        def __init__(self,message):
            self.message = message
        def __call__(self, form, field):
            print(field.data,"用户输入的信息")
            if field.data == "haiyan":
                return None
            raise validators.ValidationError(self.message)
    
    class LoginForm(Form):
        '''Form'''
        name = simple.StringField(
            label="用户名",
            widget=widgets.TextInput(),
            validators=[
                Myvalidators(message="用户名必须是haiyan"),#也可以自定义正则
                validators.DataRequired(message="用户名不能为空"),
                validators.Length(max=8,min=3,message="用户名长度必须大于%(max)d且小于%(min)d")
            ],
            render_kw={"class":"form-control"}  #设置属性
        )
    
        pwd = simple.PasswordField(
            label="密码",
            validators=[
                validators.DataRequired(message="密码不能为空"),
                validators.Length(max=8,min=3,message="密码长度必须大于%(max)d且小于%(min)d"),
                validators.Regexp(regex="\d+",message="密码必须是数字"),
            ],
            widget=widgets.PasswordInput(),
            render_kw={"class":"form-control"}
        )
    
    
    
    @app.route('/login',methods=["GET","POST"])
    def login():
        if request.method =="GET":
            form = LoginForm()
            return render_template("login.html",form=form)
        else:
            form = LoginForm(formdata=request.form)
            if form.validate():
                print("用户提交的数据用过格式验证,值为:%s"%form.data)
                return "登录成功"
            else:
                print(form.errors,"错误信息")
            return render_template("login.html",form=form)
    
    
    if __name__ == '__main__':
        # app.__call__()
        app.run(debug=True)
    

    html

    <body>
    <form action="" method="post" novalidate>
        <p>{{ form.name.label }} {{ form.name }} {{ form.name.errors.0 }}</p>
        <p>{{ form.pwd.label }} {{ form.pwd }} {{ form.pwd.errors.0 }}</p>
        <input type="submit" value="提交">
        <!--用户名:<input type="text">-->
        <!--密码:<input type="password">-->
        <!--<input type="submit" value="提交">-->
    </form>
    </body>
    
  2. 用户注册
    在这里插入图片描述
    .py

    from flask import Flask,render_template,redirect,request
    from wtforms import Form
    from wtforms.fields import core
    from wtforms.fields import html5
    from wtforms.fields import simple
    from wtforms import validators
    from wtforms import widgets
    
    app = Flask(__name__,template_folder="templates")
    app.debug = True
    
    =======================simple===========================
    class RegisterForm(Form):
        name = simple.StringField(
            label="用户名",
            validators=[
                validators.DataRequired()
            ],
            widget=widgets.TextInput(),
            render_kw={"class":"form-control"},
            default="haiyan"
        )
        pwd = simple.PasswordField(
            label="密码",
            validators=[
                validators.DataRequired(message="密码不能为空")
            ]
        )
        pwd_confim = simple.PasswordField(
            label="重复密码",
            validators=[
                validators.DataRequired(message='重复密码不能为空.'),
                validators.EqualTo('pwd',message="两次密码不一致")
            ],
            widget=widgets.PasswordInput(),
            render_kw={'class': 'form-control'}
        )
    
      ========================html5============================
        email = html5.EmailField(  #注意这里用的是html5.EmailField
            label='邮箱',
            validators=[
                validators.DataRequired(message='邮箱不能为空.'),
                validators.Email(message='邮箱格式错误')
            ],
            widget=widgets.TextInput(input_type='email'),
            render_kw={'class': 'form-control'}
        )
    
      ===================以下是用core来调用的=======================
        gender = core.RadioField(
            label="性别",
            choices=(
                (1,"男"),
                (1,"女"),
            ),
            coerce=int  #限制是int类型的
        )
        city = core.SelectField(
            label="城市",
            choices=(
                ("bj","北京"),
                ("sh","上海"),
            )
        )
        hobby = core.SelectMultipleField(
            label='爱好',
            choices=(
                (1, '篮球'),
                (2, '足球'),
            ),
            coerce=int
        )
        favor = core.SelectMultipleField(
            label="喜好",
            choices=(
                (1, '篮球'),
                (2, '足球'),
            ),
            widget = widgets.ListWidget(prefix_label=False),
            option_widget = widgets.CheckboxInput(),
            coerce = int,
            default = [1, 2]
        )
    
        def __init__(self,*args,**kwargs):  #这里的self是一个RegisterForm对象
            '''重写__init__方法'''
            super(RegisterForm,self).__init__(*args, **kwargs)  #继承父类的init方法
            self.favor.choices =((1, '篮球'), (2, '足球'), (3, '羽毛球'))  #吧RegisterForm这个类里面的favor重新赋值
    
        def validate_pwd_confim(self,field,):
            '''
            自定义pwd_config字段规则,例:与pwd字段是否一致
            :param field:
            :return:
            '''
            # 最开始初始化时,self.data中已经有所有的值
            if field.data != self.data['pwd']:
                # raise validators.ValidationError("密码不一致") # 继续后续验证
                raise validators.StopValidation("密码不一致")  # 不再继续后续验证
    
    @app.route('/register',methods=["GET","POST"])
    def register():
        if request.method=="GET":
            form = RegisterForm(data={'gender': 1})  #默认是1,
            return render_template("register.html",form=form)
        else:
            form = RegisterForm(formdata=request.form)
            if form.validate():  #判断是否验证成功
                print('用户提交数据通过格式验证,提交的值为:', form.data)  #所有的正确信息
            else:
                print(form.errors)  #所有的错误信息
            return render_template('register.html', form=form)
    
    if __name__ == '__main__':
        app.run()
    

    html

    <body>
    <h1>用户注册</h1>
    <form method="post" novalidate style="padding:0  50px">
        {% for item in form %}
        <p>{{item.label}}: {{item}} {{item.errors[0] }}</p>
        {% endfor %}
        <input type="submit" value="提交">
    </form>
    </body>
    
  3. meta

    from flask import Flask, render_template, request, redirect, session
    from wtforms import Form
    from wtforms.csrf.core import CSRF
    from wtforms.fields import core
    from wtforms.fields import html5
    from wtforms.fields import simple
    from wtforms import validators
    from wtforms import widgets
    from hashlib import md5
    
    app = Flask(__name__, template_folder='templates')
    app.debug = True
    
    
    class MyCSRF(CSRF):
        """
        Generate a CSRF token based on the user's IP. I am probably not very
        secure, so don't use me.
        """
    
        def setup_form(self, form):
            self.csrf_context = form.meta.csrf_context()
            self.csrf_secret = form.meta.csrf_secret
            return super(MyCSRF, self).setup_form(form)
    
        def generate_csrf_token(self, csrf_token):
            gid = self.csrf_secret + self.csrf_context
            token = md5(gid.encode('utf-8')).hexdigest()
            return token
    
        def validate_csrf_token(self, form, field):
            print(field.data, field.current_token)
            if field.data != field.current_token:
                raise ValueError('Invalid CSRF')
    
    
    class TestForm(Form):
        name = html5.EmailField(label='用户名')
        pwd = simple.StringField(label='密码')
    
        class Meta:
            # -- CSRF
            # 是否自动生成CSRF标签
            csrf = True
            # 生成CSRF标签name
            csrf_field_name = 'csrf_token'
    
            # 自动生成标签的值,加密用的csrf_secret
            csrf_secret = 'xxxxxx'
            # 自动生成标签的值,加密用的csrf_context
            csrf_context = lambda x: request.url
            # 生成和比较csrf标签
            csrf_class = MyCSRF
    
            # -- i18n
            # 是否支持本地化
            # locales = False
            locales = ('zh', 'en')
            # 是否对本地化进行缓存
            cache_translations = True
            # 保存本地化缓存信息的字段
            translations_cache = {}
    
    
    @app.route('/index/', methods=['GET', 'POST'])
    def index():
        if request.method == 'GET':
            form = TestForm()
        else:
            form = TestForm(formdata=request.form)
            if form.validate():
                print(form)
        return render_template('index.html', form=form)
    
    
    if __name__ == '__main__':
        app.run()
    
  4. 钩子函数

    class LoginForm(Form):
    	name = simple.StringField(
    		validators=[
    			validators.DataRequired(message='用户名不能为空.'),
    		],
    		widget=widgets.TextInput(),
    		render_kw={'placeholder':'请输入用户名'}
    	)
    	pwd = simple.PasswordField(
    		validators=[
    			validators.DataRequired(message='密码不能为空.'),
    
    		],
    		render_kw={'placeholder':'请输入密码'}
    	)
    
    	def validate_name(self, field):
    		"""
    		自定义name字段规则
    		:param field:
    		:return:
    		"""
    		# 最开始初始化时,self.data中已经有所有的值
    		print('钩子函数获取的值',field.data)
    		if not field.data.startswith('old'):
    			raise validators.ValidationError("用户名必须以old开头") # 继续后续验证
    			# raise validators.StopValidation("用户名必须以old开头")  # 不再继续后续验证
    
  5. metaclass

    实现步骤:
    	- 创建类时,先执行type的__init__。
    			- 类的实例化时,执行type的__call__,__call__方法的的返回值就是实例化的对象。
    				__call__内部调用:
    					- 类.__new__,创建对象
    					- 类.__init__,对象的初始化
    
    
    class MyType(type):
        def __init__(self,*args,**kwargs):
            super(MyType,self).__init__(*args,**kwargs)
    
        def __call__(cls, *args, **kwargs):
            obj = cls.__new__(cls)
    
            cls.__init__(obj,*args, **kwargs)
    
            return obj
    
    class Foo(object,metaclass=MyType):
        a1 = 123
        def __init__(self):
            pass
    
        def __new__(cls, *args, **kwargs):
            return object.__new__(cls)
    
        def func(self):
            return 666
    
    # Foo是类
    # Foo是MyType的一个对象
    
    obj = Foo()
    
    注释:
    1、创建类时先执行type的__init__方法
    2、当一个类实例化时执行type的__call__方法,__call__方法的返回值就是实例化的对象
    3、__call__的内部调用类的__new__方法创建对象
    

二、SQLAlchemy

  1. 基本操作

    models.py

    from sqlalchemy.ext.declarative import declarative_base
    from sqlalchemy import Column
    from sqlalchemy import Integer,String,Text,Date,DateTime
    from sqlalchemy import create_engine
    
    
    Base = declarative_base()
    
    class Depart(Base):
        __tablename__ = 'depart'
        id = Column(Integer, primary_key=True)
        title = Column(String(32), index=True, nullable=False)
    
    class Users(Base):
        __tablename__ = 'users'
    
        id = Column(Integer, primary_key=True)
        name = Column(String(32), index=True, nullable=False)
        depart_id = Column(Integer,ForeignKey("depart.id"))
    
        dp = relationship("Depart", backref='pers')
    
    class Student(Base):
        __tablename__ = 'student'
        id = Column(Integer, primary_key=True)
        name = Column(String(32), index=True, nullable=False)
    
    course_list = relationship('Course', secondary='student2course', backref='student_list')
    
    class Course(Base):
        __tablename__ = 'course'
        id = Column(Integer, primary_key=True)
        title = Column(String(32), index=True, nullable=False)
    
    class Student2Course(Base):
        __tablename__ = 'student2course'
        id = Column(Integer, primary_key=True, autoincrement=True)
        student_id = Column(Integer, ForeignKey('student.id'))
        course_id = Column(Integer, ForeignKey('course.id'))
    
    __table_args__ = (
        UniqueConstraint('student_id', 'course_id', name='uix_stu_cou'), # 联合唯一索引
        # Index('ix_id_name', 'name', 'extra'),                          # 联合索引
    )
    
    
    def create_all():
        engine = create_engine(
            "mysql+pymysql://root:123456@127.0.0.1:3306/s9day120?charset=utf8",
            max_overflow=0,  # 超过连接池大小外最多创建的连接
            pool_size=5,  # 连接池大小
            pool_timeout=30,  # 池中没有线程最多等待的时间,否则报错
            pool_recycle=-1  # 多久之后对线程池中的线程进行一次连接的回收(重置)
        )
    
    Base.metadata.create_all(engine)
    
    def drop_all():
        engine = create_engine(
            "mysql+pymysql://root:123456@127.0.0.1:3306/s9day120?charset=utf8",
            max_overflow=0,  # 超过连接池大小外最多创建的连接
            pool_size=5,  # 连接池大小
            pool_timeout=30,  # 池中没有线程最多等待的时间,否则报错
            pool_recycle=-1  # 多久之后对线程池中的线程进行一次连接的回收(重置)
        )
        Base.metadata.drop_all(engine)
    
    if __name__ == '__main__':
       # drop_all()
        create_all()
    

    views.py

    from sqlalchemy.orm import sessionmaker
    from sqlalchemy import create_engine
    from models import Users
    
    engine = create_engine(
            "mysql+pymysql://root:123456@127.0.0.1:3306/s9day120?charset=utf8",
            max_overflow=0,  # 超过连接池大小外最多创建的连接
            pool_size=5,  # 连接池大小
            pool_timeout=30,  # 池中没有线程最多等待的时间,否则报错
            pool_recycle=-1  # 多久之后对线程池中的线程进行一次连接的回收(重置)
        )
    SessionFactory = sessionmaker(bind=engine)
    
    # 根据Users类对users表进行增删改查
    session = SessionFactory()
    
    # ############################## 基本增删改查 ###############################
    # 1. 增加
    # obj = Users(name='alex')
    # session.add(obj)
    # session.commit()
    
    # session.add_all([
    #         Users(name='小东北'),
    #         Users(name='龙泰')
    # ])
    # session.commit()
    
    # 2. 查
    # result = session.query(Users).all()
    # for row in result:
    #         print(row.id,row.name)
    
    # result = session.query(Users).filter(Users.id >= 2)
    # for row in result:
    #         print(row.id,row.name)
    
    # result = session.query(Users).filter(Users.id >= 2).first()
    # print(result)
    
    # 3.删
    # session.query(Users).filter(Users.id >= 2).delete()
    # session.commit()
    
    # 4.改
    # session.query(Users).filter(Users.id == 4).update({Users.name:'东北'})
    # session.query(Users).filter(Users.id == 4).update({'name':'小东北'})
    # session.query(Users).filter(Users.id == 4).update({'name':Users.name+"DSB"},synchronize_session=False)
    # session.commit()
    
    # ############################## 其他常用 ###############################
    # 1. 指定列
    # select id,name as cname from users;
    # result = session.query(Users.id,Users.name.label('cname')).all()
    # for item in result:
    #         print(item[0],item.id,item.cname)
    # 2. 默认条件and
    # session.query(Users).filter(Users.id > 1, Users.name == 'eric').all()
    # 3. between
    # session.query(Users).filter(Users.id.between(1, 3), Users.name == 'eric').all()
    # 4. in
    # session.query(Users).filter(Users.id.in_([1,3,4])).all()
    # session.query(Users).filter(~Users.id.in_([1,3,4])).all()
    # 5. 子查询
    # session.query(Users).filter(Users.id.in_(session.query(Users.id).filter(Users.name=='eric'))).all()
    # 6. and 和 or
    # from sqlalchemy import and_, or_
    # session.query(Users).filter(Users.id > 3, Users.name == 'eric').all()
    # session.query(Users).filter(and_(Users.id > 3, Users.name == 'eric')).all()
    # session.query(Users).filter(or_(Users.id < 2, Users.name == 'eric')).all()
    # session.query(Users).filter(
    #     or_(
    #         Users.id < 2,
    #         and_(Users.name == 'eric', Users.id > 3),
    #         Users.extra != ""
    #     )).all()
    
    # 7. filter_by
    # session.query(Users).filter_by(name='alex').all()
    
    # 8. 通配符
    # ret = session.query(Users).filter(Users.name.like('e%')).all()
    # ret = session.query(Users).filter(~Users.name.like('e%')).all()
    
    # 9. 切片
    # result = session.query(Users)[1:2]
    
    # 10.排序
    # ret = session.query(Users).order_by(Users.name.desc()).all()
    # ret = session.query(Users).order_by(Users.name.desc(), Users.id.asc()).all()
    
    # 11. group by
    from sqlalchemy.sql import func
    
    # ret = session.query(
    #         Users.depart_id,
    #         func.count(Users.id),
    # ).group_by(Users.depart_id).all()
    # for item in ret:
    #         print(item)
    #
    # from sqlalchemy.sql import func
    #
    # ret = session.query(
    #         Users.depart_id,
    #         func.count(Users.id),
    # ).group_by(Users.depart_id).having(func.count(Users.id) >= 2).all()
    # for item in ret:
    #         print(item)
    
    # 12.union 和 union all
    """
    select id,name from users
    UNION
    select id,name from users;
    """
    # q1 = session.query(Users.name).filter(Users.id > 2)
    # q2 = session.query(Favor.caption).filter(Favor.nid < 2)
    # ret = q1.union(q2).all()
    #
    # q1 = session.query(Users.name).filter(Users.id > 2)
    # q2 = session.query(Favor.caption).filter(Favor.nid < 2)
    # ret = q1.union_all(q2).all()
    
  2. relation:

    # 3. relation字段:查询所有用户+所属部门名称
    # ret = session.query(Users).all()
    # for row in ret:
    #     print(row.id,row.name,row.depart_id,row.dp.title)
    
    # 4. relation字段:查询销售部所有的人员
    # obj = session.query(Depart).filter(Depart.title == '销售').first()
    # for row in obj.pers:
    #     print(row.id,row.name,obj.title)
    
    # 5. 创建一个名称叫:IT部门,再在该部门中添加一个员工:田硕
    # 方式一:
    # d1 = Depart(title='IT')
    # session.add(d1)
    # session.commit()
    #
    # u1 = Users(name='田硕',depart_id=d1.id)
    # session.add(u1)
    # session.commit()
    
    # 方式二:
    # u1 = Users(name='田硕',dp=Depart(title='IT'))
    # session.add(u1)
    # session.commit()
    
    # 6. 创建一个名称叫:王者荣耀,再在该部门中添加一个员工:龚林峰/长好梦/王爷们
    # d1 = Depart(title='王者荣耀')
    # d1.pers = [Users(name='龚林峰'),Users(name='长好梦'),Users(name='王爷们'),]
    # session.add(d1)
    # session.commit()
    
  3. Manytomany:

    # 1. 录入数据
    # session.add_all([
    #     Student(name='先用'),
    #     Student(name='佳俊'),
    #     Course(title='生物'),
    #     Course(title='体育'),
    # ])
    # session.commit()
    
    # session.add_all([
    #     Student2Course(student_id=2,course_id=1)
    # ])
    # session.commit()
    
    # 2. 三张表关联
    # ret = session.query(Student2Course.id,Student.name,Course.title).join(Student,Student2Course.student_id==Student.id,isouter=True).join(Course,Student2Course.course_id==Course.id,isouter=True).order_by(Student2Course.id.asc())
    # for row in ret:
    #     print(row)
    # 3. “先用”选的所有课
    # ret = session.query(Student2Course.id,Student.name,Course.title).join(Student,Student2Course.student_id==Student.id,isouter=True).join(Course,Student2Course.course_id==Course.id,isouter=True).filter(Student.name=='先用').order_by(Student2Course.id.asc()).all()
    # print(ret)
    
    # obj = session.query(Student).filter(Student.name=='先用').first()
    # for item in obj.course_list:
    #     print(item.title)
    
    # 4. 选了“生物”的所有人
    # obj = session.query(Course).filter(Course.title=='生物').first()
    # for item in obj.student_list:
    #     print(item.name)
    
    # 5. 创建一个课程,创建2学生,两个学生选新创建的课程。
    # obj = Course(title='英语')
    # obj.student_list = [Student(name='为名'),Student(name='广宗')]
    #
    # session.add(obj)
    # session.commit()
    
    
    session.close()
    
  4. 链接池连接两种方式:

    方式一:
    	from sqlalchemy.orm import sessionmaker
    	from sqlalchemy import create_engine
    	from models import Student,Course,Student2Course
    
    	engine = create_engine(
    			"mysql+pymysql://root:123456@127.0.0.1:3306/s9day120?charset=utf8",
    			max_overflow=0,  # 超过连接池大小外最多创建的连接
    			pool_size=5,  # 连接池大小
    			pool_timeout=30,  # 池中没有线程最多等待的时间,否则报错
    			pool_recycle=-1  # 多久之后对线程池中的线程进行一次连接的回收(重置)
    		)
    	SessionFactory = sessionmaker(bind=engine)
    
    	def task():
    		# 去连接池中获取一个连接
    		session = SessionFactory()
    
    		ret = session.query(Student).all()
    
    		# 将连接交还给连接池
    		session.close()
    
    
    	from threading import Thread
    
    	for i in range(20):
    		t = Thread(target=task)
    		t.start()
    
    	方式二:(推荐,基于Threading.local实现)
    		from sqlalchemy.orm import sessionmaker
    		from sqlalchemy import create_engine
    		from sqlalchemy.orm import scoped_session
    		from models import Student,Course,Student2Course
    
    		engine = create_engine(
    				"mysql+pymysql://root:123456@127.0.0.1:3306/s9day120?charset=utf8",
    				max_overflow=0,  # 超过连接池大小外最多创建的连接
    				pool_size=5,  # 连接池大小
    				pool_timeout=30,  # 池中没有线程最多等待的时间,否则报错
    				pool_recycle=-1  # 多久之后对线程池中的线程进行一次连接的回收(重置)
    			)
    		SessionFactory = sessionmaker(bind=engine)
    		session = scoped_session(SessionFactory)
    
    
    		def task():
    			ret = session.query(Student).all()
    			# 将连接交还给连接池
    			session.remove()
    
    
    		from threading import Thread
    
    		for i in range(20):
    			t = Thread(target=task)
    			t.start()
    
  5. 执行原生SQL

    	from sqlalchemy.orm import sessionmaker
    	from sqlalchemy import create_engine
    	from sqlalchemy.orm import scoped_session
    	from models import Student,Course,Student2Course
    
    	engine = create_engine(
    			"mysql+pymysql://root:123456@127.0.0.1:3306/s9day120?charset=utf8",
    			max_overflow=0,  # 超过连接池大小外最多创建的连接
    			pool_size=5,  # 连接池大小
    			pool_timeout=30,  # 池中没有线程最多等待的时间,否则报错
    			pool_recycle=-1  # 多久之后对线程池中的线程进行一次连接的回收(重置)
    		)
    	SessionFactory = sessionmaker(bind=engine)
    	session = scoped_session(SessionFactory)
    
    
    	def task():
    		""""""
    		# 方式一:
    		"""
    		# 查询
    		# cursor = session.execute('select * from users')
    		# result = cursor.fetchall()
    
    		# 添加
    		cursor = session.execute('INSERT INTO users(name) VALUES(:value)', params={"value": 'wupeiqi'})
    		session.commit()
    		print(cursor.lastrowid)
    		"""
    		# 方式二:
    		"""
    		# conn = engine.raw_connection()
    		# cursor = conn.cursor()
    		# cursor.execute(
    		#     "select * from t1"
    		# )
    		# result = cursor.fetchall()
    		# cursor.close()
    		# conn.close()
    		"""
    
    		# 将连接交还给连接池
    		session.remove()
    
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值