增加书籍表
下面我们用flask_sqlalchemy提供的建表语句来通过类的形式创建表。
class Author(db.Model):
id = db.Column(db.Integer, primary_key=True, comment='作者主键ID')
name = db.Column(db.String(30), nullable=False, comment='作者姓名')
class Book(db.Model):
id = db.Column(db.Integer, primary_key=True, comment='书籍主键ID')
title = db.Column(db.String(30), nullable=False, comment='书籍标题')
author_id = db.Column(db.Integer, db.ForeignKey('author.id')) # 外键,关联作者表的主键ID
db.ForeignKey:定义此字段为外键,关联author表的主键ID字段。
修改所有作者模板
<!--all_authors.html文件-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>所有作者</title>
</head>
<body>
{% extends 'base.html' %}
{% block content %}
{% for author in authors %}
<p>{{ author.id }}、{{ author.name }} |
<a href="{{ url_for('edit_author', author_id=author.id) }}">编辑</a> |
<a href="{{ url_for('delete_author', author_id=author.id) }}">删除</a> |
<a href="{{ url_for('add_book', author_id=author.id) }}">添加{{ author.name }}的书籍</a> |
<a href="{{ url_for('author_books', author_id=author.id) }}">{{ author.name }}的书籍</a> |
</p>
{% endfor %}
{% for message in get_flashed_messages() %}
<span style="color:red">{{ message }}</span>
{% endfor %}
{% endblock content %}
</body>
</html>
添加书籍
# 添加书籍
@app.route('/add_book', methods=['GET', 'POST'])
def add_book():
author_id = request.args.get('author_id') # 首页要拿到作者id,因为我们要添加书籍到某个用户下面
print(author_id)
if request.method == 'POST':
title = request.form.get('title') # 从表单里面接收过来的
new_book = Book(title=title, author_id=author_id) # 要传递两个字段的数据
try:
db.session.add(new_book)
db.session.commit()
flash('添加书籍成功!')
except Exception as e:
flash('添加书籍不成功!')
return redirect(url_for('all_authors'))
return render_template('add_book.html')
<!--add_book.html-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>添加书籍</title>
</head>
<body>
{% extends 'base.html' %}
{% block content %}
<form action="" method="post">
书籍名称:<input type="text" name="title" value="">
<input type="submit" value="确认添加">
</form>
{% for message in get_flashed_messages() %}
<span style="color:red">{{ message }}</span>
{% endfor %}
{% endblock %}
</body>
</html>
作者书籍方法一
# 作者书籍 方法一
@app.route('/author_books')
def author_books():
author_id = request.args.get('author_id')
books = Book.query.filter(Book.author_id == author_id).all()
# filter当中 表.字段(以哪个字段为条件进行查询)== 传递的值
print(books)
return render_template('author_books.html', books=books)
<!--author_books.html文件-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>作者书籍</title>
</head>
<body>
{% extends 'base.html' %}
{% block content %}
<!--对应视图函数方法一-->
{% for book in books %}
<p>{{ book.title }}</p> <!--这里无法获取到作者数据,因为此页面只有书籍数据-->
{% endfor %}
{% endblock %}
</body>
</html>
作者书籍方法二
# 作者书籍 方法二
@app.route('/author_books')
def author_books():
# 先添加 many_books = db.relationship('Book', backref='one_book_author') 到author表
# many_books是虚拟字段,此虚拟字段相当于一个作者的所有书籍的列表,one_book_author字段相当于给book表使用的虚拟字段,代表了一本书籍的作者。
author_id = request.args.get('author_id') # 拿到作者ID
one_author = Author.query.get(author_id) # 通过作者ID取到作者对象
return render_template('author_books2.html', one_author=one_author)
<!--author_books2.html文件-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{ one_author.name }}作者书籍</title>
</head>
<body>
{% extends 'base.html' %}
{% block content %}
{% for book in one_author.many_books %} <!--通过作者对象拿到作者下面所有书籍,并进行遍历-->
<p>{{ book.id }}、{{ book.title }} |
<a href="{{ url_for('edit_book', book_id=book.id) }}">编辑{{ one_author.name }}书籍</a> |
<a href="{{ url_for('delete_book', book_id=book.id) }}">删除{{ one_author.name }}书籍</a> |
</p>
{% endfor %}
{% endblock %}
</body>
</html>
编辑书籍
# 编辑书籍
@app.route('/edit_book', methods=['GET', 'POST'])
def edit_book():
book_id = request.args.get('book_id')
one_book = Book.query.get(book_id) # 通过书籍id获取单个书籍的记录
if request.method == 'POST':
title = request.form.get('title') # 取到传递过来的书籍的标题
one_book.title = title # 将传递过来的书籍的标题赋值到现有记录上
db.session.add(one_book)
db.session.commit()
return redirect(url_for('author_books', author_id=one_book.author_id))
# 跳转到某一个作者的所有书籍下面,因为当前页面没有作者的数据,所以只能从单个书籍里面通过单本书籍的外键拿到作者的id
return render_template('edit_book.html', one_book=one_book)
<!--edit_book.html文件-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>编辑书籍</title>
</head>
<body>
{% extends 'base.html' %}
{% block content %}
<form action="" method="post">
书籍名称:<input type="text" name="title" value="{{ one_book.title }}">
<input type="submit" value="确认修改">
</form>
{% endblock content %}
</body>
</html>
删除单本书籍
# 删除单本书籍
@app.route('/delete_book')
def delete_book():
book_id = request.args.get('book_id')
one_book = Book.query.get(book_id)
db.session.delete(one_book)
db.session.commit()
return redirect(url_for('author_books', author_id=one_book.author_id))
批量删除多本书籍
<!--修改模板-->
<!--author_books3.html文件-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{ one_author.name }}作者书籍</title>
</head>
<body>
{% extends 'base.html' %}
{% block content %}
<form action="{{ url_for('delete_books') }}" method="post"> <!--注意提交的视图函数已经不是默认的了,还有方法-->
{% for book in one_author.many_books %} <!--通过作者对象拿到作者下面所有书籍,并进行遍历-->
<p>
<input type="checkbox" name="book_ids" value="{{ book.id }}"> <!--加复选框,name是多个复选框公用的,是一个列表 值就是当前书籍的id-->
{{ book.id }}、{{ book.title }} |
<a href="{{ url_for('edit_book', book_id=book.id) }}">编辑{{ one_author.name }}书籍</a> |
<a href="{{ url_for('delete_book', book_id=book.id) }}">删除{{ one_author.name }}书籍</a> |
</p>
{% endfor %}
<input type="submit" value="批量删除"> <!--提交按钮注意要在form表单中-->
</form>
{% endblock %}
</body>
</html>
# 批量删除多本书籍
@app.route('/delete_books', methods=['POST'])
def delete_books():
book_ids = request.form.getlist('book_ids') # 接收复选框参数的语法要注意
one_book = ''
for book_id in book_ids: # 遍历出单本书籍的id,再进行逐一删除即可
print(book_id)
print(type(book_id))
one_book = Book.query.get(int(book_id))
db.session.delete(one_book)
db.session.commit()
return redirect(url_for('author_books', author_id=one_book.author_id)) # 注意跳转要放到最下面,不要放到循环当中。
# 如果放到循环当中,那么就只删除一条就会跳转走了,也就是不会再继续删除了。
修改删除作者
上一讲,当我们只有一张表的时候,删除作者的时候不会有任何问题,可是现在我们有两张表了,而且书籍表有一个字段是外键,指向作者表,那么如果一个作者存在书籍记录在书籍表的话,删除作者的时候就会有问题。当我们没有配置 many_books = db.relationship('Book', backref='one_book_author')
这个关系的话,会提示删除不了。如果配置了的话,此作者可以删除,但是在书籍表中,此作者下面的书籍记录的author_id这个外键会置为null,这样显示是不合适的,会造成数据的错乱。不建议这样做,所以我们就要修改下删除作者的视图函数了,先遍历删除此作者下面的书籍,再删除此作者即可。
# 删除作者(先删除作者的书籍,后删除作者)
@app.route('/delete_author')
def delete_author():
author_id = request.args.get('author_id') # 跟编辑一样需要获取当前用户的id
one_author = Author.query.get(author_id) # 通过id获取当前记录(对象)
for book in one_author.many_books: # 通过many_books拿到此作者所有书籍,遍历删除
one_book = Book.query.get(book.id) # 通过单本书籍id获取单本书籍记录
try:
db.session.delete(one_book)
db.session.commit()
flash('删除书籍成功!')
except Exception as e:
flash('删除书籍不成功!')
try:
db.session.delete(one_author) # 删除作者记录(对象)
db.session.commit()
flash('删除作者成功!')
except Exception as e:
flash('删除作者不成功!')
return redirect(url_for('all_authors')) # 删除之后跳转到所有作者页面