Flask Programming Summary - Fish Book Project

Disclaimer: This article is a blogger original article, shall not be reproduced without the bloggers allowed. https://blog.csdn.net/qq_29027865/article/details/89811316

A. Flask rationale

View function

fisher.py

© view function definitions

By decorator to define a route to a function, which can be accessed via http request to the function;

The view function is difficult to achieve code multiplexing based;

from flask import Flask
app = Flask(__name__)
@app.route('/hello')
def hello()
    return 'hello'
app.run()

The only principle url

The need to ensure a unique url, without / can be guaranteed to be unique url, but is not compatible with the user's input, it can be compatible with the user's input in the rule:

@app.route('/hello/')

The new code changes to the server must be restarted under the new code changes take effect;

The only principle of nature url - redirects

Principle compatible with or without / of: processing substantially different url is to do a redirect, redirect the principle of access between the browser and the server:

  1. In a normal access process, url1 browser access resources accessible, the server after receiving the request, the url1 resources returned to the browser, and the status code is set to 200;

    1. But in the redirection process, the browser to access the resources url1, for some reason, the server does not url1 or do not want to let you access url1, this time will be location field is set in the information returned by the server to the browser in the address url2 and the return status codes to 301 or 302, when receiving the browser will redirect url to obtain information according to a state code, and sends a request to url2 again.

Open flask Automatic Server Restart

The flask mode is set to debug mode, you can start the flask server automatically restart. Method to open the debug mode is the debug parameter passed in app.run method, and set it to true:

app.run(debug=True)

Another benefit of open debug mode is that it can be accessed abnormal operation;

Routing Registry

A method by decorators to register (decorator without adding view_func parameters) (recommended)

@app.route('/hello')
def hello()
 return 'hello'

Method two methods to register through the app (if you are using plug view, it is necessary to add a way to use to register)

def hello()
 return 'hello'
# 第一个参数指定路由链接,第二个参数指定视图函数
app.add_url_rule('/hello',view_func=hello)

The difference between the two methods is to be routed without specifying view_func registered by decorators method, because the decorator itself is defined to be in front of the decorated function. If the view is based on the use of the class, i.e. plug view of the method, it is necessary to use add_url_rule register.

app.run relevant parameters

app.run default server is running, only the local machine or a LAN can access, you can app.run method host attribute to the url external network access.

# host如果定为固定的ip地址,则只有那一个可以访问
app.run(host='0.0.0.0',debug=True,port=81)

flask profile

The most basic principle of the deployment is to ensure that the source code in the source code and production environments in our development environment must be a mirror image relationship, that is the same as two source code.

Then the solution is to profile config.py :

DEBUG = True

Method a: When using the configuration file, which was introduced as a module to come:

from config import DEBUG
app.run(host='0.0.0.0',debug=DEBUG,port=81)

Option two: app approach to introducing:

# 配置文件载入:方法需要接受一个模块的路径
app.config.from_object('config')
# 配置文件读取:
# config本身就是字典dict的一个子类
app.run(host='0.0.0.0',debug=app.config['DEBUG'],port=81)

Note: If you are using from_object to load, then DEBUG requirements need to be capitalized. But if you do not define the DEBUG parameter in the configuration file, it will not run error, because DEBUG default value is false in the flask.

== if__name__ ' main ' means:

In the development environment, the server is running flask comes with a very simple server, but when the project will be deployed to a production environment, we usually do not use the flask comes with the server, usually using nginx + uwsgi, nginx as front server to accept a request sent by the browser, and then forwards the request to our uwsgi. In the project, instead of executing a program run by direct, but to start the flask relevant code by fisher uwsgi load module.

if __name__ == '__main__':
               app.run(host='0.0.0.0',bebug=app.config['DEBUG'],port=81)

In a production environment fisher files are no longer import documents, it's just loaded uwsgi module files, so in a production environment, app.run that will not be executed. If there is no name = main judgment, once the file is loaded fisher, app.run will be executed in a production environment, we have started the uwsgi as our server, then we started app.run as our built-in server , two servers is not possible. But then he joined the main, we can guarantee that will not start flask own web server in a production environment. (Running to enter the main function of the test environment)

Response object Response

return return normal function and view function What is the difference?

view function return, will do a series of Flask encapsulated in the back, i.e. in addition to the defined content returned string is also returned status code, content-type;

content-type attribute is placed in the http headers of, content-type http request to tell the recipient how to resolve our main content.

For the view function, content-type default value is "text / html", which will guide the browser as html tags to parse html.

When you return a simple string in the view function, flask will string as the main content of the response, and the subject matter for the Response object package, so for the view function always returns a Response object.

from flask import Flask,make_response
def hello():
    # 修改content-type让其显示
    headers = {
        'content-type':'text/plain'
    }
    response = make_response('<html></html>',404)
    response.headers = headers
    return response

Returns a string web is the essence, the essence of which is to control the content-type;

You can not create a response object itself:

from flask import Flask,make_response
def hello():
    return '<html></html>',301

II. Flask routing data

The basic objectives and functions

The goal is complete: As a person who presented the book, presented to you in the end Which book;

Book search function consists of two parts, one is the keyword search, and the other is a search pursuant isbn. The books book information is not local data sources, but rely on external data sources, to obtain the data through external API.

Consider the client to pass parameters

What you need to pass parameters

The client needs to be passed down to us to think what kind of parameters, the client parameter passed to us eventually to use an external API, so first look at the exterior of the API and what kind of parameters accepted.

So here, API interface to search for keywords:

http://t.yushu.im/v2/book/search?q={}&start={}&count={}

Interface isbn search for:

http://t.yushu.im/v2/book/isbn/{isbn}

Interfaces to distinguish between different search methods

After you find out about the interface, whether it requires the user to search by distinguishing different it? That is, after users choose to use subjective or isbn keyword search, enter a search. Obviously this is not necessary, we can deal with their own internal logic judgment, unified search interface.

Accept parameters transmitted in the user view the function

First in the simplest possible way, namely by means of parameter passing to url path defined by <> in the form of route, it can be identified as a content parameter string is not fixed.

Note: When writing multiple conditional statements, there are two principles: the first principle is: should a large probability of false conditional on the front, so once the front judged to be false after, the judge will not be back and then executed, so that the efficiency of code execution speed up; the second principle is: the more time-consuming operation on the back;

@app.route('/book/searc h/<q>/<page>')
def search(q,page):
    # q:普通关键字,isbn关键字
    # page
    #isbn有isbn13和isbn10两种方式:13表示由13个0-9                          之间的数字组成,isbn10表示是10个0到9数字组成,含有一些'-';   
    isbn_or_key = 'key'
    if len(q) == 13 and q.isdigit():
        isbn_or_key = 'isbn'
    short_q = q.replace('-','')
    if '-' in q and len(short_q) == 10 and short_q.isdigit:
        isbn_or_key = 'isbn'
    pass 

Refactoring

The code bad place:

  1. Analyzing too conditional logic statements;

  2. Reuse can not be achieved;

  3. Codes are usually read from the controller or the view function-based, so the view or controller function should be reflected in this piece is what to do;

So a better solution is to wind these logical functions give you a claw and then call it in the view function.

Helper.py new module in the package file constructor:

def is_isbn_or_key(word)
    isbn_or_key = 'key'
    if len(q) == 13 and q.isdigit():
        isbn_or_key = 'isbn'
        short_q = q.replace('-','')
    if '-' in q and len(short_q) == 10 and     short_q.isdigit:
        isbn_or_key = 'isbn'
    return isbn_or_key

Then call this logic function fisher.py file:

from helper import is_isbn_or_key

The view function is a starting point for beginning web project, so make sure the view is a simple function of the code in the appropriate reading.

See the source code to see the stratification of the first layer is to know what function do enough, clear rationale and structure of the entire source code for clues.

and code for sending an http request requests simplified means

Py in the access API, namely transmission url http request, we can define http modules, classes in the package module to achieve this function.
API is done according to the standard API for restful fish book, those who restful API that have followed certain rules.
Defined http.py file in the same module

from urllib import request
import requests
class HTTP:
    def get(self, url, return_json=True):
        r = requests.get(url)
        if r.status_code == 200:
            if return_json 
                return r.json()
            else:
                return r.text
        else:
            if return_json:
                return {}
            else:
                return ''

Simplify the wording:

class HTTP:
    def get(self, url, return_json=True):
        r = requests.get(url)
        if r.status_code != 200:
            return {} if rerurn_json else ''
        return r.json() if return_json else r.text

Do not directly straightforward to write if-else, this will make the code appears to be too long, summed up under the simplified method if-else of:

  1. Using ternary expressions with simplified if-else wording;

  2. Use if + return to simplify the code written;

    if + 2 th return later in the return process can be understood as a special case of normal flow;

Http request to call functions in the view class

In view of the tile in the function write business logic code is not a good practice, it is possible to package the whole process request as a class: a new module file in the package fisher yushu_book.py, and build a new class YuShuBook, followed by the encapsulate business logic into this class.
Because there isbn query keyword query and query, these two methods of inquiry and not the same, so we can define two methods to accomplish.
Since the definition of a class, it will have to fulfill their duties of API requests, so the way to pass parameters is not a good practice (search_by_isbn (self, url) is not good). So we can put the url defined in the class attribute or class variables in process, where if we consider an instance method, this argument is self itself does not make sense, so we can change it to a static method.

from http import HTTP
class YuShuBook:
    isbn_url = 'http://t.yushu.im/v2/book/isbn/{}'
    keyword_url = 'http://t.yushu.im/v2/book/search?q={}&start={}&count={}'
    @classmethod
    def search_by_isbn(cls, isbn):
        # 通过类名访问类变量
        url = YuShuBook.isbn_url.format(isbn)
        # 定义为类方法后,就可以通过cls来访问方法或变量
        url = cls.isbn_url.format(isbn)
        result = HTTP.get(url)
        return result
    @classmethod
    def search_by_keyword(cls,keyword,count=15,start=0):
        url = YuShuBook.keyword_url.format(keyword,count,start)
        result = HTTP.get(url)
        return result    

Next, we use two methods in view of the function packages:
(performed by alt + enter key tips passthrough packets)

def search(q,page):
    isbn_or_key = is_isbn_or_key(q)
    if isbn_or_key == 'isbn':
        result = YuShuBook.search_by_isdn(q)
    else:
        result = YuShuBook.search_by_keyword(q)
        # dict序列化
       return json.dumps(result),200,{'content-type':'application/json'} 

jsonify

In the content delivery front json lengthy comparison, here we json to process the contents of a particular method jsonify flask, which is somewhat similar to the functionality of the API: the data back to the client to go through json format.

return jsonify(result)

The split view function to separate file

Not recommended to view all functions in a file:

  1. Into a file, the code is too long, not easy to maintain;
  2. From the perspective of the business model in terms of different business models should be assigned to a different file to go;

Now we have to design the directory structure of files:
- Fisher
fisher.py
- App
- web
---- book.py
then moved to the view functions to our web directory, for web.py :

@app.route('/book/searc h/<q>/<page>')
def search(q,page):
    isbn_or_key = is_isbn_or_key(q)
    if isbn_or_key == 'isbn':
        result = YuShuBook.search_by_isdn(q)
    else:
        result = YuShuBook.search_by_keyword(q)
    # dict序列化
    return jsonify(result)

So now there is a problem, how do we import core objects app to book this file to use it?
We thought before the next review: Before the view function on the fisher, py this startup file, and then we start the file instantiating the flask core objects, and then they can use our core object directly below. But now as you move the files, no way to directly use the core object, and then the next we consider are:

  1. To import core objects start-up files to book in use (Results -> will report a 404 error)
    but there must be clear that we are fisher.py as a boot file, rather than book.py file, then book referenced in the core objects, can only guarantee the associated book a fisher, but at run-time fisher, book files will still not implemented. So after the execution will still report 404 errors.
  2. And then view the import function module startup files (Results -> still 404 error)
    in the plus after fisher.py instantiate objects flask statement: from app.web Import Book, the startup file does run the view function, but will still It reported 404 errors.
# fisher.py
from flask import jsonify
from helper import is_isbn_or_key
from yushu_book import YuShuBook
from fisher import app

app = Flask(__name__)
app.config.from_object('config')

from app.web import book

if __name__ == '__main__':
	print(id(app))
    app.run(host='0.0.0.0', debug=app.config['DEBUG'], port=81)

This clearly wrong issue 404, we need to have a mechanism for routing flask-depth understanding:
First of all, the client (or should we say postman), how we ultimately have access to this view Search function via url address. It is easy to think of is to map a dictionary, that dictionary of key represents the url, the dictionary value represents the view function.
In addition to the flask and the corresponding url view function, there is an intermediate endpoint. endpoint is configured to reverse the url.
How can a success registered routing? First urlmap, the map object must have a point to our search, as well as view-functions must record search on a view function point to which it points. When such a request into the interior of the flask, it will ultimately find our view function through url, to invoke the view function.
Be a second 404 for the wrong reasons is that we are a circular reference when calling.

Guess you like

Origin blog.csdn.net/qq_29027865/article/details/89811316