flask_十二、模板视图渲染+一对多关系简述
模板视图渲染+一对多关系简述
一、模板视图渲染
1.1在template下新建new_note.html
{% extends 'base.html'%} {% from 'macros.html' import form_field %} {% block content %} <h2>New Note</h2>> <form method="post"> {{ form.csrf_token }} {{ form_field(form.body,rows=5,cols=50)}} {{ form.submit }} </form> {% endblock %}
1.2在template下新建index.html
{% extends 'base.html'%} {% block content %} <h1>Notebook</h1> <a href="{{ url_for ('new_note')}}">New Note</a> <h4>{{ notes|length }} notes:</h4> {% for note in notes %} <div class="note"> <p>{{ note.body}}</p> <a class="btn" href="{{ url_for('edit_note',note_id=note.id) }}">Edit</a> <form method="post" action="{{ url_for('delete_note',note_id=note.id) }}"> {{ form_delete.csrf_token }} {{ form_delete.submit(class='btn') }} </form> </div> {% endfor %} {% endblock %}
1.3在template下新增edit_note.html
{% extends 'base.html'%} {% from 'macros.html' import form_field %} {% block title %}Edit Note{% endblock %} {% block content %} <h2>Edit Note</h2>> <form method="post"> {{ form.csrf_token}} {{ form_field(form.body,rows=5,cols=50) }} {{form.submit}}<br> </form> {% endblock %}
1.4说明
1、index模板的渲染
2、点击new note按钮访问的url是什么?(/new)请求的方法是get还是post(get)
3、请求到flask之后,触发的视图函数是什么(new_note)
1)在new_note视图函数里,form是否做了实例化(是)
是否传入了request.form(是)
2) 表单数据是否为空(是),是否通过了表单验证(否)
——if form.validate_on_submit()
3) 视图函数处理的结果是渲染了哪个模板(new_note.html),到哪个页面?new_note.html
4) New_note页面填入表单数据后,处罚的请求方式是啥(post),页面请求啥(/new/)
到哪个视图函数下处理(new_note),是否表单数据验证通过(是),视图函数的结果是渲染的哪个页面(index),数据是怎么处理的(实例化一个note数据,存到note表里)
1.5更新app.py
# encoding=utf-8 from flask import Flask,render_template,flash,url_for,redirect,request from flask_sqlalchemy import SQLAlchemy from flask_wtf import FlaskForm from wtforms import TextAreaField,SubmitField from wtforms.validators import DataRequired app = Flask(__name__) import os app.secret_key = os.getenv('SECRET_KEY','secret string') app.config['SQLALCHEMY_DATABASE_URI'] = os.getenv('DATABASE_URL','sqlite:///' + os.path.join(app.root_path,'data.db')) app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False db = SQLAlchemy(app) # 该方法跟模板上下文函数类似,返回的是一个字典,将对象以key和value @app.shell_context_processor def make_shell_content(): return dict(db=db,Note=Note,Author=Author,Article=Article,Writer=Writer,Book=Book) class Author(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(70), unique=True) articles = db.relationship('Article') #定义关联函数,关联属性,一对多的一,即为标量,出发侧,参数是关联的模型类 def __repr__(self): return '<Author id: %r, name: %r>' % (self.id, 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')) #定义外键,集合属性就是多 # 指定显示内容,否则默认显示<表名 主键id> def __repr__(self): return '<Article id: %r, title: %r, body: %r, author_id: %r>' % (self.id, self.title,self.body,self.author_id) class Writer(db.Model): id = db.Column(db.Integer,primary_key = True) name = db.Column(db.String(70),unique = True) # back_populats定义双向关系 # back_populats参数的值需要设为关系另一侧的关系属性名 books = db.relationship('Book', back_populates='writer') def __repr__(self): return '<Writer id: %r, name: %r>' %(self.id,self.name) class Book(db.Model): id = db.Column(db.Integer,primary_key = True) title = db.Column(db.String(50), primary_key=True) writer_id = db.Column(db.Integer, db.ForeignKey('writer.id')) writer = db.relationship('Writer', back_populates='books') def __repr__(self): return '<Book id: %r, title: %r, writer_id:%r>' %(self.id,self.title,self.writer_id) # 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 = relationship('song',backref=backref('singer',uselist=False)) def __repr__(self): return '<Singer id: %r, name: %r>' %(self.id,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 id: %r, name: %r>' %(self.id,self.name) # class Citizen(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(70), unique=True) city_id = db.Column(db.Integer, db.ForeignKey('city.id')) # back_population的值为另一侧的关系属性名 # city = db.relationship('City') # relationship函数的第一个参数是另一侧的模型名(类型) city = db.relationship('City', back_populates='citizen') def __repr__(self): return '<Citizen id: %r, name: %r, city_id: %r>' %(self.id,self.name,self.city_id) # class City(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(30), unique=True) # back_population的值为另一侧的关系属性名 # relationship函数的第一个参数是另一侧的模型名(类型) citizen = db.relationship('Citizen', back_populates='city') def __repr__(self): return '<City id: %r, name: %r>' %(self.id,self.name) # # 101行 class Country(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(30), unique=True) capital = db.relationship('Capital',uselist=False) # 109hang def __repr__(self): return '<Country id: %r, name: %r>' %(self.id,self.name) # class Capital(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(30), unique=True) country_id = db.Column(db.Integer, db.ForeignKey('country.id')) country = db.relationship('Country') def __repr__(self): return '<Capital id: %r, name: %r, country_id: %r>' %(self.id,self.name,self.country_id) # 多对多关系 association_table = db.Table('association', db.Column('student_id',db.Integer,db.ForeignKey('student.id')), db.Column('teacher_id',db.Integer,db.ForeignKey('teacher.id')), ) # 125行代码 class Student(db.Model): id = db.Column(db.Integer,primary_key=True) name = db.Column(db.String(70),unique = True) grade = db.Column(db.String(20)) teachers = db.relationship('Teacher', secondary = association_table, back_populates = 'students') # collection def __repr__(self): return '<Student id: %r, name: %r, grade: %r>' %(self.id, self.name,self.grade) # 135行行号 class Teacher(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(70),unique = True) office = db.Column(db.String(20)) # black_populates,定义双向关系 # back_populations参数的值需要设为关系另一侧的关系属性名 students = db.relationship('Student', secondary = association_table, back_populates = 'teachers') # collection def __repr__(self): return '<Teacher id: %r,name: %r,office: %r>' %(self.id,self.name,self.office) #定义Note模型类,映射到表note class Note(db.Model): id = db.Column(db.Integer,primary_key = True) body = db.Column(db.Text) def __repr__(self): # %r 是用repr()方法处理对象,返回类型本身,而不进行类型转化 return '<Note id: %r, body: %r>' % (self.id,self.body) class NewNoteForm(FlaskForm): body = TextAreaField('Body',validators=[DataRequired()]) # 跳转新页面的body框 submit = SubmitField('Save') class EditNoteForm(FlaskForm): body = TextAreaField('Body',validators=[DataRequired()]) submit = SubmitField('Update') class DeleteNoteForm(FlaskForm): submit = SubmitField('Delete') import click @app.cli.command() def initdb(): db.create_all() click.echo('Initialized database') @app.route('/new/',methods=['GET','POST']) def new_note(): print("request.form in new_note: %s" % request.form) form = NewNoteForm() print("form:" , form) print("form.validate_on_submit(): " ,form.validate_on_submit()) # if request.method == 'POST' and form validate(): if form.validate_on_submit(): print("pass") try: print(Note.query.all()) except: print("initdb...") initDB() body = form.body.data note = Note(body = body) db.session.add(note) db.session.commit() flash("your note is saved") return redirect(url_for('index')) return render_template('new_note.html',form=form) @app.route('/edit/<int:note_id>',methods=['GET','POST']) def edit_note(note_id): print("request.form in edit_note: %s" % request.form) form = EditNoteForm() print("form.body: %s" % form.body) print("form.body.data: %s" % form.body.data) note = Note.query.get(note_id) print("note.body: %s" % note.body) if form.validate_on_submit(): # 判断表单提交的数据是否不为空+是post请求 print("validated") note.body = form.body.data # 赋值新值 print("note.body in validate: %s" % note.body) db.session.commit() flash("your note is edited") return redirect(url_for('index')) form.body.data = note.body # return render_template('edit_note.html',form=form) @app.route('/delete/,<int:note_id>',methods=['POST']) def delete_note(note_id): form = DeleteNoteForm() if form.validate_on_submit(): note = Note.query.get(note_id) #获取对应记录 db.session.delete(note) #删除记录 db.session.commit() # 提交修改 flash('Your note is deleted') else: abort(400) return redirect(url_for('index')) @app.route('/index/') def index(): db.create_all() form = NewNoteForm form_delete = DeleteNoteForm() notes = Note.query.all() return render_template('index.html',notes=notes,form=form,form_delete=form_delete) if __name__ == "__main__": print(app.config) app.run(debug=True)
1.5.1说明:
@app.shell_context_processor装饰器的作用,自动返回所有类对象
@app.shell_context_processor def make_shell_content(): return dict(db=db,Note=Note,Author=Author,Article=Article,Writer=Writer,Book=Book)
1.6操作查看
启动flask
.在pipenv shell启动之后
再次执行flask shell

>>> db <SQLAlchemy engine=sqlite:///E:\FlaskTest\data.db> >>> Note <class 'app.Note'> >>> Author <class 'app.Author'> >>>
二、一对多(单向关系)
只能一对多,去查

2.1声明表的绝对路径

db
db.create_all()
之后,成功新建了定义的以类名做表名的数据

2.2数据可作实例化
>>> a1 <Author id: None, name: 'xxx'> >>> >>> b1 = Article(title = 'yyy') >>> b1 <Article id: None, title: 'yyy', body: None, author_id: None> >>> >>> db.session.add_all([a1,b1]) # 多个数据的提交 >>> db.session.commit() >>>
>>> a1 <Author id: 1, name: 'xxx'> >>> b1 <Article id: 1, title: 'yyy', body: None, author_id: None> >>>
# 把b1加到a1的关系里面 >>> >>> a1.articles [] >>> a1.articles.append(b1) >>> a1.articles [<Article id: 1, title: 'yyy', body: None, author_id: None>] >>>
# commit提交之后的效果(append) >>> a1.articles #查看a1的articles属性 [<Article id: 1, title: 'yyy', body: None, author_id: None>] >>> db.session.commit() >>> a1.articles [<Article id: 1, title: 'yyy', body: None, author_id: 1>] >>>
# 再次新增数据(指定外键) >>> b2 = Article(title = 'qwerty') >>> b2.author_id = 1 >>> a1.articles [<Article id: 1, title: 'yyy', body: None, author_id: 1>] >>> db.session.add(b2) >>> db.session.commit() >>> a1.articles [<Article id: 1, title: 'yyy', body: None, author_id: 1>, <Article id: 2, titl e: 'qwerty', body: None, author_id: 1>] >>>
# 查找出id=3的数据 >>> b3 = Article(title = 'sdfgh') >>> db.session.add(b3) >>> db.session.commit() >>> b3 <Article id: 3, title: 'sdfgh', body: None, author_id: None> >>> >>> st = Article.query.get(3) >>> st <Article id: 3, title: 'sdfgh', body: None, author_id: None>
# 新增了一条数据 >>> a1.articles [<Article id: 1, title: 'yyy', body: None, author_id: 1>, <Article id: 2, titl e: 'qwerty', body: None, author_id: 1>] >>> a1.articles.append(b3) >>> a1.articles [<Article id: 1, title: 'yyy', body: None, author_id: 1>, <Article id: 2, titl e: 'qwerty', body: None, author_id: 1>, <Article id: 3, title: 'sdfgh', body: None, author_id: None>] >>>
通过切片取值 >>> a1.articles = a1.articles[0:2] >>> a1.articles [<Article id: 1, title: 'yyy', body: None, author_id: 1>, <Article id: 2, titl e: 'qwerty', body: None, author_id: 1>] >>>
#删除关联关系的这1整条数据 a1.articles.remove(b1)
db.sesson.rollback() a1.articles #数据又还原回来了


三、一对多的双向关系


浙公网安备 33010602011771号