Flask Wolf Book Notes | 08_Personal Blog (Part 1)

Please add image description

8 personal blogs

A personal blog is a typical CMS (content management system), which usually consists of a front-end and a back-end. This one will cover more advanced project organization , as well as some new Python packages: Flask-Login , Unidecode .

8.1 Large Project Structure

In this chapter, you will learn to use blueprints and factory functions to further organize Flask programs. When there is too much code in a module, a common practice is to upgrade the single module to a package . The directory structure of the new version is as follows:

blueblog/
	blueprints/
		- __init__.py
		- blog.py
		- auth.py
		- admin.py
	templates/
		- admin/
		- auth/
		- blog/
		- base.html
		- macros.html
	static/
	__init__.py
	forms.py
	models.py
	...

Blueprints provide more powerful code organization capabilities and can modularize code at the program function level, not just at the code organization level.

1. Use blueprint modular programs

We can register routes, functions, etc. for the blueprint instance. The use is very similar to the program instance, but it is actually different. The blueprint is just a model . Only by attaching the operations in the blueprint to the program can these operations be effective.

  • Create a blueprint :
auth_bp = BluePrint('auth', __name__)

Use errorhandler()decorators to register error handling functions on the blueprint. You can also register view functions, request processing functions, and template context processing functions on the blueprint. At this time, they only work locally in the blueprint. (p223)

  • Registration blueprint :

The blueprint must be registered to the program instance in order to function. url_prefixAdd a url prefix to all view functions registered on the blueprint.

app.register_blueprint(auth_bp, url_prefix='/auth')

View all routes registered by the current program :flask route

  • Endpoint : 蓝本.视图函数名The method used to access it.
  • Resources :

static/Upgrading a blueprint module to a package allows you to create folders and templates/folders within it that are unique to the blueprint . You need to specify them when creating a blueprint:

auth_bp = Blueprint('auth', __name__, static_folder='static', templates_folder='templates')

2. Use class organization configuration

Configurations can be written as class attributes, and different configuration combinations can be derived through inheritance .

class BaseConfig(object):
    SECRET_KEY = ...
    ...
    
class DevelopmentConfig(BaseConfig):
    ...

config = {
    
    
    'base': BaseConfig,
    'development': DevelopmentConfig
}

Then import the configuration from the class:

config_name = os.getenv('FLASK_CONFIG', 'development')
app.config.from_object(config[config_name])

3. Use factory functions to create program instances (p229)

The factory function here, that is, the return value of the function is a program instance, which can be used to create a program instance anywhere.

def create_app(config_name=None):
    ...
    app = Flask('bluelog')
    app.config.from_object(config[config_name])
    
    app.register_blueprint(blog_bp)
    return app

When instantiating an extension object, you need to pass in appa program instance, but using the factory function does not have a created program instance to pass in (and there is no need to have one). Extension objects generally provide init_app()methods to create extension objects in other modules and then complete initialization in factory functions.

Start the program : When flask runthe command is running, it will look for a factory function named create_app()or at the location specified by FLASK_APP, and automatically call the factory function to create a program instance.make_app()

current_app : Properties unique to the program instance can be called outside the factory function, such as app.config. When an instance is created and run, it automatically points to the program instance and forwards operations to the instance.

8.2 Writing program skeleton

In the notes of this chapter, I will mainly record some small points that need attention, which will be relatively scattered.

The functions of BlueBlog in this book are divided into three parts: blog front-end, user authentication, and blog back-end.

1. Database

  • adjacency list relationship

Comments in the blog program must support replies, and the reply itself can be counted as a type of comment, so we can define a one-to-many relationship within the model , and each comment object can contain multiple sub-comments (replies).

class Comment(db.Model):
    ...
    replied_id = db.Column(db.Integer, db.ForeignKey('comment.id'))
    
    replied = db.relationship('Comment', back_populates='replies', remote_side=[id])
    replies = db.relatoinship('Comment', back_populates='replied', cascade='all')

Since both sides of the relationship are in the same model, SQLAlchemy cannot tell the two sides of the relationship (should mean at the time of the call relationship). remote_side=[id]Setting ida field to the remote siderelationship of the relationship makes the field act as the local side of the relationship . That is, the field is regarded as an attribute of the "many" side of the relationship (a one-to-many relationship always defines a foreign key on the "many" side).replied_idreplied

This section seems a bit convoluted, but I feel it is more important.

  • Generate dummy data : (p236)

2. Template

Theme : In addition to using the default style of Bootstrap, some websites also provide many free themes, such as Bootswatch and StartBootstrap. (p242)

  • Template context : The data used in the base template. In order to avoid passing it in once in each view function (trouble), you can register the template context processing function.
@app.context_processor
def make_template_context():
    ...
    return dict(...)

The method I used before was to store data session, such as user name and user id, to determine the login status.

  • Render navigation links : Buttons on the navigation bar should show active status on the corresponding page. This can be achieved by determining the endpoint of the request (p244) and can be wrapped into a macro . However, Bootstrap-Flask already provides a macro: render_nav_item().

Common parameters of render_nav_item() macro : (p245)

  • Flash message classification : the category of messages that can be passed in when calling the flask() function, see (p245)

3. Form

  • The options (ie <option>labels) of the drop-down list are specified through the parameter choices. (p247)
  • The name of "category" cannot be repeated, and an inline validator can be defined. (p248)
  • Use Optionalvalidators to make fields nullable.

4. Email support

How to send emails has been introduced in the previous chapter. But if you use an asynchronous method to send emails, since our program instance is built in factory mode, a real program object is required to create a context when creating a new thread.

app = current_app._get_current_object() # 获取被代理的真实对象

8.3 Writing the blog frontend

1. Display the article list in pages

  • Cut the beginning of the text : Use truncatea filter.
  • Pagination

all()By changing paginate()the query execution function from (p254)

page = request.args.get('page', 1, type=1)  # 获取哪一页的数据
per_page = 10  # 每一页的数量
pagination = Post.query.paginate(page, per_page=per_page)
posts = pagination.items()

Attributes of the Pagination class: (p255)

  • Render the pagination widget

You can simply set two buttons for the previous page and next page, or you can use render_page()the or render_paginationmacro provided by bootstrap.

2. Display the article text

If a rich text editor is used, the style of the body content is implemented through HTML tags, and jinja2 will automatically filter out the HTML code in the text by default. You need to use safea filter to let jinja2 render these texts as html code.

  • Article permalink

The link of the article often looks like http://example.com/post/120this. The article id=120 is used in the background to query the article. You can also use a more readable link, such as replacing the id with the title of the article. (p259)

If you want to share articles conveniently, you can provide a one-click function to copy the article link. Alternatively, use the sharing API provided by the social networking site, or directly use a third-party social sharing service.

3. Display the comment list

Comments can be set at the bottom of the article page, you can add a paging navigation to the comments, and you can also use keywords to add URL fragmentsfragment to the links of the paging buttons . In this way, after adjusting to another page of comments, it will automatically jump to the comment area below the article (rather than manually sliding from the article title to the comment area below).

{
   
   { render_pagination(pagination, fragment='#comments') }}

url_for() and query strings : When using url_for()functions to build URLs, any extra keyword arguments are automatically converted into query strings. Use request.argsto get the query string.

4. Website theme switching

Different css files can be loaded according to the user's selection to achieve theme switching. This theme option can be stored in a cookie because each user will have different choices.


Guess you like

Origin blog.csdn.net/m0_63238256/article/details/132863544