Flask Framework
synopsis
Features:
- Microframe, indirectly, gives developers great scalability
- Flask and the corresponding plugins are well written and a pleasure to use.
- Development is very efficient, for example, using SQLAlchemy's ORM to manipulate databases saves developers a lot of time writing sql.
file address
-
Chinese Documentation (/docs/flask/)
-
English Documentation (/docs/1.0/)
Flask itself is the equivalent of a kernel, and almost all other features use extensions (mail extensions)Flask-Mail
, User AuthenticationFlask-Login
, databasesFlask-SQLAIchemy
) all need to be implemented with third-party plugins.
Extended List
- Flask-SQLaIchemy: Manipulating Databases
- Flask-script: inserting scripts
- Flask-migrate: Managing the Migration Database
- Flask-Session: Session Storage Method Specification
- Flask-WTF: Forms
- Flask-Mail: Mail
- Flask-Bable: provides internationalization and localization support, translation
- Flask-Login: Authenticate User Status
- Flask-OpenID: Authentication
- Flask-RESTful: Tools for Developing REST APIs
- Flask-Bootstrap: integrated front-end Twitter Bootstrap framework
- Flask-Moment: Localizing Date and Time
- Flask-Admin: A Simple and Extensible Framework for Managing Interfaces
The first Flask program
Installing Flask
pip install flask
# Import Flask classes from flask package
from flask import Flask
# Create a Flask object
app = Flask(__name__)
#@: is a decorator
#@('/') is to map the / in the url to hello_world.
Set a view function on top
# When you visit the / directory of my website in the future, it will execute the function
hello_world function, and then return the return value of this function to the browser.
browser
@('/')
def hello_world(): return 'ShangXueTang'
return 'ShangXueTang'
#Start the web service
if __name__ == '__main__'.
# Default to port 5000
() #(port=8000)
start up a run
python
Running through objects
When running the program, you can specify the ip address of the host on which to run, the port
(host='0.0.0.0',port=5000)
parameter interpretation
host
- Host IP address, can not pass
- Default localhost
port
- Port number, can not pass
- Default 5000
Debug mode with configuration parameter loading
mileage
- Can be hot loaded
- Error messages can be displayed on the console
# Introducing the flask application
from flask import Flask
# Create the object
app = Flask(__name__)
# Routing address
@('/')
def index(): # return
# return means return data to the browser
return 'world '
if __name__ == '__main__'.
# The default port is 5000
(debug=True)
Enable debug mode
-
Passing parameters at runtime
(debug=True)
-
Configuration through parameters
= True
()
By modifying the configuration parameters
(DEBUG = True)
['DEBUG'] = True
()
Loading via mapping
.from_mapping({'DEBUG':True})
()
Setting the config via the configuration object
class Config:
DEBUG = True
.from_object(config)
()
Setting config via configuration file
DEBUG = True
.from_pyfile('')
.from_json('')
via the environment variable
DEBUG = True
.from_envvar('DEBUG')
Mapping of URLs to functions (dynamic routing)
URL path parameters
For example, there is a request for access to the interface address /users/11001, where 11001 is actually a specific request parameter, indicating that information is being requested for user number 11001.
@('/users/<user_id>')
def user_info(user_id):
print(type(user_id))
return 'hello user{}'.format(user_id)
Where , the angle brackets are fixed and the syntax is , variable The default data type is string.
If you need to specify the type, you need to write converter:variable, where converter is the name of the type, there can be the following kinds of
- string: If no specific data type is specified, then the string data type is used by default.
- The int:data type can only pass the int type.
- float: The data type can only be passed as float.
- The path: datatype is somewhat similar to string in that it can take arbitrary strings, but path can take paths, i.e. it can contain slashes.
- The uuid:data type can only accept strings that match a uuid. The uuid is a universe-unique string that can be used as the primary key of a table.
- The any: datatype can specify multiple paths in a single url. For example:
Matching the above example to data in integers can be used as follows.
@('/users/<int:user_id>')
def user_info(user_id):
print(type(user_id))
return f'Acquiring ID {user_id} user information'
@('/users/<int(min=1):user_id>')
def user_info(user_id):
print(type(user_id))
return f'hello user {user_id}'
Attention:
If the data does not match the set type, Not Found is returned.
Customizable changers
- Create a converter class that holds the regular expression that matches yes
from import BaseConverter
class MobileConverter(BaseConverter).
""" cell phone number format """
regex = r'1[3-9]\d{9}'
# Note that the regex name is fixed
- Inform Flask apps about customized converters
app = Flask(__name__)
# Add the customized converter to the converter dictionary and specify that the converter is used with the name: mobile
if __name__ == '__main__'.
# Add the custom converter to the converter dictionary and specify that the converter uses the name: mobile
app.url_map.converters['mobile'] = MobileConverter
- Define the use of converters where they are used
requesting
Query parameter acquisition
# Get request parameters
@('/')
def index(): uname = ('uname')
uname = ('uname')
pwd = ('pwd')
pwd2 = ('pwd')
return '{}:{}'.format(uname,pwd)
request body parameters
# Receive form parameters
@('/', methods=['POST'])
def index2():
uname = ('uname')
pwd = ('pwd')
age = ('age')
return f"Hello! {uname} == {pwd} =={age}"
Uploading files
# Uploading files
@('/upload', methods=['POST'])
def upload():
f = ['pic']
# Get filename
fname =
# with open('./', 'wb') as new_file:
# new_file.write(())
('./')
return 'Uploaded successfully'
Other parameters
@('/args')
def args():
cookies = ('uid')
headers = ('Content_Type')
url =
method =
return f'Uploaded successfully!! {cookies} =={headers} =={url} == {method}'
url_for function
According to the function, get the corresponding url, url_for function can realize this function
take note of
The url_for function can take one or more arguments, and accepts the function name as its first argument.
If other parameters are present, they are appended to the URL as query parameters.
@('/post/list/<page>/')
def my_list(page):
return 'my list'
@('/')
def hello_world():
return url_for('my_list',page=2,num=8)
# return "/post/list/2?num=8"
Reasons to use the url_for function
- In the future, if you change the url but not the function name corresponding to that URL, you won't have to go around replacing URLs
- The url_for() function escapes some special characters and unicode strings, something that url_for does automatically for us.
@('/')
def hello_world(): return url_for('login', next='/')
return url_for('login', next='/')
# /login/?next=/
# The /'s are automatically encoded, so you don't need to handle them manually.
# url=/login/?next=%2F
finesse
When defining a url, always remember to add a slash at the end
- If you don't add the slash, then when you access the url in the browser, if you add the slash at the end, then you won't be able to access it. This is not a good user experience.
- Search engines will treat the unslashed and slashed url as two different urls, while in fact both the slashed and unslashed url are the same url, then it will give the search engine to create a misunderstanding. If you add a slash, there will be no slash.
responsive
Response_Redirect
-
Permanent redirection
The status code of http is 301, which is mostly used when the old URL is discarded to go to a new URL to ensure the user's access.
-
Temporary redirection
The status code for http is 302, indicating a temporary jump of the page
For example: accessing a URL that requires permissions should redirect to the login page if the user is not logged in
Redirection in flask
redirect is through redirect(location,code=302) this function to achieve, location indicates the need to redirect to the URL, should be used with the url_for() function previously mentioned, code indicates the use of which redirect, the default is 302 that is, a temporary redirect, can be modified to 301 to achieve permanent redirection
from flask import
Flask,request,url_for,redirect
app = Flask(__name__)
@('/')
def hello_world():
return 'Hello World!'
@('/login/')
def login():
return 'This is the login page'
#falskMedium Redirection
@('/profile/')
def proflie():
if ('name'):
return 'Personal Center Page'
else:
# return redirect(url_for('login'))
return
redirect(url_for('login'),code=302)
if __name__ == '__main__':
(debug=True)
Response_Response Content
Returns a string
from flask import redirectd
@('/return_str')
def return_str():
return "How are you?,juvenile"
Return json
from flask import jsonify
['JSON_AS_ASCII'] = False
@('/return_json1')
def return_json1():
json_dict = {
"msg_int": 10,
"msg_str": "How are you?,juvenile"
}
return jsonify(json_dict)
@('/return_json2')
def return_json2():
json_dict = {
"msg_int": 10,
"msg_str": "How are you?,juvenile"
}
return json_dict
tuple approach
A tuple may be returned, which must contain at least one item consisting of (response, status), (response, headers), or (response, status, headers). The value of status overrides the status code, and headers is a list or dictionary of additional header values.
The status value overrides the status code, and headers can be a list or dictionary for additional message header values.
@('/demo1')
def demo1().
# return 'Status code is 666', 666
# return 'Status code is 666', 666.
[('itbaizhan', 'Python')]
return 'Status code is 666', 666, {'itbaizhan'.
'Python'}
Response_Custom_Response
Creating a response
from flask import Response
@('/return_str')
def return_str():
return Response("How are you?,juvenile")
make_response method
@('/demo2')
def demo2():
resp = make_response('make responsetest (machinery etc)')
['itbaizhan'] = 'Python'
= '404 not found'
return resp
(architecture) formwork
Template
T in MVT Design Pattern , Template
M is Model, the same function as M in MVC, responsible for interacting with the database for data processing.
V is spelled View, which has the same function as C in MVC, receiving requests, performing business processing, and returning answers.
The full spelling of T is Template, which has the same function as V in MVC and is responsible for encapsulating the html to be returned.
Use of templates
In Flask, the companion template is Jinja2, the author of Jinja2 is also the author of Flask. This template is very powerful and executes efficiently.
Steps to use:
- Creating Templates
- in application
peer catalog
Create a template folder undertemplates
The file name and folder name are written in a fixed way. - exist
templates
folder, createappliance
Folders with the same name. Example, Book - exist
appliance
Created in a folder of the same nameWeb templates
Documentation. Example.
- in application
- Setting the template lookup path
- Template Processing Data
from flask import Flask, render_template
app = Flask(__name__,render_template('templates'))
# Default usetemplates
# If you want to modify the catalog of the template,Can be settemplate_folderparameters
@('/')
def index():
return render_template('index_03.html')
if __name__ == '__main__':
(debug=True)
Template_Passing_Parameters
in usingrender_template
When rendering a template, you can pass keyword parameters (named parameters).
from flask import Flask,render_template
app = Flask(__name__)
@('/')
def hello_world():
return
render_template('',uname='sxt')
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"> <title>S.T.F.A.S.
<title>SXT</title>.
</head>.
<body>
Data rendered from the template
<br>
{{ uname}}
</body>
</html>
tip
If you have too many parameter entries, then you can put all of them into a dictionary, the
Then when passing this dictionary parameter, use two asterisks to break up the dictionary into keyword parameters (also called named parameters)
@('/')
def hello_world():
context = {
'uname': 'momo',
'age': 18,
'country': 'china',
'childrens': {
'name': 'mjz',
'height': '62cm'
}
}
return
render_template('',**context)
Access is: {{}}
or{{childrens['name']}}
Templates use the url_for function
draw attention to sth.
To use a function in a template, you need to add 2 {{}} to the left and right sides of the function
Example: {{ url_for(func) }}
@('/accounts/login/<name>/')
def login(name).
print(name)
return 'Located by URL_FOR!!!'
<a href="{{url_for('login',p1='abc',p2='ddd',name='Shangxue') }}">login</a>
take note of
Both path and query parameters can be passed directly.
Filter Introduction
In the template, the filter is equivalent to a function that passes the current variable into the filter, then the filter returns the corresponding value according to its function, and then renders the result into the page.
@('/')
def hello_world():
return render_template('',postion=-1)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"> <title>S.T.F.A.S.
<title>SXT</title>.
</head>.
<body>.
<h3>Basic use of filters</h3> </h3>
<p> Absolute value of position as [no filter used]: {{ postion}}</p>
<p> Absolute value of position is [use filter]: {{postion|abs}}</p>
</body>
</html>
Jinja templates come with filters
The filter is passed through the pipe symbol|
used, e.g. { name|length }} will return the length of name.
Filter is equivalent to a function, pass the current variable into the filter, then the filter according to its own function, and then return the corresponding value, after which the results will be rendered to the page.
There are a number of filters built into Jinja2
/en/3./templates/#filters
defalut filter
<body>
<h1> default filter</h1>
Nickname data before filtering is: {{nick_name}}<br>
The nickname data after filtering is: {{nick_name | default('user1',boolean=true)}}<br>
The filtered nickname data is: {{nick_name or 'user2'}}
<br>
</body>
escape character
<body>
<h1> escape character filter </h1>
<! -- The template does escape characters by default -->.
The data before escaping is: {{ info | safe }} <! -- Unescaped: does not convert special characters to <-like data -->
{% autoescape true %} <! -- false means no more escaping special characters / true escapes special characters <--> {% autoescape true %} <!
{{info }} <! -- escape: converts special characters to <similar data -->
{% endautoescape %}
</body>
Other filters
<body>
<h1> other filters</h1>
Absolute values: {{ -6 | abs }}<br>
Decimal: {{ 6 | float }}<br>
String: {{ 6 | string }}<br>
Formatting: {{'%s--%s' | format('me','you')}}<br>
length: {{'I'm a nine, you're a three, except for you, or you're a you'|length}}<br>
Last: {{'I'm nine, you're three, except you, or you' |last}}<br>
First: {{'I'm nine, you're three, except you, or you're you'|first}}<br>
Count: {{'I'm nine, you're three, except you, or you' |wordcount }}<br>
Replace: {{'===I'm nine, you're three, except you, or you ====' |replace('I'm nine, you're three, except you, or you','Take,this unlimited limit black card and swipe it any way you want')}}
</body>.
tip
The jinja2 template has auto-escaping turned on globally by default.
- safe filter: disables automatic escaping of a string.
- escape filter: escapes a particular string
- autoescape tag, which turns off or on auto-escaping for the code blocks it contains.
- {% autoescape true/false %} Code Block
Customized filters
If the filter is called from within the template, the value of the variable is passed as the first argument to the filter function.The return value of the function is then used as the return value of this filter.A decorator needs to be used: @app.template_filter('filter name')
Custom Data Replacement Filters
For example, replace all the "I'm a nine and you're a three, except you're still you" in the news with "You don't have to be nice, you don't need to be nice, you can be nice.I like it.
# Set the template to autoload mode
['TEMPLATES_AUTO_RELOAD']=True
@app.template_filter('cut')
def cut(value).
value=("I'm a nine and you're a three, except you're still you",'You don't have to be good, I like it')
return value
<p> Using custom filters: {{news content value|cut}}</p>
Customized time filters
For example, the time interval between the operation posting a news item and the present time.
# Requirement: Manipulate the time interval between posting a news item and the present time.
@app.template_filter('handle_time')
def handle_time(time).
"""
time is the time interval from the present.
1. if the time interval is less than 1 minute or less, then "just now" is displayed. 2.
2. if the time interval is greater than 1 minute and less than 1 hour, then "xx minutes ago". 3.
3. if the time interval is greater than 1 hour and less than 24 hours, then "xx hours ago". 4.
4. if it's more than 24 hours and less than 30 days old, then "xx days ago".
5. otherwise it shows the specific time 2030/10/2016:15
"""
if isinstance(time, datetime):
now = ()
timestamp = (now - time).total_seconds()
if timestamp < 60.
return "just now"
elif timestamp >= 60 and timestamp < 60 * 60: minutes = timestamp / 60: now = (now - time).
minutes = timestamp / 60
return "%s minutes ago" % int(minutes)
elif timestamp >= 60 * 60 and timestamp < 60 * 60 * 24: hours = timestamp / (60 * 60 * 24:)
hours = timestamp / (60 * 60)
return '%s hours ago' % int(hours)
elif timestamp >= 60 * 60 * 24 and timestamp < 60 * 60 * 24 * 30: days = timestamp / (60 * 60 * 24 * 30)
days = timestamp / (60 * 60 * 24)
return "%s days ago" % int(days)
else.
return ('%Y/%m/%d %H:%M')
else: return time
return time
(Other knowledge of logical grammar not organized)
Static files
Static files: css files js files image files and other files
The url_for function is used to load static files. Then the first argument is static and the second is a keyword argument filename='path'.
grammatical
{{ url_for("static",filename='xxx') }}
take note of
Path lookup, to use the current project's static directory as the root directory
view
add_url_rule with
-
add_url_rule
add_url_rule(rule,endpoint=None,view_func=None)
: This method is used to add a mapping of the url to the view function.If not filled in
endpoint
If it is not, then the default will be to use theview_func
given name asendpoint
. In the future, when using theurl_for
It depends on whether or not the mapping is passed theendpoint
parameter, if passed, then it should be used with theendpoint
specified string, if it is not passed then theview_func
The name.def my_list(): return "I'm the listing page." app.add_url_rule('/list/',endpoint='sxt',view_func=my_list)
-
Anatomy of an app_route
This decorator underlying, in fact, also uses the
add_url_rule
to implement the url to function mapping of thefrom flask import Flask,url_for app = Flask(__name__) @('/',endpoint='index') def index(). print(url_for('show')) print(url_for('index')) return "Hello" def show_me(). return "This introductory message!!!" # endpoint If endpoint is not set, url_for writes the name of the function, if it is set, it writes the value of the endpoint app.add_url_rule('/show_me',view_func=show_me,endpoint='show') # @ The bottom line is that add_url_rule is used if __name__ == '__main__'. (debug=True)
class view
The benefit of class views is that they support inheritance, but class views can't be written in the same way as function views, which still need to be passed through the
app.add_url_rule(url_rule,view_func)
to register
Steps for using the standard class view
-
Must be inherited from
-
must be realized
dispatch_request
method, which will be executed when future requests come inThe return value of this method is the equivalent of the previous view function. It must also return
Response
Or an object of a subclass, or a string, or a tuple. -
must pass
app.add_url_rule(rule,endpoint,view_func)
to do the url to view mapping.view_func
This parameter, which requires the use of the class view under theas_view
Class method class conversion: ListView.as_view('list'). -
If you specify the
endpoint
Then, when using theurl_for
The reversal would have to be done using theendpoint
The value specified. If you don't specifyendpoint
Then you can use theas_view(view name)
The name of the view specified in to be inverted.from flask import Flask,url_for from import View app= Flask(__name__) @('/') def index(): # print(url_for('mylist')) print(url_for('my')) return 'Hello' class ListView(View): def dispatch_request(self): return 'Returns aListcontent!!' # app.add_url_rule('/list',view_func=ListView.as_view('mylist')) app.add_url_rule('/list',endpoint='my',view_func=ListView.as_view('mylist')) # For testing with app.test_request_context(): print(url_for('my')) if __name__ =='__main__': (debug=True)
decorator
A python decorator is a function that is used to extend the functionality of an original function. The special feature of this function is that its return value is also a function.
- existview functioncustom decorator, then the custom decorator must be placed in the
below, otherwise this decorator will not do any good
Defining Decorators
def login_required(func):
@wraps(func)
def wrapper(*arg,**kwargs):
uname = ('uname')
pwd = ('pwd')
if uname == 'zs' and pwd == '123':
(f'{uname}:Login Successful')
return func(*arg,**kwargs)
else:
(f'{uname}:Try to log in,But it didn't work.')
return 'Please log in first'
return wrapper
Using Decorators
@('/settings/')
@login_requierd
def settings(): return 'This is the settings screen'.
return 'This is the settings screen'
- existclass viewUsing a decorator in a class view requires overriding one of the class attributes of the class view
decorators
This class property is either a list or a tuple, which holds all of the decorators
class ProfileView():
decorators = [login_requierd]
def dispatch_request(self):
return 'This is the personal center screen'
app.add_url_rule('/profile/',view_func=ProfileView.as_view('profile'))
Blueprint
It can be understood as a container object that stores a set of view methods with the following characteristics:
- An application with multiple Blueprints
- It is possible to place a BlueprintRegister to any unusedThe URLs of the following are for example "/user", "/goods", and "/goods".
- Blueprint can stand alone with its own templates, static files, or other common operations, and it is not necessary to implement the application's views and functions.
- When an application is initialized, it should register the Blueprints that need to be used.
take note of
Blueprint is not a complete application, it cannot run independently of the application, but must be registered to an application
Usage
-
Creating a Blueprint Object
user_bp=Blueprint('user',__name__)
-
On this blueprint object
@user_bp.route('/') def user_profile(): return 'user_profile'
-
Register this blueprint object with the application object
app.register_blueprint(user_bp)
Single file blueprints
It is possible to create blueprints and define views in a single file.
import logging
from import Blueprint
from flask import Flask
app = Flask(__name__)
(level=)
@('/')
def index():
('Output.Hello!!')
return 'Hello'
user = Blueprint('user', __name__)
@('/user')
def index():
return 'User Templates'
app.register_blueprint(user)
if __name__ =='__main__':
(debug=True)
Specify blueprint url prefix
app.register_blueprint(user_bp,url_prefix='/user')
app.register_blueprint(goods_bp,url_prefix='/goods')
Catalog structure of the blueprint
Based on functional modules
For a blueprint that is intended to contain multiple files, it is common to create the blueprint object in the Python package'sinit.py file
--------- project # Project directory
|------ # startup files
|------ user # user blueprint
| |--- __init__.py # Create blueprint objects here
| |---
| |--- ...
||--- __init__.py # Create blueprint objects here
| |--- __init__.py
||--- ...
|...
Based on the technology module
--------- project # Project directory
|------ # startup files
|------ view # user blueprints
| |--- # Create blueprint objects here
| |--- # Create blueprint object here
| |--- # Create blueprint object here | |--- # Create blueprint object here
||--- ...
|...
Example.
#
from flask import Flask
import logging
app = Flask(__name__)
(level=)
@('/')
def index():
('Output.Hello!!')
return 'Hello'
from user import user
app.register_blueprint(user)
if __name__ =='__main__':
(debug=True)
# __init__.py
from import Blueprint
user = Blueprint('user', __name__)
from user import view
#
from user import user
@('/user')
def index():
return 'User Templates'
Template files in blueprints
Finding the rules
- If there is a corresponding template file in the templates folder in the project, it is used directly.
- If there is no corresponding template file in the templates folder in the project, then look for it in the path specified when defining the blueprint.
- And the path specified in the blueprint can be a relative path, relative to the directory where this blueprint file is currently located
Since this blueprint file is in user/, then it goes to the user_page folder under the folder blueprints to find the template file.
Mini-Summary:
General: blueprint files are looked up with templates as the root directory when looking for template files
user_bp = Blueprint('user',__name__,url_prefix='/user',template_folder='user_page')
Flask Advanced Section
Cookie
Flask Setting Cookies
Setting a cookie is set on the response object
The object has aset_cookie method, which allows you to set the cookie information.
from flask import Flask, make_response
from flask import request
app = Flask(__name__)
@('/cookie')
def set_cookie():
resp = make_response('set cookie ok')
resp.set_cookie('uname', 'itbaizhan')
return resp
# ferret outcookie
@('/get_cookie')
def get_cookie():
resp = ('uname')
return resp
# removingcookie
@('/delete_cookie')
def delete_cookie():
response = make_response('helloworld')
response.delete_cookie('uname')
return response
Cookie expiration time
- Default expiration time: If no expiration time is shown, the cookie will expire after the browser is closed.
- max_age: in seconds, how many seconds from now the cookie will expire.
- expires: of datetime type. This time needs to be set to Greenwich Mean Time, which is automatically +8 hours relative to Beijing Time.
- If max_age and expires are both set, then max_age is the standard at this point.
from flask import Flask,Response
app = Flask(__name__)
@('/')
def index():
return 'Hello!!'
@('/create_cookie/defualt/')
def create_cookie1():
resp = Response('By default,set upcookievalidity period')
# 如果没有set upvalidity period,The default will be when the browser is closed,have sb do sthcookieexpire (as in expiration date)
resp.set_cookie('uname','sxt')
return resp
@('/create_cookie/max_age/')
def create_cookie2():
resp = Response('pass (a bill or inspection etc)max_age,set upcookievalidity period')
# max_age以秒为单位set upcookie的validity period
age = 60*60*2
resp.set_cookie('uname','itbaizhan',max_age=age)
return resp
from datetime import datetime
@('/create_cookie/expires/')
def create_cookie3():
resp = Response('pass (a bill or inspection etc)expires,set upcookievalidity period')
# expires Take the specified time as thecookie的validity period
# 16+8 == 24
tmp_time = datetime(2021, 11,11,hour=18,minute=0,second=0)
resp.set_cookie('uname','python',expires=tmp_time)
return resp
from datetime import timedelta
@('/create_cookie/expires2/')
def create_cookie4():
resp = Response('pass (a bill or inspection etc)expires,set upcookievalidity period')
# expires Take the specified time as thecookie的validity period
tmp_time = () +
timedelta(days=2)
resp.set_cookie('uname','python_sql',expires=tmp_time)
return resp
@('/create_cookie/exp_max/')
def create_cookie5():
resp = Response('pass (a bill or inspection etc)expirestogether withmax_age,set upcookievalidity period')
# expires together withmax_age同时set up了,will be based onmax_ageserve as the norm
tmp_time = () + timedelta(days=2)
resp.set_cookie('uname','python_sql',expires=tmp_time,max_age = 60*60*2)
return resp
if __name__ == '__main__':
(debug=True)
Session
Using Session in flask
Required settingsSECRET_KEY
class DefaultConfig(object).
SECRET_KEY = 'fih9fh9eh9gh2'
.from_object(DefaultConfig)
# Or just set
app.secret_key = 'xihwidfw9efw'
Settings, Modifications
from flask import session
@('/set_session/')
def set_session():
session['username'] = 'itbaizhan'
return 'set session ok'
retrieve
@('/get_session/')
def get_session():
username = ('username')
return 'get session username{}'.format(username)
removing
@('/del_session/')
def delete_session().
# Delete the session with the specified key
# ('uname')
# Delete all the keys in the session [delete all].
()
return 'Deleted successfully'
Flask sets the expiration date of the session
If the session expiration date is not set. Then the default is that it expires when the browser is closed.
If set = True, then it will expire after 31 days by default.
- =True
- Can be set
['PERMANENT_SESSION_LIFETIME'] = timedelta(hour=2)
Expires in two hours.
from flask import Flask,session
from datetime import timedelta
app = Flask(__name__)
app.secret_key = 'sdfdfdsfsss'
['PERMANENT_SESSION_LIFETIME'] = timedelta(days=2)
@('/')
def index().
return 'Hello!!!
@('/set_session/')
def set_session().
# Set session persistence, default is 31 days.
= True
session['uname'] = '10001'
return 'Set a session's information'
@('/get_session/')
def get_session():
# If the server is down, the session expiration date will still be the previous system save date.
# If secret_key is set to a fixed value, a server reboot will not affect the session validity.
# If the secret_key is not set to a fixed value, then all sessions set by the server will expire.
return ('uname')
if __name__ == '__main__'.
(debug=True)
Local objects
Demand:
- To achieve the concurrency effect, we start a process for each request that comes in, which is obviously not reasonable, and then we can use threading
- Then the data in the threads are not isolated from each other, there is the problem of data insecurity when modifying the data
In Flask, something like a request object is actually bound to aObject on.
This way, even if it is the same object, then it is isolated across multiple threads. A similar object is the session object.
from import Local
#flask=werkzeug + sqlalchemy + jinja2
ThreadLocal variables
Python provides the ThreadLocal variable, which is itself a global variable, but each thread can use it to store its own private data, which is also invisible to other threads.
from threading import Thread,local
local =local()
= 'User-specific request objects'
class MyThread(Thread):
def run(self):
= 'sxt'
print('subthread:',)
mythread = MyThread()
()
()
print('main thread:',)
from import Local
local = Local()
= 'User-specific request object'
class MyThread(Thread).
def run(self).
= 'sxt'
print('Subthread:',)
mythread = MyThread()
()
()
print('Main thread:',)
summarize
As long as the properties bound to the "local" or "local" object are isolated per thread, then it is called a ThreadLocal object, or a 'ThreadLocal' variable.
Flask_app context
take note of
In view functions, you don't have to worry about the application context. Because the view function is executed by accessing the url, in this case, Flask automatically pushes the application context onto the stack for us.
If you want to perform a related operation outside of a view function, the
Example: Get the current app name, then you have to manually push into the app context
First approach: easy-to-understand writing style
from flask import Flask,current_app
app = Flask(__name__)
#app(textual) context
app_context = app.app_context()
app_context.push()
print(current_app.name)
@('/')
def hello_world():
print(current_app.name) #Get the name of the application
return 'Hello World!'
if __name__ == '__main__':
(debug=True)
The second way: using the with statement
from flask import Flask,current_app
app = Flask(__name__)
#app(textual) context
#Write it another way.
with app.app_context():
print(current_app.name)
@('/')
def hello_world():
print(current_app.name) #Get the name of the application
return 'Hello World!'
if __name__ == '__main__':
(debug=True)
Flask_request context in detail
take note of
In view functions, you don't have to worry about the request context. Because the view function to be executed, then certainly through the way to access the url to execute, then in this case, Flask underlying has automatically help us to push the application context and the request context into the appropriate stack.
take note of
If you want to perform a related operation outside of a view function, the
For example, if you reverse the url, then you have to push in the request context manually:
Underlying code execution description:
- Pushing a request context onto the stack will first determine if there is an application context
- If not then the application context is pushed onto the stack first
- Then push the request context onto the stack
from flask import Flask,url_for
app = Flask(__name__)
@('/')
def index():
url = url_for('test_url')
return f'Hello!==={url}'
@('/test/')
def test_url():
return 'This is to test the request context'
# RuntimeError: Attempted to generate a URL without the application context being pushed.
# This has to be executed when application context is available.
# with app.app_context():
# url = url_for('test_url')
# print(url)
# RuntimeError: Application was not able to create a URL adapter for request independent URL generation.
# You might be able to fix this by setting the SERVER_NAME config variable.
with app.test_request_context():
url = url_for('test_url')
print(url)
if __name__ == '__main__':
(debug = True)
Flask_thread-isolated g-objects
Benefits of saving as a global object g object:
The g object is available throughout the runtime of the Flask application.
and is also thread-isolated like request.
This object is dedicated to storing some data defined by the developer himself, so that it can be used throughout the Flask application.
Scenarios for using the g object: There is a tool class and a user to conduct business:
def funa(uname):
print(f'funa {uname}')
def funb(uname):
print(f'funb {uname}')
def func(uname):
print(f'func {uname}')
Customer Service
from flask import Flask,request
from utils import funa,funb,func
app = Flask(__name__)
#Flask_Thread_Isolated_g_Object_Use_Explained
@("/profile/")
def my_profile().
#Fetch the reference from the url
uname = ('uname')
# Call the function function to do business
funa(uname)
funb(uname)
func(uname)
#Trouble passing a parameter every time, optimized by introducing the g object.
return "Successful operation"
if __name__ == '__main__': (debug=True)
(debug=True)
Optimize utils tools
from flask import g
def funa():
print(f'funa {}')
def funb():
print(f'funb {}')
def func():
print(f'func {}')
Optimization of user processing operations
from flask import Flask,request,g
from utils import funa,funb,func
app = Flask(__name__)
#Flask_Thread_Isolated_g_Object_Use_Explained
@("/profile/")
def my_profile().
#Fetch the reference from the url
uname = ('uname')
# Call the function function to do business
# funa(uname)
# funb(uname)
# func(uname)
#The trouble of passing a parameter every time is optimized by introducing the g object
= uname
funa()
from flask import Flask,request,g
from utils import funa,funb,func
app = Flask(__name__)
#Flask_Thread_Isolated_g_Object_Use_Explained
@("/profile/")
def my_profile().
#Fetch the reference from the url
uname = ('uname')
# Call the function function to do business
# funa(uname)
# funb(uname)
# func(uname)
#The trouble of passing a parameter every time is optimized by introducing the g object
= uname
funa()
funb()
func()
return "Successful transaction"
if __name__ == '__main__'.
(debug=True)
Introduction to Flask_Hook Functions
Common Hook Functions
-
before_first_request: executed before processing the first request for an item.
@app.before_first_request def first_request(): print('first time request')
-
before_request Execute before each request
@app.before_request def before_request(): if not hasattr(g,'glo1'): setattr(g,'glo1','desired')
-
teardown_appcontext Regardless of exceptions, registered functions are executed after each request.
@app.teardown_appcontext def teardown(exc=None): if exc is None: () else: () ()
-
template_filter Customize filters when using Jinja2 templates.
@app.template_filter("upper") def upper_filter(s): return ()
-
context_processor The context processor. Using this hook function, theMust return a dictionary. The values in this dictionary are available in all templates. The function of this hook function is that if some variables are used in many templates, then you can use this hook function to return them without having to write them in the render_template of each view function, which makes the code more concise and better maintained.
@app.context_processor def context_processor(): if hasattr(g,'user'): return {"current_user":} else: return {}
-
errorhandler errorhandler receives a status code and can be customized to return a response with this status code. In the event of an exception, such as a 404 error, or a 500 error, you can use errorhandler to handle the error gracefully.
@(404) def page_not_found(error): return 'This page does not exist',404
Flask_signaling_mechanism
pip install blinker
Customizing the Signaling Mechanism Steps
-
Creating a Signal: To define a signal you need to create a namespace using the Namespace class of the blinker package. For example, define a signal when a view function is accessed. The example code is as follows:
# Role of Namespace: To prevent multiple developers from signaling name conflicts when developing with multiple users. from blinker import Namespace mysignal = Namespace() signal1 = ('Signal name')
-
Listen to a signal: listen to the signal using the signal1 object of the connect method, in this method you need to pass a function, used to listen to the signal to do what should be done. The sample code is as follows:
def func1(sender,uname): print(sender) print(uname) (func1)
-
Send a signal: Send a signal using the send method of the signal1 object, which can be passed some other parameters. The example code is as follows:
(uname='momo')
Code demo.
from flask import Flask
from blinker import Namespace
app = Flask(__name__)
#【1】signaling mechanism 3walk
# Namespace:namespace (computing)
#1.Defining Signals
sSpace = Namespace()
fire_signal = ('Send Signal Rocket')
#2.listen in on signals
def fire_play(sender):
print(sender)
print("start play")
fire_signal.connect(fire_play)
#3.Send a signal
fire_signal.send()
if __name__ == '__main__':
(debug=True)
Flask Signal Usage Scenario_Storing User Login Logs
Define a login signal, after the user logs in, send a login signal, and then can listen to this signal, after listening to this signal, record the current user login information Use the signal to record the user's login information, that is, the login log.
Write a file to create a login signal
from blinker import Namespace
from datetime import datetime
from flask import request,g
namespace = Namespace()
#Create Login Signal
login_signal = ('login')
def login_log(sender):
# user ID login time ipaddress
now = ()
ip = request.remote_addr
log_data = "{uname}*{now}*{ip}".format(uname=, now=now, ip=ip)
with open('login_log.txt','a') as f:
(log_data + "\n")
()
#listen in on signals
login_signal.connect(login_log)
Using signals to store user login logs
from flask import Flask,request,g
from signals import login_signal
app = Flask(__name__)
@('/login/')
def login().
# Pass the uname argument as a query string
uname = ('uname')
if uname.
= uname
# Send the signal
login_signal.send()
return 'Login successful!
else: = uname
return 'Please enter your username!
if __name__ == '__main__'.
(debug=True)
Flask_Built-in_Signals
Flask has 10 common signals built-in
- template_rendered: signal when the template rendering is complete.
- **before_render_template: signal before template rendering. **
- **request_started: request_started: request_started is signaled before reaching the view function. **
- **request_finished: the end of the request is signaled before the response is sent to the client. **
- **request_tearing_down: signal sent when the request object is destroyed, even if an exception occurs during the request. **
- got_request_exception: sends a signal when an exception is thrown during the request process. The exception itself will be passed to the subscription (listening) function through the exception. Generally, you can listen to this signal to record the exception information of the website.
- appcontext_tearing_down: signal sent when the application context is destroyed.
- appcontext_pushed: signal sent when the application context is pushed onto the stack.
- appcontext_popped: signal sent when the application context is pushed off the stack.
- message_flashed: the signal sent when the flash method of Flask is called.
WTForms_Form Validation/Template Rendering
pip install flask-wtf
WTFormsBasic use of form validation
- Customize a form class that inherits from class.
- Define the fields that need to be validated. The names of the fields must be consistent with the values of the name attributes of the input tags in the template that need to be validated.
- On the fields that need to be validated, you need to specify the specific data type.
- On the relevant field, specify the validator.
- In the future, in the view function, you only need to use the object of this form class and pass the data to be validated, that is, to this form class, and then call the form class object.validate() method, if it returns True, then it means that the data entered by the user is in accordance with the format requirements, Flase means that the data entered by the user is problematic. If the validation fails, then you can get specific error information through the form class object.errors.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>A system registration page</title>
</head>
<body>
<form action="/register/" method="post">
<table>
<tr>
<th>user ID:</th>
<td><input type="text"
name="uname"></td>
</tr>
<tr>
<th>cryptographic:</th>
<td><input type="password"
name="pwd"></td>
</tr>
<tr>
<th>确认cryptographic:</th>
<td><input type="password"
name="pwd2"></td>
</tr>
<tr>
<td></td>
<td><input type="submit"
value="enrollment"></td>
</tr>
</table>
</form>
</body>
</html>
from flask import
Flask,render_template,request
from wtforms import Form,StringField
from import
Length,EqualTo
app = Flask(__name__)
@('/')
def index():
return 'Hello! '
class RegisterForm(Form):
uname = StringField(validators= [Length(min=2,max=10,message='User name length2-10among')])
pwd = StringField(validators=[Length(min=2,max=10)])
pwd2 = StringField(validators=[Length(min=2,max=10),EqualTo('pwd',message='2Inconsistent sub-passwords')])
@('/register/', methods=['GET','POST'])
def register():
if == 'GET':
return render_template('')
else:
form = RegisterForm()
if (): # Verification Success:True,fail (e.g. experiments):False
return 'Verification Success!'
else:
return f'验证fail (e.g. experiments)!{}'
if __name__ == '__main__':
(debug=True)
WTForms Common Validators
-
Length: the length of the string, there are min and max values to limit.
username = StringField(validators=[Length(min=3,max=10,message="Username must be between 3 and 10 digits long")])
-
EqualTo: verify whether the data is equal to another field, commonly used is whether the two fields Password and Confirm Password are equal.
password_repeat = StringField(validators= [Length(min=6,max=10),EqualTo("password")])
-
Email: Verify that the uploaded data is in email format.
email = StringField(validators=[Email()])
-
InputRequired: validate that the data is required, i.e., the item is required to be non-empty.
username = StringField(validators= [input_required()])
-
NumberRange: the range of the value, there is a limit of two values, min and max, which is satisfied if it is between these two numbers.
age = IntegerField(validators= [NumberRange(12,18)])
-
Regexp: Define regular expressions for validation, such as validating a cell phone number.
phone = StringField(validators= [Regexp(r'1[34578]\d{9}')])
-
URL: must be in the form of a URL Like.
home_page = StringField(validators=[URL()])
-
UUID: Verify that the data is of type UUID.
uuid = StringField(validators=[UUID()])
Form validation tool class file
from wtforms import
Form,StringField,IntegerField
from import
Length,EqualTo,Email,InputRequired,NumberRange,Regexp,URL,UUID
class RegisterForm(Form):
uname =StringField(validators= [Length(min=2,max=15,message='The length of the username must be within2-15among')])
pwd = StringField(validators= [Length(min=6,max=12)]) pwd2 = StringField(validators=[Length(min=6,max=12),EqualTo("pwd")])
class RegisterForm2(Form):
email = StringField(validators=[Email()])
uname = StringField(validators=[InputRequired()])
age = IntegerField(validators=[NumberRange(18,40)])
phone = StringField(validators=[Regexp(r'1[34578]\d{9}')])
phomepage = StringField(validators=[URL()])
uuid = StringField(validators=[UUID()])
WTForms Custom Validator
The steps to customize the validator are as follows
-
Define a method with the method name rule: validate_field_name(self,field).
-
In the method, use to get the specific value of the field.
-
When validating, if the data satisfies the conditions, then nothing can be done. If the validation fails, the
Then an exception should be thrown and the message that the validation failed should be passed to this exception class.
Flask Secure File Upload_Access
Upload File Steps:
- In the template html, the form needs to specify enctype='multipart/form-data' in order to upload the file.
- In the backend, if you want to get the uploaded file, you should use ('filename') to get it.
- Before saving a file, use .secure_filename to filter the uploaded file name. This ensures that there are no security issues.
- After getting the uploaded file, use the file object.save(path) method to save the file. Path = full path = pathname + filename
from flask import
Flask,request,render_template
import os
from import secure_filename
app = Flask(__name__)
UPLOAD_PATH =
((__file__),'imag
es')
@('/upload/',methods=
['GET','POST'])
def upload():
if == 'GET':
return render_template('')
else:
desc = ("desc")
pichead = ("pichead")
filename = secure_filename() #Pack it up. Keeping documents safe
#((UPLOAD_PATH,)) #optimizable
((UPLOAD_PATH,filename)) #Optimized
print(desc)
return 'File uploaded successfully'
if __name__ == '__main__':
(debug=True)
Restful
pip install flask-restful
Basic use
Define Restful class views:
-
Import Api from flask_restful to create an api object.
-
Write a class view that inherits from the Resource class, and within it, define the methods for the requests you want to make. For example, if you want the class view to be post-only, define a post method.
-
Use api.add_resource to add a class view and url.
from flask import Flask,url_for # pip install flask-restful from flask_restful import Resource,Api app = Flask(__name__) # build upApiboyfriend,and bind the applicationAPP api = Api(app) class LoginView(Resource): def get(self): return {"flag":True} def post(self): return {"flag":False} # build up路由映射 # api.add_resource(LoginView,'/login/') api.add_resource(LoginView,'/login/','/login2/',endpoint='login') with app.test_request_context(): # : Could notbuild url for endpoint 'LoginView'. # Did you mean 'loginview' instead? # The default is not writtenendpointopposite directionurl_forFunctions are passed the lowercase function name # If there is more than oneurl,will return the first1classifier for individual things or people, general, catch-all classifierURL # print(url_for('loginview')) print(url_for('login')) if __name__ == '__main__': (debug=True)
SQLAlchemy
SQLAlchemy is an ORM framework.
Relational Object Mapping: Mapping of Object Model to Database Tables
class Person.
name = 'xx'
age = 18
country = 'xx'
# Person class -> a table in the database
# Properties of the Person class -> a table field in the database
# An object of the Person class -> a piece of data from a table in the database
# p = Person('xx',xx)
# ()
# insert into table values ('xx',xx)
Before operating the database, make sure that the following software is installed:
-
mysql
-
pymysql
pip install pymysql
-
SQLAlchemy
pip install SQLAlchemy
Operational databases
-
Connecting to the database
from sqlalchemy import create_engine def conn_db1(). # Variables for the database HOST = '192.168.30.151' # 127.0.0.1/localhost PORT = 3306 DATA_BASE = 'flask_db' USER = 'root' PWD = '123' # DB_URI = f'Name of database + driver name://{USER}:{PWD}@{HOST}:{PORT}/{DATA_BASE}' DB_URI = f'mysql+pymysql://{USER}:{PWD}@{HOST}:{PORT}/{DATA_BASE}' engine = create_engine(DB_URI) # Execute a SQL sql = 'select 2;' conn = () rs = (sql) print(())
-
Execute native sql
def conn_db2(). # Variables for the database HOST = '192.168.30.151' # 127.0.0.1/localhost PORT = 3306 DATA_BASE = 'flask_db' USER = 'root' PWD = '123' # DB_URI = f'Name of database + driver name://{USER}:{PWD}@{HOST}:{PORT}/{DATA_BASE}' DB_URI = f'mysql+pymysql://{USER}:{PWD}@{HOST}:{PORT}/{DATA_BASE}' ''' # Create an engine, specifically for linking to the database engine = create_engine(DB_URI) sql = 'create table t_user(id int primary key auto_increment, name varchar(32));'' # Create an engine to link to the database. # Link the database conn = () # Just execute the SQL (sql) ''' def conn_db3(). # Variables for the database HOST = '192.168.30.151' #127.0.0.1/localhost PORT = 3306 DATA_BASE = 'flask_db' USER = 'root' PWD = '123' # DB_URI = f'Name of database + driver name://{USER}:{PWD}@{HOST}:{PORT}/{DATA_BASE}' DB_URI = f'mysql+pymysql://{USER}:{PWD}@{HOST}:{PORT}/{DATA_BASE}' # Create an engine, specifically for linking to the database engine = create_engine(DB_URI) sql = 'create table t_user1(id int primary key auto_increment, name varchar(32));' # Link to the database with () as conn. # Just execute the SQL (sql)
-
ORM model mapping to the database
-
expense or outlay
declarative_base
according toengine
Create an ORM base classfrom import declarative_base engine = create_engine(DB_URI) Base = declarative_base(engine)
-
Use this.
Base
class as a base class to write your own ORM class. To define the__tablename__
Class attribute to specify the name of the table in the database to which the model is mapped.class Person(Base): __tablename__ ='t_person'
-
Create properties to map to fields in the table. All properties that need to be mapped to the table should be of type Column.
class Person(Base). __tablename__ = 't_person' # Create some attributes in this ORM model to map one-to-one with the fields in the table. # These attributes must be of the type that sqlalchemy gives us. id = Column(Integer,primary_key=True,autoincrement=True) name = Column(String(50)) age = Column(Integer) country = Column(String(50))
-
-
Use .create_all() to map the model to the database
.create_all()
take note of
Once you have used the
.create_all()
After mapping the model to the database, even if you change the fields of the model, it won't be remapped again
Crud on data
Building session objects
All ORM operations with the database must be realized through a session object called session, through the following code to get the session object
from import sessionmaker
engine = create_engine(DB_URI)
Base = declarative_base(engine)
session = sessionmaker(engine)()
Add object
def create_data_one():
with Session() as session:
p1 = Person(name ='all kinds of warfare',age = 6 ,country='Beijing, capital of People's *')
(p1)
()
def create_data_many():
with Session() as session:
p2 = Person(name ='Lü Bu (-198), general and warlord',age = 19 ,country='Beijing, capital of People's *')
p3 = Person(name ='Dengcicang, female folk singer (Wuhan City)',age = 18 ,country='Beijing, capital of People's *')
session.add_all([p2,p3])
()
Find objects
def query_data_all():
with Session() as session:
all_person =
(Person).all()
for p in all_person:
print()
def query_data_one():
with Session() as session:
p1 = (Person).first()
print()
def query_data_by_params():
with Session() as session:
# p1 = (Person).filter_by(name='Lü Bu (-198), general and warlord').first()
p1 = (Person).filter( =='Lü Bu (-198), general and warlord').first()
print()
Modify object
def update_data():
with Session() as session:
p1 = (Person).filter( == 'Lü Bu (-198), general and warlord').first()
= 20
# Submission of transactions
()
Deleting objects
Check the object to be deleted from the database, then use the method to delete this data from the session, and finally COMMIT.
def delete_data():
with Session() as session:
p1 = (Person).filter( =='Dengcicang, female folk singer (Wuhan City)').first()
(p1)
()
Common Data Types
-
Integer: plastic, maps to the database as type int.
-
Float: Floating point type that maps to float in the database. It occupies 32 bits.
-
Double: double-precision floating-point type, maps to double in the database, occupies 64 bits (not in SQLALCHEMY).
-
String: variable character type, maps to varchar in the database.
-
Boolean: Boolean type, maps to tinyint type in the database.
-
DECIMAL: Fixed-point type. Is specifically designed to solve the problem of lost precision for floating point types. It is recommended that you use this data type when storing money related fields.
This type is used by passing two parameters, the first parameter is used to mark how many numbers this field can always store, and the second parameter indicates how many decimal places there are.
-
Enum: enumeration type. Specifies that a field can only be a few values specified in the enumeration and cannot be any other value. In the ORM model, use Enum as an enumeration, the sample code is as follows:
class News(Base): __tablename__ = 't_news' tag = Column(Enum("python",'flask','django'))
The enum module has been built into python3, and we can use it to define the relevant fields as well
class TagEnum():
python = "python"
flask = "flask"
django = "django"
class News(Base):
__tablename__ = 't_news'
id =Column(Integer,primary_key=True,autoincrement=True)
tag = Column(Enum(TagEnum))
news = News(tag=)
-
Date: store the time, can only store the year, month and day. The mapping to the database is of type date. In Python code, you can use to specify the
-
DateTime: store time, can store year, month, day, hour, minute, second, millisecond, etc.. The mapping to the database is also of type datetime. In Python code, you can use the
to specify.
-
Time: store time, can store hours, minutes and seconds. The mapping to the database is also of type time. In Python code, you can use to this one.
class News(Base): __tablename__ = 't_news' create_time = Column(Time) news =News(create_time=time(hour=11,minute=11,second=11))
-
Text: store long strings. Generally can store more than 6W characters. If beyond this range, you can use the LONGTEXT type. Mapped to the database is the text type.
-
LONGTEXT: long text type, mapped to the database is longtext type.
Code demo.
from sqlalchemy import create_engine,Column,Integer,String,Float,Enum,Boolean,DECIMAL,Text,Date,DateTime,Time
from import declarative_base
from import LONGTEXT
from import sessionmaker
import enum
from datetime import date
from datetime import datetime
from datetime import time
#Prepare a bunch of information for the database ip port user pwd
Name of the database Organize the format as required
HOSTNAME = '127.0.0.1'
PORT = '3306'
DATABASE = 'first_sqlalchemy'
USERNAME = 'root'
PASSWORD = 'root'
#dialect+driver://username:password@host:port/database?charset=utf8
#Follow the format above to Organizational database information
DB_URI ="mysql+pymysql://{username}:{password}@{host}:{port}/{db}?charset=utf8".format(username=USERNAME,password=PASSWORD,host=HOSTNAME,port=PORT,db=DATABASE)
#Creating a Database Engine
engine = create_engine(DB_URI)
#Creating Session Objects
session = sessionmaker(engine)()
#Define an enum class
class TagEnum():
python="PYHTON2"
flask="FLASK2"
django ="DJANGO"
#Create aORMmould Description based onsqlalchemy map tomysqlWhat are the common field types for databases?
Base = declarative_base(engine)
class News(Base):
__tablename__='news'
id = Column(Integer,primary_key=True,autoincrement=True)
price1 = Column(Float) #Loss of precision when storing data
price2 = Column(DECIMAL(10,4))
title = Column(String(50))
is_delete =Column(Boolean)
tag1 =Column(Enum('PYTHON','FLASK','DJANGO')) #regular way of writing an enumeration
tag2 =Column(Enum(TagEnum)) #Enumeration written another way
create_time1=Column(Date)
create_time2=Column(DateTime)
create_time3=Column(Time)
content1 =Column(Text)
content2 =Column(LONGTEXT)
# .drop_all()
# .create_all()
#Adding data to a tablenewscenter
# a1 = News(price1=1000.0078,price2=1000.0078,title='Test Data',is_delete=True,tag1="PYTHON",tag2=,
# create_time1=date(2018,12,12),create_time2=datetime(2019,2,20,12,12,30),create_time3=time(hour=11,minute=12,second=13),
#content1="hello",content2="hello hi nihao")a1 =News(price1=1000.0078,price2=1000.0078,title='Test Data',is_delete=False,tag1="PYTHON",tag2=,
create_time1=date(2018,12,12),create_time2=datetime(2019,2,20,12,12,30),create_time3=time(hour=11,minute=12,second=13),content1="hello",content2="hello hi nihao")
(a1)
()
Column common parameters
- primary_key: True sets a field as primary key.
- autoincrement: True sets this field to autoincrement.
- default: set the default value of a field. It is often used for fields such as publish time.
- nullable: Specifies whether a field is null. The default value is True, which means it can be null.
- unique: Specifies whether the value of a field is unique. The default is False.
- onupdate: The value or function specified by this parameter is called when the data is updated. The first time this data is inserted, the value of onupdate will not be used, only the default value will be used. Commonly used is the update_time field (which is updated every time the data is updated).
- name: Specifies the name of the field in the table to which an attribute in the ORM model is mapped. If not specified, the name of the attribute is used as the field name. If specified, the specified value is used as the table field name. This parameter can also be specified as a positional parameter in the first parameter.
title = Column(String(50),name='title',nullable=False)
title = Column('my_title',String(50),nullable=False)
from datetime import datetime
from sqlalchemy import
Column,Integer,DateTime,String
from db_util import Base,Session
class News(Base):
__tablename__ = 't_news2'
id = Column(Integer,primary_key = True,autoincrement = True)
phone = Column(String(11),unique = True)
title = Column(String(32),nullable =False)
read_count = Column(Integer,default=1)
create_time = Column(DateTime,default =)
update_time = Column(DateTime,default =, onupdate = ) # When the data is updated,The content of the parameter is only changed
def create_data():
new1 = News(phone='16866666666',title='Test Column Parameters')
with Session() as session:
(new1)
()
def create_data2():
# new1 = News(phone='16866666666',title='Test Column Parameters') #No duplicates allowed
# new1 = News(phone='16866666668') #titleCannot be empty
# with Session() as session:
# (new1)
# ()
with Session() as session:
new1 = (News).first()
new1.read_count = 2
()
if __name__ == '__main__':
# .create_all()
# create_data()
create_data2()
Use of the query function
-
Model Name. Specifies that all attributes in this model are to be looked up (the corresponding lookup table is a full table lookup)
-
Attributes in a model. You can specify that you want to find only a few of the attributes of a model
-
aggregate function (math.)
- : The number of statistical rows.
- : Take the average.
- : Find the maximum value.
- : Find the minimum value.
- : Summation.
draw attention to sth.
func
On, in fact, there is no any aggregate function, but because he did some magic at the bottom, as long as mysql has the aggregate function, can be called through funcfrom random import randint from sqlalchemy import Column,Integer,String,func from db_util import Base,Session class Item(Base): __tablename__ = 't_item' id = Column(Integer,primary_key = True,autoincrement = True) title = Column(String(32)) price = Column(Integer) def create_data(): with Session() as ses: for i in range(10): item = Item(title = f'offerings:{i+1}',price=randint(1,100)) (item) () def query_model_name(): # Get all fields with Session() as ses: rs = (Item).all() for r in rs: print() def query_model_attr(): # Get the specified field with Session() as ses: rs = (,).all() for r in rs: print() def query_by_func(): # Statistics for a specified column with Session() as ses: # rs = (()).first() # rs = (()).first() # rs = (()).first() rs = (()).first() print(rs) if __name__ =='__main__': # .create_all() # create_data() # query_model_name() # query_model_attr() query_by_func()
filter filter data
-
equals
news= (News).filter( == "title1").first()
-
not equals
query(User).filter( != 'ed')
-
like & like [case insensitive]
query(User).filter(('%ed%'))
-
in
query(User).filter(.in_(['ed','wendy','jack']))
-
not in
query(User).filter(~.in_(['ed','wendy','jack']))
-
is null
query(User).filter(==None) # or query(User).filter(.is_(None))
-
is not null
query(User).filter( ! = None) # Or query(User).filter((None))
-
and
query(User).filter(and_(=='ed',=='Ed Jones')) # Or pass multiple parameters query(User).filter(=='ed',=='Ed Jones') # Or by passing multiple filters query(User).filter(=='ed').filter(=='Ed Jones')
-
or
query(User).filter(or_(=='ed',=='wendy'))
superficial relationship
foreign key
Creating a foreign key with SQLAlchemy is very simple. Just add a field to the slave table and specify which field of which table this field is foreign keyed to. The field that is foreign keyed in the slave table must be of the same type as the primary key field of the master table.
class User(Base):
__tablename__ = 't_user'
id = Column(Integer,primary_key=True,autoincrement=True)
uname =Column(String(50),nullable=False,name='name')
class News(Base):
__tablename__ = 't_news'
id = Column(Integer,primary_key=True,autoincrement=True)
title = Column(String(50),nullable=False)
content = Column(Text,nullable=False)
uid = Column(Integer,ForeignKey('t_user.id',)
foreign key constraint
RESTRICT: If the child table has associated data corresponding to the parent table, deleting the corresponding data of the parent table will prevent the deletion. Default
NO ACTION: In MySQL, same as RESTRICT.
CASCADE: Cascade deletion.
SET NULL: When the corresponding data of the parent table is deleted, the corresponding data item of the child table will be set to NULL.
from sqlalchemy import Column,Integer,String,Text,ForeignKey
from db_util import Base,Session
class User(Base):
__tablename__ = 't_user'
id = Column(Integer,primary_key=True,autoincrement=True)
uname =Column(String(50),nullable=False,name='name')
class News(Base):
__tablename__ = 't_news'
id = Column(Integer,primary_key=True,autoincrement=True)
title = Column(String(50),nullable=False)
content = Column(Text,nullable=False)
# uid =Column(Integer,ForeignKey('t_user.id')) #Do not delete master table data by default
# uid =Column(Integer,ForeignKey('t_user.id',ondelete = 'RESTRICT')) # Default Policy
# uid =Column(Integer,ForeignKey('t_user.id',ondelete = 'NO ACTION')) # Default Policy
# uid =Column(Integer,ForeignKey('t_user.id',ondelete = 'CASCADE')) # Cascade Deletion,Deletion of data from the master table,The data in the sub-table will also be deleted
uid =Column(Integer,ForeignKey('t_user.id',ondelete = 'SET NULL')) # When you find that the master table data has been deleted,The data columns of the sub-table will be cleared
many-to-one (game)
SQLAlchemy provides a relationship, a class that defines attributes that can be accessed directly through attribute access when accessing the associated table in the future.
Alternatively, a backref can be used to specify the name of the property to be accessed in reverse. newss means that there are multiple news articles. The relationship between them is a "one-to-many" relationship
from sqlalchemy import Column,Integer,String,Text,ForeignKey
from import relationship
from db_util import Base,Session
class User(Base):
__tablename__ = 't_user'
id = Column(Integer,primary_key=True,autoincrement=True)
uname = Column(String(50),nullable=False,name='name')
# news = relationship('News') # unfriendly
def __repr__(self):
return f'<User: id={} uname={}>'
# 1many-layered (authority) ForeignKeyThe keywords are to be built on the one side more
class News(Base):
__tablename__ = 't_news'
id = Column(Integer,primary_key=True,autoincrement=True)
title = Column(String(50),nullable=False)
content = Column(Text,nullable=False)
uid = Column(Integer,ForeignKey('t_user.id'))
user = relationship('User',backref='news') # Inject data from the main table into this field
def __repr__(self):
return f'<News: id={} title={} content={} uid=
{}>'
def create_data():
user = User(uname = 'sxt')
news1 = News(title='Python',content='flask',uid = 1)
news2 = News(title='MySQL',content='SQL',uid = 1)
with Session() as ses:
(user)
()
with Session() as ses:
(news1)
(news2)
()
def query_data():
with Session() as ses:
# news1 = (News).first()
# print(news1)
# select from t_news n left join t_user u = where =1;
news1 = (News).first()
uid =
user = (User).first()
print(user)
def query_data2():
# Querying data from the main table with the pass-through sub-table
with Session() as ses:
news1 = (News).first()
print()
def query_data3():
# Finding data in sub-tables through the main table
with Session() as ses:
user1 = (User).first()
print()
if __name__ == '__main__':
# .create_all()
# create_data()
# query_data()
# query_query_data3()data2()
query_data3()
one-to-one
In sqlalchemy, if you want to map two models into a one-to-one relationship, you should pass a uselist=False parameter when specifying the reference in the parent model.
It's telling the parent model that when it refers to this slave model in the future, it's no longer a list, but rather an object
Method 1
class LoginUser(Base):
__tablename__ = 't_user_login'
id = Column(Integer,primary_key=True,autoincrement=True)
uname = Column(String(32),nullable=False)
passwd = Column(String(32),nullable=False)
user = relationship('User',uselist=False) # unfriendly,There's always a warning.
class User(Base):
__tablename__ = 't_user'
id = Column(Integer,primary_key=True,autoincrement=True)
name = Column(String(32),nullable=False,name='name')
gender = Column(String(1))
address = Column(String(64))
login_id = Column(Integer,ForeignKey('t_user_login.id'))
login_user = relationship('LoginUser')
Method 2
The code can also be simplified with the help of
class LoginUser(Base):
__tablename__ = 't_user_login'
id = Column(Integer,primary_key=True,autoincrement=True)
uname = Column(String(32),nullable=False)
passwd =Column(String(32),nullable=False)
# establish1treat (sb a certain way)1exclusionary rule, establish一个字段来做别一个表的标识(foreign key)
class User(Base):
__tablename__ = 't_user'
id =Column(Integer,primary_key=True,autoincrement=True)
name =Column(String(32),nullable=False,name='name')
gender = Column(String(1))
address = Column(String(64))
login_id = Column(Integer,ForeignKey('t_user_login.id'))
login_user = relationship('LoginUser',backref=backref('user',uselist=False))
Example.
from sqlalchemy import Column,Integer,String,Text,ForeignKey
from import relationship,backref
from db_util import Base,Session
class LoginUser(Base):
__tablename__ = 't_user_login'
id = Column(Integer,primary_key=True,autoincrement=True)
uname = Column(String(32),nullable=False)
passwd = Column(String(32),nullable=False)
# user = relationship('User',uselist=False) # unfriendly,There's always a warning.
def __repr__(self):
return f'<User: id={} uname={} passwd={}>
# establish1treat (sb a certain way)1exclusionary rule, establish一个字段来做别一个表的标识(foreign key)
class User(Base):
__tablename__ = 't_user'
id = Column(Integer,primary_key=True,autoincrement=True)
name = Column(String(32),nullable=False,name='name')
gender = Column(String(1))
address = Column(String(64))
login_id = Column(Integer,ForeignKey('t_user_login.id'))
login_user = relationship('LoginUser',backref=backref('user',uselist=False))
def __repr__(self):
return f'<User: id={} name={} gender={} address=
{}>'
def create_data():
login = LoginUser(uname = 'baizhan',passwd = '123')
user = User(name='all kinds of warfare',gender ='daughter',address ='Beijing, capital of People's *')
# = user # Establishment of affiliation
user.login_user = login
with Session() as ses:
(user)
()
def query_data():
# with Session() as ses:
# login =(LoginUser).first()
# print()
with Session() as ses:
user = (User).first()
print(user.login_user)
if __name__ == '__main__':
# .create_all()
# create_data()
query_data()
many-to-many
- Many-to-many relationships require an intermediate table to bind them to each other.
- Start by defining two models that need to do many-to-many
- Use a Table to define an intermediate table, which usually contains the foreign key fields of both models, and let them both act as a "composite primary key".
- Choose one of the two models you want to do many-to-many, define a relationship attribute to bind the relationship between the three, and pass in a secondary=intermediate table object name when you use relationships.
from sqlalchemy import Column,Integer,String,ForeignKey
from sqlalchemy import Table
from import relationship,backref
from db_util import Base,Session
# Creation of the first3set out,to establish a many-to-many relationship
# put into2over a model
news_tag = Table(
't_news_tag',
,
Column('news_id',Integer,ForeignKey('t_news.id'),primary_key = True),
Column('tag_id',Integer,ForeignKey('t_tag.id'),primary_key = True),)
class News(Base):
__tablename__ = 't_news'
id = Column(Integer,primary_key=True,autoincrement=True)
title = Column(String(32),nullable=False)
tags = relationship('Tag',backref='newss',secondary= news_tag)
def __repr__(self):
return f'<News: id={} title={}>'
class Tag(Base):
__tablename__ = 't_tag'
id = Column(Integer,primary_key=True,autoincrement=True)
name = Column(String(32),nullable=False)
# news = relationship('News',backref='tags',secondary= news_tag)
def __repr__(self):
return f'<Tag: id={} name={}>'
def create_data():
news1 = News(title = 'PythonUpdated.!')
news2 = News(title = 'SQLAlchemyIt's powerful again.!')
tag1 = Tag(name = 'ITpublic information')
tag2 = Tag(name ='science and technology')
(tag1)
(tag2)
(tag1)
(tag2)
with Session() as ses:
(news1)
(news2)
()
def query_data():
with Session() as ses:
news = (News).first()
print()
if __name__ == '__main__':
# .create_all()
# create_data()
query_data()
Considerations for deleting data at the ORM level
Deleting data at the ORM level ignores foreign key constraints at the mysql level
The corresponding data will be deleted directly, and then the foreign key from the table will be set to NULL, which is the SET NULL of the database.
If you want to avoid this behavior, you should set nullable=False for foreign keys from the table.
from sqlalchemy import Column, Integer, String, ForeignKey
from import relationship
from db_util import Base, Session
class User(Base):
__tablename__ = 't_user'
id = Column(Integer, primary_key=True,autoincrement=True)
name = Column(String(32))
class Article(Base):
__tablename__ = 't_article'
id = Column(Integer, primary_key=True,autoincrement=True)
title = Column(String(32))
uid = Column(Integer,ForeignKey("t_user.id"))
# uid = Column(Integer,ForeignKey("t_user.id"),nullable = False)
user =relationship('User',backref='articles')
def create_data():
.drop_all() # Deleting an Existing Table
.create_all() # Create Table
# Initialization data
user = User(name='SXT')
art1 = Article(title='Python', uid=1)
art2 = Article(title='MySQL', uid=1)
(art1)
(art2)
with Session() as ses:
(user)
()
def delete_data():
# When deleting master table data by default,will set the foreign key of the child table that references data from the master table to theNull
with Session() as ses:
user = (User).first()
(user)
()
if __name__ == '__main__':
# create_data()
delete_data()
ORM level relationships method in cascade
The cascade attribute value is:
- save-update: The default option. When you add a piece of data, it adds all other data associated with it to the database. This behavior is affected by the save-update attribute.
- delete: Indicates whether deleting data in a model also deletes the data associated with that model using relationship.
- delete-orphan: indicates that when an ORM object is deleted from the parent table, it will be deleted itself. Of course, if the data in the parent table is deleted, it will also be deleted. This option can only be used for one-to-many and requires a single_parent=True parameter in the relationships in the submodel.
- merge: the default option. When you use merge to merge an object, the objects associated with the relationship will also be merged.
- expunge: When an expunge operation is performed, the associated objects are also removed. This operation only removes the object from the session, it does not actually remove it from the database.
- all:Yes, it is.save-update, merge, refresh-expire, expunge, delete Abbreviations for several。
from sqlalchemy import Column, Integer, String, ForeignKey
from import relationship,backref
from db_util import Base, Session
class User(Base):
__tablename__ = 't_user'
id = Column(Integer, primary_key=True,autoincrement=True)
name = Column(String(32))
# articles =relationship('Article',backref='user',cascade='')
# articles =relationship('Article',backref='user',cascade='save-update') # default (setting)cascadeThe value ofsaveupdate
# articles =relationship('Article',backref='user',cascade='save-update,delete') # deleteCan help to delete data from related tables
# articles = relationship('Article',backref='user',cascade='save-update,delete,deleteorphan',single_parent=True) # When the affiliation is dissolved,Subtable data will be cleared
class Article(Base):
__tablename__ = 't_article'
id = Column(Integer, primary_key=True,autoincrement=True)
title = Column(String(32))
uid = Column(Integer,ForeignKey("t_user.id"))
# user =relationship('User',backref='articles',cascade='save-update,delete') # It deletes the data from the master table
user = relationship('User',backref=backref('articles',cascade='save-update,delete,deleteorphan'))
def create_data():
.drop_all() # Deleting an Existing Table
.create_all() # Create Table
# Initialization data
user = User(name='SXT')
art1 = Article(title='Python', uid=1)
art2 = Article(title='MySQL', uid=1)
(art1)
(art2)
# Save data
with Session() as ses:
(user)
()
def delete_data():
with Session() as ses:
user = (User).first()
(user)
()
def delete_art():
with Session() as ses:
art = (Article).first()
(art)
()
def update_data():
with Session() as ses:
user = (User).first()
= []
()
if __name__ == '__main__':
# create_data()
# delete_data()
# update_data()
delete_art()
arrange in order
order_by method sorting: you can specify that the attributes in the model should be sorted according to a certain attribute, "model_name.attribute_name.desc()" means descending order. Attribute.desc()" represents a descending order.
The order_by attribute in the relationship's method: When specifying the relationship method, add the order_by attribute to specify the sorted field.
Method 1: The order_by method specifies that the
# Ascending order
users = (User).order_by().all()
# Descending
users = (User).order_by(()).all()
Method 2: When two tables are involved, use the order_by attribute in the relationships method to specify the sorting method when defining the model.
from random import randint
from sqlalchemy import Column,Integer,String,ForeignKey
from import relationship,backref
from db_util import Base,Session
class User(Base):
__tablename__ = 't_user'
id = Column(Integer, primary_key=True,autoincrement=True)
name = Column(String(32))
age = Column(Integer)
def __repr__(self):
return f'<User: id={} name={} age={}>'
class News(Base):
__tablename__ = 't_news'
id = Column(Integer,primary_key=True,autoincrement=True)
title = Column(String(32),nullable=False)
content = Column(String(32),nullable=False)
read_count = Column(Integer)
uid = Column(Integer,ForeignKey('t_user.id'))
user = relationship('User',backref=backref('newss',order_by=read_count))
def __repr__(self):
return f'<User: id={} title={} content={}
read_count={self.read_count}>'
def create_user():
with Session() as ses:
for i in range(10):
user = User(name = f'subscribers{i}',age= randint(6,20))
(user)
for i in range(10):
news = News(title = f'public information{i}',content ='public information',read_count =randint(1,1000))
(news)
()
def query_user():
with Session() as ses:
users = (User).all()
for i in users[-1].newss:
print(i)
if __name__ == '__main__':
# .drop_all()
# .create_all()
# create_user()
query_user()
take note of
__mapper_args__
Version 1.1 of the parameter has been discarded
Limit, offset, slice usage
- limit: you can limit the query to the first few data. Generic top-N query
- offset: You can limit the number of previous items to be filtered out when searching for data. You can specify the offset at which to start the query.
- Slicing: You can use slicing operations on Query objects to get the desired data.
- You can use the slice(start,stop) method to do slicing.
- You can also use [start:stop] for slicing operations.
- Generally in actual development, the center bracket form is used more often.
from random import randint
from sqlalchemy import Column,Integer,String
from db_util import Base,Session
class News(Base):
__tablename__ = 't_news'
id =Column(Integer,primary_key=True,autoincrement=True)
title =Column(String(32),nullable=False)
content =Column(String(32),nullable=False)
read_count = Column(Integer)
def __repr__(self):
return f'<User: id={} title={} content={}
read_count={self.read_count}>'
def create_data():
.drop_all()
.create_all()
with Session() as ses:
for i in range(10):
news = News(title=f'title{i}',content=f'info{i}',read_count= randint(0,1000))
(news)
()
def query_by_limit():
with Session() as ses:
newss = (News).limit(3).all()
for n in newss:
print(n)
def query_by_offset():
with Session() as ses:
newss = (News).offset(3).all()
for n in newss:
print(n)
def query_by_page():
# limit topNdigital
# offset skip overndigital
# paging effect 1-3 4-6 7-9
# 3 0 1 (pagenum-1)*pagesize
# 3 3 2 (2-1)*3 = 3
# 3 6 3 (3-1)*3 = 6
# 3 9 4 (4-1)*3 = 6
with Session() as ses:
# (pagenum-1)*pagesize
newss = (News).limit(3).offset(3).all()
for n in newss:
print(n)
def query_by_slice():
with Session() as ses:
# Which index to start with,Which index to end at
newss = (News).slice(3,6).all()
for n in newss:
print(n)
def query_by_qiepian():
with Session() as ses:
# Which index to start with,Which index to end at
newss = (News).all()[3:6]
for n in newss:
print(n)
if __name__ == '__main__':
# create_data()
# query_by_limit()
# query_by_offset()
# query_by_page()
# query_by_slice()
query_by_qiepian()
lazy loading (computing)
Database migration tool alembic use
alembic was developed by the authors of sqlalchemy to migrate and map ORM models to databases.
The use of alembic is a bit similar to git.
All commands in alembic start with alembic.
The alembic migration file is also controlled by versioning the
mounting
pip install alembic
utilization
Such as creating a module and then defining the required model classes in it:
from sqlalchemy import Column,String,Integer,create_engine
from import declarative_base
HOSTNAME = '127.0.0.1'
PORT = '3306'
DATABASE = 'alembic_demo'
USERNAME = 'root'
PASSWORD = 'root'
DB_URI ="mysql+pymysql://{username}:{password}@{host}:{port}/{db}?charset=utf8".format(username=USERNAME,password=PASSWORD,host=HOSTNAME,port=PORT,db=DATABASE)
engine = create_engine(DB_URI)
Base = declarative_base(engine)
class User(Base):
__tablename__ = 'user'
id =Column(Integer,primary_key=True,autoincrement=True)
uname = Column(String(50),nullable=False)
country = Column(String(50))
# ORM -> Migration documents -> Mapping to the database
# import os
# print((__file__))
Modify the configuration file
In the item, set the connection method to the database. The method is the same as for sqlalchemy.
= driver://user:pass@localhost/dbname
Give the item to set the database connection operation to:
= mysql+pymysql://root:root@localhost/alembic_demo?charset=utf8
In order to update the database using the model class, you need to set the target_metadata entry in the alembic/ file, which defaults to target_metadata=None.
You need to set the value of target_metadata to the model, but then import the models
Import the path of the current project into path using the sys and os modules:.
The operation to import models is:
import sys,os
(((__file__)))
import models
Set the target_metadata item action to
target_metadata =
Automatic generation of migration files
Use alembic revision --autogenerate -m to generate a migration file with the current state in the model.
Mapping the generated migration files to the database
Use the alembic upgrade head to actually map the migration file you just generated to the database.
Similarly, if you want to downgrade, then use the alembic downgrade head.
If the model is modified later, repeat steps 4 and 5
Explanation of common alembic commands and parameters
- init: create an alembic repository.
- revision: creates a new revision file.
- --autogenerate: Automatically take the changes of the current model and generate a migration script.
- -m: what changes have been made to this migration, the user can specify this parameter for easy review
- upgrade: Maps the specified version of the migration file to the database, executing the upgrade function in the version file.
If there are multiple migration scripts that are not mapped to the database, then multiple migration scripts are executed
- [head]: represents the version number of the latest migration script.
- downgrade: will execute the downgrade function in the specified version of the migration file.
- heads: show the version number of the script file pointed to by heads.
- history: Lists all migrated versions and their information.
- current: show the current version number in the database.
Also, the first time you perform an upgrade, a table called alembic_version is created in the database, which will have only one piece of data that records which version of the migration file is currently mapped to the database.
Common errors and solutions
concern
Error when creating a new version FAILED: Target database is not up to date
rationale
Mainly heads and current are not the same. current is behind the version of heads
method settle an issue
commander-in-chief (military)currentmove toheadfirst (of multiple parts)。alembic upgrade head
concern
Error when creating a new version KeyError: '087f047901d6' or FAILED: Can't locate revision identified by 'da3a8bee2343'
rationale
The version number stored in the database is not in the migration script file
method settle an issue
Delete all migration files in versions, delete all tables in the database
Flask-SQLAlchemy in combination with alembic
-
Configure the database connection file as
HOSTNAME = '127.0.0.1' PORT = '3306' DATABASE = 'fs_alembic_demo' USERNAME = 'root' PASSWORD = 'root' DB_URI ="mysql+pymysql://{username}:{password}@{host}:{port}/{db}?charset=utf8".format(username=USERNAME,password=PASSWORD,host=HOSTNAME,port=PORT,db=DATABASE) SQLALCHEMY_DATABASE_URI = DB_URI
-
Combine the files with the main runtime files of the flask project such as
from flask import Flask from flask_sqlalchemy import SQLAlchemy import config app = Flask(__name__) .from_object(config) db = SQLAlchemy(app) class User(): __tablename__ = 'user' id = (,primary_key=True,autoincrement=True) uname =((50),nullable=False) age = () gender=((2)) @('/') def hello_world(): return 'Hello World!' if __name__ == '__main__': ()
-
Creating a repository with alembic (initializing the repository)
- Open the dos system interface
- cd to the current project directory. Note: If you want to use the alembic, you need to enter the virtual environment where alembic is installed, otherwise you won't be able to find this command.
- Then run the command "alembic init [name of the repository, alembic is recommended]"
-
Modify the configuration file
In the item, set the connection method to the database. The method is the same as for sqlalchemy.
= driver://user:pass@localhost/dbname
Give the item to set the database connection operation to:
= mysql+pymysql://root:root@localhost/fs_ale mbic_demo?charset=utf8
In order to update the database with the model class, you need to set the target_metadata entry in the alembic/ file, which defaults to target_metadata=None. You need to set the value of target_metadata to the model , but to import momo use the sys module and the os module to import the path of the current project to the path: The operation to import momo is:
import sys,os (((__file__ ))) import main
Set the target_metadata item operation to:
target_metadata =
-
Automatic generation of migration files
Use alembic revision --autogenerate -m "prompt message" to generate a migration file from the state in the current model.
-
Mapping the generated migration files to the database
Use the alembic upgrade head to take the migration file you just generated and actually map it to the database.
Similarly, if you want to downgrade, then use the alembic downgrade head.
-
If the model is modified later, repeat steps 5 and 6
Flask-Migrate
flask-migrate is based on Alembic for a package, and integrated into Flask, all the migration operations are actually done by Alembic, he can track the changes in the model and map the changes to the database
mounting
pip install flask-migrate
Usage
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
# Database variables
HOST = '192.168.30.151' #
127.0.0.1/localhost
PORT = 3306
DATA_BASE = 'flask_db'
USER = 'root'
PWD = '123'
DB_URI = f'mysql+pymysql://{USER}:{PWD}@{HOST}:{PORT}/{DATA_BASE}'
#mysql+pymysql://root:[email protected]/flask_db
['SQLALCHEMY_DATABASE_URI'] =DB_URI
['SQLALCHEMY_TRACK_MODIFICATIONS']= False
db = SQLAlchemy(app)
# Creating Model Classes
class User():
__tablename__ = 't_user'
id = (,primary_key =True,autoincrement = True)
name = ((32))
age = ()
def __repr__(self):
return f'<User id={} name={}>'
from flask_migrate import Migrate
Migrate(app,db)
take note of
Create a Migrate(app,db) object.
-
Creating a Migration Repository
This command creates the migrations folder, where all the migration files will be placed.
flask db init
-
Generating Script Files
flask db migrate
-
Updating the database
flask db upgrade
-
Return to previous version
flask db downgrade version_
Flask project structure refactoring
The basic structure is as follows: minor adjustments can be made according to actual needs.
|project_name
|--pro_name # Package directory for the entire program
|----__init__.py # Project package files
|----templates # Template files
|------common # Common templates
|------errors # Error pages
|------user # User templates
|------email # Email templates
|----static # Static resource files
|------js # JS scripts
|------css # Style Sheets
|------img # images
|------ # site charts
|----user # user module
|------__init__.py # user-module-package-file
|------ # user-module-view-file
|----item # product-module
|------__init__.py # product-module-package-file
|------ # product-module-view-file
|---- # data-model
|-- # Project startup control file
|-- # Configuration files
|-- # List of dependency packages
|--migrations # Database migration directory
Note 1
The package directory name of the entire program cannot be app , otherwise it will report the
Error: Failed to find Flask application or factory in module 'app'. Use 'FLASK_APP=app:name' to specify one.
Note 2
The name of the project startup control file is ,otherwise it will report the
Error: Could not locate a Flask application. You did not provide the "FLASK_APP" environment variable, and a "" or "" module was not found in the current directory.
Solution 2
Use .env files to solve
# .env
FLASK_APP=pro_name/init:create_app()
# manager
from pro_name import create_app
# pip install python-dotenv
if __name__ == '__main__':
app = create_app('dev')
()
# config
class BaseConfig:
# Database variables
HOST = '192.168.30.151' #127.0.0.1/localhost
PORT = 3306
DATA_BASE = 'flask_db'
USER = 'root'
PWD = '123'
DB_URI = f'mysql+pymysql://{USER}:{PWD}@{HOST}:{PORT}/{DATA_BASE}'
SQLALCHEMY_DATABASE_URI = DB_URI
SQLALCHEMY_TRACK_MODIFICATIONS = False
class DevelopmentConfig(BaseConfig):
DEBUG = True
class ProductionConfig(BaseConfig):
DEBUG = False
config = {
'dev': DevelopmentConfig,
'pro': ProductionConfig,
'base': BaseConfig
}
# pro_name/__init__.py
from config import config
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
db = SQLAlchemy()
def create_app(model = 'base'):
app = Flask(__name__)
# .from_pyfile('')
obj = (model)
.from_object(obj)
db.init_app(app)
Migrate(app,db)
from pro_name.user import user_bp
app.register_blueprint(user_bp)
return app
#
from pro_name import db
# Creating Model Classes
class User():
__tablename__ = 't_user'
id = (,primary_key =
True,autoincrement = True)
name = ((32))
pwd = ((32))
age = ()
city = ((32))
def __repr__(self):
return f'<User id={} name={}>'
# pro_name/user/__init__.py
from import Blueprint
user_bp = Blueprint('user',__name__)
from pro_name.user import view
# pro_name/user/
from import MethodView
from flask import request,render_template
from pro_name.models import User
from pro_name.user import user_bp
class LoginView(MethodView):
def _jump(self,msg = None):
return
render_template('',msg = msg)
def get(self,msg = None):
return self._jump()
def post(self):
uname = ('name')
pwd = ('pwd')
user = ( ==uname, == pwd).first()
if user:
return 'Login Successful!'
else:
return self._jump(msg='Incorrect login username or password')
user_bp.add_url_rule('/login/',view_func=LoginView.as_view('login'))
Ajax
Basic Ajax Usage
-
Create Ajax
XMLHttpRequest
boyfriendlet xhr = new XMLHttpRequest()
-
Setting the AJAX request address and request method
The () method is used to specify the parameters of the HTTP request, or to initialize the XMLHttpRequest instance object. It can take a total of five parameters.
void open( string method, string url, optional boolean async, optional string user, optional string password );
- method: represents the HTTP verb method, such as GET, POST, PUT, DELETE, HEAD and so on.
- url : Indicates the request send target URL.
- async : Boolean indicating whether the request is asynchronous or not, default is true. If set to false, the send() method will not proceed until it receives the result back from the server. This parameter is optional. Because synchronous AJAX requests can cause browsers to become unresponsive, many browsers have banned their use in the main thread and only allow them to be used inside a worker. Therefore, this parameter should never be set to false.
- user : Indicates the user name to be used for authentication, the default is an empty string. This parameter is optional.
- password : The password used for authentication, the default is an empty string. This parameter is optional.
Case in point:
('GET','')
-
Send Request
() method is used to actually make the HTTP request. Its parameters are optional; without parameters, the HTTP request contains only headers, i.e., a URL, typically a GET request; with parameters, it contains headers as well as a body of information containing specific data, typically a POST request.
()
-
Getting the response data from the server to the client The XMLHttpRequest object can be assigned a listener function for the following events
- : listen function for loadstart event (HTTP request sent)
- : Listener function for progress events (data being sent and loaded)
- : Listener function for abort events (request aborts, e.g. user calls abort() method)
- : listen function for error events (failed requests)
- : Listen function for load event (successful completion of request)
- : listen function for the timeout event (the user-specified time limit has expired and the request has not been completed)
- : Listen function for loadend event (request completion, regardless of success or failure)
- : readystatechange event (when the readyState property changes) listener function
= function()
Full Code
// Create the AJAX object
let xhr = new XMLHttpRequest()
// Set the parameters of the request
('GET','/get')
// Send the request
()
// Get the response data
= function () {
// Get the text of the response
content =
// Print the data to the console
(content)
// Get the div tag
info_tag = ('info')
// Fill the div with data
info_tag.innerHTML = content
}
AJAX get request parameters
In a get request, the parameters are spliced into the url, so you can get the parameters and splice them into the url.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>02_AJAX(used form a nominal expression)get(used form a nominal expression)参数传递</title>
</head>
<body>
<h1>02_AJAX(used form a nominal expression)get(used form a nominal expression)参数传递</h1>
name:<input type="text" ><br/>
passwd: <input type="password" >
<br/>
<input type="button" value="Getting data" onclick="submitForm()">
<script>
function submitForm(){
let name = ('name').value
let pwd = ('pwd').value
url = '/get'
url = url +"?name="+name+"&pwd="+pwd
let xhr = new XMLHttpRequest()
('get',url)
()
= function(){
()
}
}
</script>
</body>
</html>
Use of AJAX post
AJAX request using post is basically the same. But when passing parameters, there are some differences, the parameters should be placed in the body, and through () to set the format of the request information
() method is used to set the header information for HTTP requests sent by the browser. The method accepts two parameters. The first parameter is a string representing the field name of the header information, and the second parameter is the value of the field
take note of
() This method must be called after open() and before send(). If the method is called multiple times, setting the same field, the values from each call are combined and sent as a single value.
The request parameter method of str is passed
function submitForm1(){
// Get the data inside the input
uname =
('uname').value
pwd =
('pwd').value
// Splice the arguments
args = 'uname='+uname+'&pwd='+pwd
// Create the xhr object
let xhr = new XMLHttpRequest()
// Set the request method and request address
('POST','/post')
// Set the type of the request content (recommended)
('ContentType','application/x-www-form-urlencoded')
// Send the request
(args)
// Get the server response
= () => {
()
}
}
The json request parameter method is passed
function submitForm2(){
// Get the data inside the input
uname = ('uname').value
pwd = ('pwd').value
// Splice the arguments
args = {'uname':uname,'pwd':pwd}
args = (args)
// Create the xhr object
let xhr = new XMLHttpRequest()
// Set the request method and request address
('POST','/post')
// Set the type of the request content (recommended)
('ContentType','application/json')
// Send the request
(args)
// Get the server response
= () => {
()
}
}
Attention:
A get request cannot submit data in the form of a json object, and traditional web form submissions do not support json objects.
Getting the server-side response
Returns an integer representing the current state of the instance object. This attribute is read-only. It may return the following values.
0: Indicates that an XMLHttpRequest instance has been generated, but the instance's open() method has not yet been called.
1: Indicates that the open() method has been called, but the instance's send() method has not yet been called, you can still use the instance's setRequestHeader() method to set the HTTP request header information.
2: Indicates that the instance's send() method has been called and the headers and status code returned by the server have been received.
3: Indicates that the body (body part) is being received from the server. In this case, if the instance's responseType property is equal to text or an empty string, the responseText property will contain the part of the message that has been received.
4: Indicates that the data returned by the server has been fully received, or this reception has failed.
HTTP status code
attribute returns an integer indicating the HTTP status code of the server's response. Typically, the status code is 200 if the communication was successful, or 200 if the server did not return a status code; before the request was sent, the attribute was 0.
This property is read-only in events, and we specify that the task is executed when the server response is ready to be processed.
function get_data(){
// Create the xhr object
let xhr = new XMLHttpRequest()
// Set the method and address of the request
('get','/get')
// Send the request
()
// Get the server response
= () => {
// Determine if the ajax status code is 4.
if ( == 4){
// Determine if the Http status code is 200.
if ( == 200){
//()
// Convert the data to json
data = ()
(data)
}else{
// If there is no normal response, do something about it
()
}
}else{
()
}
}
}
Data format of the server-side response
In a real project, the server side will most often use JSON objects as the format of the response data.
In the process of http request and response, both request parameters and response content, if it is an object type, it will generally be converted to an object string to be transmitted
() //convert json string to json object
AJAX Error Handling
The network is open, the server side can receive the request, and the result returned by the server side is not the expected result. You can determine the status code returned by the server and process it separately. Getting the http status code
- The network is open, the server side did not receive the request and returned a 404 status.
- Check whether the request address is wrong The network is smooth, the server side can receive the request, and the server side returns a 500 status code.
- The network is down and the request cannot be sent to the server
In AJAX, set up a listener function that specializes in handling request failures: the error event (request failure) listener function.
= function()
Using AJAX in JQuery
-
jquery online address
([settings]) - type - data - data - contentType - beforSend The functions of the XMLHttpRequest object can be modified before sending the request, such as adding custom HTTP headers. object before sending the request, such as adding a custom HTTP header - success - error
-
Passing of parameters
Delivered as json
$.AJAX({ type:'post', url:'/post', data:{ name:'zs', age:18 } // parameter will be converted toname=zs&age=18 success: function(resp){ (resp) } })
Passed as str
$.AJAX({ type:'post', url:'/get', data : 'name=zs&age=18' success: function(resp){ (resp) } })
The server asks for JSON to be passed
$.AJAX({ type:'post', url:'/get', data:({ name:'zs', age:18 }) // Note that this must be converted contentType: 'application/json' success: function(resp){ (resp) } })
Use of beforeSend
Mainly used for processing before sending a request:
- Before Getting Set the div to face load...
- Validating data before submitting a form
If ture is returned in the function continue to execute the send request, if flase is returned cancel the send.
$.AJAX({
type:'post',
url:'/get',
data:{
name:'zs',
age:18
}
beforeSend:function(){
alert("Request will not be sent")
return false
}
success: function(resp){
(resp)
}
})
### Use of () and ()
#### GET request
> $.get(url,data,function(resp))
Sample Code
``js
$.get('/get',
{name:'zs',age:18},function(resp){
(resp)
})
POST request
$.post(url,data,function(resp))
sample code (computing)
$.post('/post',
{name:'zs',age:18},function(resp){
(resp)
})
Graphql
present (sb for a job etc)
GraphQL is a data query language developed internally by Facebook in 2012 and open sourced in 2015.
Its data is provided by a Scheme on the server, and the data returned by its query relies on the exact data needed by the user at the time of the request.
Official website:/
GraphQL, like RESTful, is a website architecture, a front-end and back-end communication specification that does not involve language, and different languages have different implementation options.
GraphQL is currently considered a revolutionary API tool because it allows the client to specify the data it wishes to receive in a request, unlike traditional RESTful which can only be nerdily predefined on the server side.
This way it makes the collaboration between the front and back-end teams more fluid than ever before, thus enabling the organization to function better.
In fact, both GraphQL and RESTful are based on HTTP for requesting and receiving data, and GraphQL has a lot of elements of the RESTful model built into it.
So what are the similarities and differences between the GraphQL and RESTful API models on a technical level? In the end, there's not much difference between them, except that GraphQL has made some small improvements that make a big difference in the development experience.