Chapter 11 Blog Articles

1. Model

Create a blog post model and establish a foreign key association with User

# 文章 模型
class Post (db.Model):
     __tablename__ = ' posts ' 
    id = db.Column (db.INTEGER, primary_key = True) 
    body = db.Column (db.TEXT) 
    timestamp = db.Column (db.DATETIME, = True index, default = DateTime.UtcNow) 
    the author_id = db.Column (db.INTEGER, db.ForeignKey ( ' users.id ' )) # foreign key 
    body_html = db.Column (db.Text) # converted body Field, HTML format, you can directly call 

    def  __repr__ (self):
         return self.body 

# in the templateUser model 
class User (UserMixin, db.Model):
     # to add a User attribute posts, add an author attributes to the Post, dynamic ban to run automatically 
    posts = db.relationship ( ' Post ' , backref = ' author ' , lazy = ' dynamic ' )

2. Routing

Add a route to display the post on the home page

@ main.route ( ' / ' , methods = [ ' GET ' , ' POST ' ])
 def index (): 
    form = PostForm ()
     if current_user.can (Permission.WRITE_ARTICLES) and form.validate_on_submit (): 
        post = Post (body = form.body.data, 
                    author = current_user._get_current_object ()) # current_user is provided by flask-login, and like all contexts, 
        db.session.add (post) 
        db.session.commit is 
        implemented through the proxy object in the thread () return redirect (url_for ( ' .index' ))
     # Posts = Post.query.order_by (Post.timestamp.desc ()). All () 
    # add page navigation 
    Page request.args.get = ( ' Page ' ,. 1, type = int) # request rendered obtained from request.args pages, the default 1 
    # data for display in a page, put all () is converted into paginate flask_SQLALchemy provided () method 
    # first parameter page is required, default per_page 20, error_out: If the number of pages exceeds the range, an empty list is returned. 
    # The return value of the paginate () method is an object of the Paginate class. This class is defined in flask_SQLALchemy and is used to generate pagination links in the template 
    pagination = Post.query.order_by (Post.timestamp. desc ()). paginate ( 
        page, per_page = current_app.config [ ' FLASK_POSTS_PER_PAGE ' ], error_out = False 
    )
    posts = pagination.items
    return render_template('index.html', form=form, posts=posts, pagination=pagination)

 

3. View 

{% extends "base" %}
{% import "bootstrap/wtf.html" as wtf %}
{% import "_macros.html" as macros %}



{% block title %}Flasky{% endblock %}

{% block page_content %}
<div class="page-header">
    <h1>Hello, {% if current_user.is_authenticated %}{{ current_user.username }}{% else %}Stranger{% endif %}!</h1>
</div>
<div>
    {% if current_user.can(Permission.WRITE_ARTICLES) %}
    {{ wtf.quick_form(form) }}
    {% endif %}
</div>
{% include '_posts.html' %}
{% if pagination %}
    <div class="pagination">
        {{ macros.pagination_widget(pagination, '.index') }}
    </div>
{% endif %}
{% endblock %}

 

 4. Page navigation

 The return value of the paginate () method is a Paginate class object. This class is defined in flask_SQLALchemy and is used to generate pagination links in the template.

Paginate class object properties:

  items: records on the current page

  query: paginated source query

  page: current page number

  prev_num: number of pages on the previous page

  next_num

  has_next: There is a next page for joining, return True

  has_prev

  pages: total number of pages

  per_page: the number of records displayed per page

  total: the number of records returned by the query

 Paginate class object method:

   iter_pages (): an iterator that returns a list of pages displayed in the page navigation

  prev (): the paging object of the previous page

  next()

Implement page navigation in the form of jinja2 macro:

{% macro pagination_widget(pagination, endpoint) %}
<ul class="pagination">
    <li {% if not pagination.has_prev %} class="disabled" {% endif %}>
        <a href="
        {% if pagination.has_prev %}
            {{ url_for(endpoint,page=pagination.page-1, **kwargs) }}
        {% else %}
            #
        {% endif %}">&laquo;</a>
    </li>
    {% for p in pagination.iter_pages() %}
        {% if p %}
            {% if p == pagination.page %}
                <li class="active">
                    <a href="{{ url_for(endpoint, page=p, **kwargs) }}">{{ p }}</a>
                </li>
            {% else %}
                <li>
                    <a href="{{ url_for(endpoint, page=p, **kwargs) }}">{{ p }}</a>
                </li>
            {% endif %}
        {% else %}
            <li class="disabled"><a href="#">&hellip;</a> </li>
        {% endif %}
    {% endfor %}
    <li {% if not pagination.has_next %} class="disabled" {% endif %}>
        <a href="
        {% if pagination.has_next %}{{ url_for(endpoint, page=pagination.page+1, **kwargs) }}
        {% else %}
            #
        {% endif %}">&raquo;</a>
    </li>
</ul>
{% endmacro %}

 

  5. Use Markdown and Flask-PageDown to support rich text articles

The Flask-PageDown extension defines a PageDownField class, which is consistent with the TextAreaField interface in WTForms

(1) Initialization

from flask_pagedown import PageDown

pagedown = PageDown()
pagedown.init_app(app)

 

(2) Modify the form

class PostForm(FlaskForm):
    # body = TextAreaField('what is your mind?', validators=[DataRequired()])
    body = PageDownField('what is your mind?', validators=[DataRequired()])#启用MarkDown的文章表单
    submit = SubmitField('Submit')

 

(3) Markdown preview 

Markdown previews are generated using the PageDown library. Flask-PageDown simplifies this process and provides a template macro to load required files from the CDN

{% block scripts% } 
{{super ()}} 
{{moment.include_moment ()}} 
{ # Markdown article preview is generated using the PageDown library, the following macro is loaded from the CDN, to be networked #} 
{{pagedown.include_pagedown ()}} 
{ % endblock%}

 

 

<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/pagedown/1.0/Markdown.Converter.min.js"></script>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/pagedown/1.0/Markdown.Sanitizer.min.js"></script>

 

 6. Process rich text on the server

# 文章 模型
class Post (db.Model):
     __tablename__ = ' posts ' 
    id = db.Column (db.INTEGER, primary_key = True) 
    body = db.Column (db.TEXT) 
    timestamp = db.Column (db.DATETIME, = True index, default = DateTime.UtcNow) 
    the author_id = db.Column (db.INTEGER, db.ForeignKey ( ' users.id ' )) # foreign key 
    body_html = db.Column (db.Text) # converted body Field, HTML format, you can directly call 

    def  __repr__ (self):
         return self.body 


    @staticmethod in the template
    # On_changed_body () registered in the body field, is the listeners SQLALchemy 'set' event, as long as the body field set a new value, it will automatically call the function 
    # This function is the body of the text field rendering into html format and save In body_html, complete the conversion of markdown text to HTML 
    def on_changed_body (target, value, oldvalue, initiator): 
        allowed_tags = [ ' a ' , ' abbr ' , ' b ' , ' blockquote ' , ' code ' , ' em ' , ' i ' , ' li ' ,
                         'the' , ' ol ' , ' pre ' , ' strong ' , ' h1 ' , ' h2 ' , ' h3 ' , ' p ' , ' acronym ' ]
         # 1markdown () Convert markdown text to html 
        # 2bleach.clean () Delete tags that are not in allowed_tags 
        # 3bleach.linkify () converts plain text URLs to <a> </a> links, because markdown officially does not provide support for automatic link generation 
        target.body_html = bleach.linkify (bleach.clean(
            markdown(value, output_format='html'),
            tags=allowed_tags, strip=True
        ))

 

Guess you like

Origin www.cnblogs.com/cc-world/p/12730246.html