当前位置:网站首页>[flask] official tutorial -part3: blog blueprint, project installability
[flask] official tutorial -part3: blog blueprint, project installability
2022-07-06 01:27:00 【Coriander Chrysanthemum】
Preface article :
The official tutorial (Tutorial)-part1: Project layout 、 Application settings 、 Define and access databases
The official tutorial (Tutorial)-part2: The blueprint - View 、 Templates 、 Static files
blog The blueprint
Next, we use the related technology of writing and verifying the blueprint model to write the blueprint of the blog . Blogs should list all posts , Allow login users to create posts , And allow the post author to edit or delete it .
When implementing each view , Please keep the development server running . When saving changes , Please try going to URL And test it .
The blueprint
Define the blueprint and register in the application factory . Use app.register_blueprint()
Import and register blueprints from the factory . Before returning to the application , Put the new code at the end of the factory function .
flaskr/__init__.py
def create_app():
app = ...
# existing code omitted
from . import blog
app.register_blueprint(blog.bp)
app.add_url_rule('/', endpoint='index')
return app
Different from the authentication blueprint , There is no blog blueprint url_prefix
. So the indexed view will be in /, Create views in /create
, And so on . The blog is Flaskr The main function of , So it makes sense that blog index will become the main index .
however , As defined below index The endpoint of the view will be blog.index. Some authentication views refer to common index endpoints . app.add_url_rule()
Set the endpoint name 'index'
And /
Link associated , In order to url_for('index')
or url_for('blog.index')
Can work , Generate the same /
URL.
In another application , You may give a blog blueprint url_prefix
And define a separate indexed view in the application factory , Be similar to hello View . that index
and blog.index
Endpoint and URL It will be different .
index page
The index will show all posts , The most recent is before . Use JOIN So that the author information in the user table can be used in the results .
flaskr/blog.py
@bp.route('/')
def index():
db = get_db()
posts = db.execute(
'SELECT p.id, title, body, created, author_id, username'
' FROM post p JOIN user u ON p.author_id = u.id'
' ORDER BY created DESC'
).fetchall()
return render_template('blog/index.html', posts=posts)
flaskr/templates/blog/index.html
{% extends 'base.html' %}
{% block header %}
<h1>{% block title %}Posts{% endblock %}</h1>
{% if g.user %}
<a class="action" href="{
{ url_for('blog.create') }}">New</a>
{% endif %}
{% endblock %}
{% block content %}
{% for post in posts %}
<article class="post">
<header>
<div>
<h1>{
{ post['title'] }}</h1>
<div class="about">by {
{ post['username'] }} on {
{ post['created'].strftime('%Y-%m-%d') }}</div>
</div>
{% if g.user['id'] == post['author_id'] %}
<a class="action" href="{
{ url_for('blog.update', id=post['id']) }}">Edit</a>
{% endif %}
</header>
<p class="body">{
{ post['body'] }}</p>
</article>
{% if not loop.last %}
<hr>
{% endif %}
{% endfor %}
{% endblock %}
When the user logs in , The title block adds a link to create the view . When the user is the author of the post , They will see the view pointing to the post update “ edit ” link .loop.last
yes Jinja for Special variables available in the loop . It is used to display a line after every post except the last one , To visually separate them .
Create a post
create How views work and auth register Same view . Or display the form , Either verify the published data and add the post to the database or display errors .
You wrote before login_required
Decorator for blog view . Users must log in to access these views , Otherwise they will be redirected to the login page .
flaskr/blog.py
@bp.route('/create', methods=('GET', 'POST'))
@login_required
def create():
if request.method == 'POST':
title = request.form['title']
body = request.form['body']
error = None
if not title:
error = 'Title is required.'
if error is not None:
flash(error)
else:
db = get_db()
db.execute(
'INSERT INTO post (title, body, author_id)'
' VALUES (?, ?, ?)',
(title, body, g.user['id'])
)
db.commit()
return redirect(url_for('blog.index'))
return render_template('blog/create.html')
flaskr/templates/blog/create.html
{% extends 'base.html' %}
{% block header %}
<h1>{% block title %}New Post{% endblock %}</h1>
{% endblock %}
{% block content %}
<form method="post">
<label for="title">Title</label>
<input name="title" id="title" value="{
{ request.form['title'] }}" required>
<label for="body">Body</label>
<textarea name="body" id="body">{
{ request.form['body'] }}</textarea>
<input type="submit" value="Save">
</form>
{% endblock %}
to update
Both updating and deleting views need to pass id Get the post and check whether the author matches the login user . To avoid duplicate code , You can write a function to get the post and call it from each view .
flaskr/blog.py
def get_post(id, check_author=True):
post = get_db().execute(
'SELECT p.id, title, body, created, author_id, username'
' FROM post p JOIN user u ON p.author_id = u.id'
' WHERE p.id = ?',
(id,)
).fetchone()
if post is None:
abort(404, f"Post id {
id} doesn't exist.")
if check_author and post['author_id'] != g.user['id']:
abort(403)
return post
abort()
Will trigger a return HTTP Special exception of status code . It needs an optional message to display the error , Otherwise, use the default message .404 Express “ Not found ”,403 Express “ prohibit ”. (401 Express “ unaccredited ”, But you redirect to the login page instead of returning to that status .)
Defined check_author
Parameters , So that this function can be used to get posts without checking the author . If you write a view to display a single post on the page , It will be useful , Users are not important , Because they didn't modify the post .
flaskr/blog.py
@bp.route('/<int:id>/update', methods=('GET', 'POST'))
@login_required
def update(id):
post = get_post(id)
if request.method == 'POST':
title = request.form['title']
body = request.form['body']
error = None
if not title:
error = 'Title is required.'
if error is not None:
flash(error)
else:
db = get_db()
db.execute(
'UPDATE post SET title = ?, body = ?'
' WHERE id = ?',
(title, body, id)
)
db.commit()
return redirect(url_for('blog.index'))
return render_template('blog/update.html', post=post)
Different from the view you are currently writing , The update function accepts a parameter id. This corresponds to <int:id>
. A real URL Look like /1/update. Flask Will capture 1, Make sure it's a int, And use it as id Parameter passing . If you don't specify int: But use <id>
, It will be a string . To generate the updated page URL, You need to url_for()
Pass on id, So that it knows what to fill in :url_for('blog.update', id=post['id'])
. This is also on the top index.html In file .
Creating and updating views look very similar . The main difference is that the update view uses a post Object and a UPDATE Query instead of a INSERT. Through some clever refactoring , You can use a view and template for these two operations , But for this tutorial , It will be clearer to separate them .
flaskr/templates/blog/update.html
{% extends 'base.html' %}
{% block header %}
<h1>{% block title %}Edit "{
{ post['title'] }}"{% endblock %}</h1>
{% endblock %}
{% block content %}
<form method="post">
<label for="title">Title</label>
<input name="title" id="title" value="{
{ request.form['title'] or post['title'] }}" required>
<label for="body">Body</label>
<textarea name="body" id="body">{
{ request.form['body'] or post['body'] }}</textarea>
<input type="submit" value="Save">
</form>
<hr>
<form action="{
{ url_for('blog.delete', id=post['id']) }}" method="post">
<input class="danger" type="submit" value="Delete" onclick="return confirm('Are you sure?');">
</form>
{% endblock %}
This template has two form. The first is to publish the edited data to the current page (/<id>/update)
. Another form contains only one button , And specify an operation attribute published to the delete view . This button uses some JavaScript Show a confirmation dialog before submitting .
Pattern { { request.form['title'] or post['title'] }}
Used to select the data displayed in the form . When the form has not been submitted , The original release data will appear , But if invalid form data is published , You want to display it so that the user can fix the error , Therefore use request.form Instead of .request Is another variable automatically available in the template .
Delete
Deleting a view does not have its own template , The delete button is update.html
Part of , And release to the /<id>/delete
URL. Because there is no template , It only handles POST Method , Then redirect to the indexed view .
flaskr/blog.py
@bp.route('/<int:id>/delete', methods=('POST',))
@login_required
def delete(id):
get_post(id)
db = get_db()
db.execute('DELETE FROM post WHERE id = ?', (id,))
db.commit()
return redirect(url_for('blog.index'))
Start the service test
Because the previous service was not shut down , And use the development mode , Then you can directly access .
After logging in, it has the following effects :
So let's click “New” You can create an article :
After clicking save , Just jump to the front page of the blog :
For this blog , We can choose “Edit”, Then go to the following page :
We can modify it , It can also be deleted . Later readers can try it by themselves .
The project can be installed
Making your project installable means that you can build a distribution file and install it in another environment , Just like you install in the project environment Flask equally . This makes deploying your project the same as installing any other library , So you use all the Standards Python Tools to manage all content .
The installation also brings others from the tutorial or as new Python Users may not have obvious benefits , Include :
- at present ,Python and Flask Learn how to use flaskr The package is just because you are running from the project directory . Installation means that you can import it no matter where you run it .
- You can manage the dependencies of a project just like any other package , therefore
pip install yourproject.whl
Will install them . - Testing tools can isolate your testing environment from your development environment .
Project description
setup.py
The file describes your project and the files that belong to it .
setup.py
from setuptools import find_packages, setup
setup(
name='flaskr',
version='1.0.0',
packages=find_packages(),
include_package_data=True,
zip_safe=False,
install_requires=[
'flask',
],
)
packages tell Python Which package directories to include ( And what they contain Python file ). find_packages()
These directories will be found automatically , So you don't have to enter them . To include other files , For example, static and template directories , Please set up include_package_data
. Python Need another one called MANIFEST.in
To explain what other data is .
MANIFEST.in
include flaskr/schema.sql
graft flaskr/static
graft flaskr/templates
global-exclude *.pyc
This tells Python Copy static and template directories and schema.sql Everything in the document , But exclude all bytecode files .
Project installation
Use pip Install your project in a virtual environment .
pip install -e .
This tells pip Find... In the current directory setup.py And install it in editable or development mode . Editable mode means that when you change local code , If you change the metadata about the project ( For example, its dependencies ), Then just reinstall .
You can observe that the project is now installed pip list.
up to now , There is no change in the way you run the project . FLASK_APP Still set to flaskr also flask run Still running the application , But you can call it from anywhere , Not just flask-tutorial Catalog
边栏推荐
- A picture to understand! Why did the school teach you coding but still not
- IP storage and query in MySQL
- 2022年广西自治区中职组“网络空间安全”赛题及赛题解析(超详细)
- [the most complete in the whole network] |mysql explain full interpretation
- 伦敦银走势中的假突破
- Recommended areas - ways to explore users' future interests
- 【Flask】响应、session与Message Flashing
- Code Review关注点
- FFT 学习笔记(自认为详细)
- 【全網最全】 |MySQL EXPLAIN 完全解讀
猜你喜欢
Basic operations of databases and tables ----- primary key constraints
Pbootcms plug-in automatically collects fake original free plug-ins
【SSRF-01】服务器端请求伪造漏洞原理及利用实例
3D视觉——4.手势识别(Gesture Recognition)入门——使用MediaPipe含单帧(Singel Frame)和实时视频(Real-Time Video)
XSS learning XSS lab problem solution
基于DVWA的文件上传漏洞测试
C web page open WinForm exe
Hcip---ipv6 experiment
DOM introduction
Folio.ink 免费、快速、易用的图片分享工具
随机推荐
500 lines of code to understand the principle of mecached cache client driver
c#网页打开winform exe
How does Huawei enable debug and how to make an image port
What is weak reference? What are the weak reference data types in ES6? What are weak references in JS?
Cookie concept, basic use, principle, details and Chinese transmission
Basic process and testing idea of interface automation
【详细】快速实现对象映射的几种方式
【Flask】静态文件与模板渲染
Nmap: network detection tool and security / port scanner
General operation method of spot Silver
一圖看懂!為什麼學校教了你Coding但還是不會的原因...
Superfluid_ HQ hacked analysis
Daily practice - February 13, 2022
Force buckle 1020 Number of enclaves
[技术发展-28]:信息通信网大全、新的技术形态、信息通信行业高质量发展概览
[understanding of opportunity-39]: Guiguzi - Chapter 5 flying clamp - warning 2: there are six types of praise. Be careful to enjoy praise as fish enjoy bait.
Vulhub vulnerability recurrence 74_ Wordpress
Cglib dynamic agent -- example / principle
ORA-00030
Unity | two ways to realize facial drive