• Flask 学习 十二 用户评论


    评论在数据库中的表示

    由于评论和2个模型有关系,分别是谁发了评论,以及评论了哪个文章,所以这次要更新数据库模型

    models.py 创建用户评论数据库模型

    class Comment(db.Model):
        __tablename__ = 'comments'
        id = db.Column(db.Integer, primary_key=True)
        body = db.Column(db.Text)
        timestamp = db.Column(db.DateTime,index=True,default=datetime.utcnow)
        body_html = db.Column(db.Text)
        disabled = db.Column(db.Boolean) # 管理员用来查禁不当评论
        author_id = db.Column(db.Integer, db.ForeignKey('users.id'))
        post_id = db.Column(db.Integer,db.ForeignKey('posts.id'))
    
        @staticmethod
        def on_changed_body(target,value,oldvalue,initiator):
            allowed_tags=['a','abbr','acronym','b','code','em','i','strong']
            target.body_html=bleach.linkify(bleach.clean(markdown(value,output_format='html'),tags=allowed_tags,strip=True))
    db.event.listen(Comment.body,'set',Comment.on_changed_body)

    User和Post里面也要和Comment设置相应的关系

    class User(db.Model):  
    # ...  
    comments = db.relationship('Comment', backref='author', lazy='dynamic')  
    class Post(db.Model):  
    # ...  
    comments = db.relationship('Comment', backref='post', lazy='dynamic')  

    提交和显示评论

    main/forms.py 创建评论输入表单

    class CommentForm(FlaskForm):
        body = StringField('输入你的评论',validators=[DataRequired()])
        submit = SubmitField('提交')

    为支持评论更新路由post

    main/views.py 支持博客文章评论

    # 文章固定链接
    @main.route('/post/<int:id>', methods=['GET', 'POST'])
    def post(id):
        post = Post.query.get_or_404(id)
        form = CommentForm()
        if form.validate_on_submit():
            # current_user(上下文代理对象)._get_current_object() 真正的User对象
            comment = Comment(body=form.body.data,
                              post=post,
                              author=current_user._get_current_object())
            db.session.add(comment)
            flash('你已经发布了新评论.')
            # page设为-1,用来请求评论的最后一页,刚提交的评论才会出现在页面中
            return redirect(url_for('.post', id=post.id, page=-1))
        page = request.args.get('page', 1, type=int)
        # 程序获取页数,发现时-1时,会计算总量和总页数得出真正显示的页数
        if page == -1:
            page = (post.comments.count() - 1) // 
                current_app.config['FLASKY_COMMENTS_PER_PAGE'] + 1
        pagination = post.comments.order_by(Comment.timestamp.asc()).paginate(
            page, per_page=current_app.config['FLASKY_COMMENTS_PER_PAGE'],
            error_out=False)
        comments = pagination.items
        return render_template('post.html', posts=[post], form=form,
                               comments=comments, pagination=pagination)

    评论模板 _comment.html

    <ul class="comments">
        {% for comment in comments %}
        <li class="comment">
            <div class="comment-thumbnail">
                <a href="{{ url_for('.user', username=comment.author.username) }}">
                    <img class="img-rounded profile-thumbnail" src="{{ comment.author.gravatar(size=40) }}">
                </a>
            </div>
            <div class="comment-content">
                <div class="comment-date">{{ moment(comment.timestamp).fromNow() }}</div>
                <div class="comment-author"><a href="{{ url_for('.user', username=comment.author.username) }}">{{ comment.author.username }}</a></div>
                <div class="comment-body">
                    {% if comment.body_html %}
                        {{ comment.body_html | safe }}
                    {% else %}
                        {{ comment.body }}
                    {% endif %}
                </div>
            </div>
        </li>
        {% endfor %}
    </ul>

    评论引入post.html

    {% extends "base.html" %}
    {% import "bootstrap/wtf.html" as wtf %}
    {% import '_macros.html' as macros %}
    {% block title %}Flasky - 文章{% endblock %}
    
    {% block page_content %}
    {% include '_posts.html' %}
    
    <h4 id="comments">评论</h4>
    {% if current_user.can(Permission.COMMENT) %}
        <div class="comment-form">
            {{ wtf.quick_form(form) }}
        </div>
    {% endif %}
    {% include '_comments.html' %}
    {% if pagination %}
        <div class="pagination">
            {{ macros.pagination_widget(pagination, '.post', fragment='#comments', id=posts[0].id) }}
        </div>
    {% endif %}
    {% endblock %}

    上面加在 _posts.html里面的这段话,在url地址后面,加了一个 #comments

    这个叫做URL片段

    可以理解为:#这个符号,在URL地址里面相当于分隔符

    #左边的,代表真实URL,对外的,就是普通用户可以看到的URL

    #右边的,代表对网页内部的代码,在浏览器的地址栏是看不到的,他针对的是,当前页面HTML文件内,id=comments的内容

    具体作用是:当加载这个页面时,直接会将这个id处于的位置,滚到页面顶端

    类似于平时的用户体验是:当评论完以后,页面重新加载,评论区域会自动翻滚到页面最上端,体验很好。

    按了comments按钮以后,可以直接跳转到post页面的评论区域,等于是个页中页功能。

    链接到博客的评论_post.html

    <a href="{{ url_for('.post', id=post.id) }}#comments">
       <span class="label label-primary">{{ post.comments.count() }} 评论</span>
    </a>

    user.html 增加评论数

    <p><b> 评论数量:</b>{{ user.comments.count() }}.</p>

    _macro.html 宏需要加入片断参数

    {% macro pagination_widget(pagination,endpoint,fragment='') %}
    <ul class="pagination">
        <li {% if not pagination.has_prev %}class="disabled" {% endif %}>
            <a href="{% if pagination.has_prev %}{{ url_for(endpoint,page = pagination.prev_num,**kwargs) }}{{ fragment }}{% 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) }}{{ fragment }}">{{ p }}</a>
                </li>
                {% else %}
                <li>
                    <a href="{{ url_for(endpoint,page=p,**kwargs) }}{{ fragment }}">{{ 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.next_num,**kwargs) }}{{ fragment }}{% else %}#{% endif %}">
            &raquo;
            </a>
        </li>
    </ul>
    {% endmacro %}

     管理评论

    base.html加入评论管理导航条

    {% if current_user.can(Permission.MODERATE_COMMENTS) %}
    <li>
        <a href="{{ url_for('main.moderate') }}">评论管理</a>
    </li>
    {% endif %}

    main/views.py 管理评论路由

    @main.route('/moderate')
    @login_required
    @permission_required(Permission.MODERATE_COMMENTS)
    def moderate():
        page = request.args.get('page', 1, type=int)
        pagination = Comment.query.order_by(Comment.timestamp.desc()).paginate(
            page, per_page=current_app.config['FLASKY_COMMENTS_PER_PAGE'],
            error_out=False)
        comments = pagination.items
        return render_template('moderate.html',comments=comments,pagination=pagination,page=page)

    moderate.html 评论管理页面模板

    {% extends "base.html" %}
    {% import '_macros.html' as macros %}
    {% block title %}Flasky - 评论管理{% endblock %}
    
    {% block page_content %}
        <div class="page-header">
            <h1>评论管理</h1>
        </div>
        {% set moderate = True %} # 决定是否渲染评论管理功能
        {% include '_comments.html' %}
        {% if pagination %}
        <div class="pagination">
            {% if pagination %}
        <div class="pagination">
            {{ macros.pagination_widget(pagination, '.moderate') }}
        </div>
    {% endif %}
        </div>
    {% endif %}
    {% endblock %}

    _comments.html 评论正文

     <div class="comment-body">
                    {% if comment.disabled %}
                        <p><i>此评论已被管理员禁用</i></p>
                    {% endif %}
                    {% if moderate or not comment.disabled %}
                        {% if comment.body_html %}
                            {{ comment.body_html | safe }}
                        {% else %}
                            {{ comment.body }}
                        {% endif %}
                    {% endif %}
                </div>
                {% if moderate %}
             <br> {% if comment.disabled %}
    <a class="btn btn-default btn-xs" href="{{ url_for('.moderate_enable',id=comment.id,page=page) }}">恢复</a> {% else %} <a class="btn btn-default btn-xs" href="{{ url_for('.moderate_disable',id=comment.id,page=page) }}">禁用</a> {% endif %} {% endif %}
    </div>

    main.views.py 评论管理路由

    @main.route('/moderate/enable/<int:id>')
    @login_required
    @permission_required(Permission.MODERATE_COMMENTS)
    def moderate_enable(id):
        comment = Comment.query.get_or_404(id)
        comment.disabled = False
        db.session.add(comment)
        return redirect(url_for('.moderate',page=request.args.get('page',1,type=int)))
    
    @main.route('/moderate/disable/<int:id>')
    @login_required
    @permission_required(Permission.MODERATE_COMMENTS)
    def moderate_disable(id):
        comment = Comment.query.get_or_404(id)
        comment.disabled = True
        db.session.add(comment)
        return redirect(url_for('.moderate',page=request.args.get('page',1,type=int)))
  • 相关阅读:
    [SQL Server]分页功能的实现
    [Others]每个文件夹都具有的特殊文件夹
    [ASP.NET]使页面的大小适合打印尺寸
    [SQL Server]树形结构的创建
    [ASP.NET]获取用户控件对象的引用
    [SQL Server]关于15517号错误的一点想法
    [SQL Server]创建自定义聚合函数值得注意的问题
    Java开源BI商业智能工具
    电子商务网站搜索架构方案
    产品经理如何培养对市场的敏感度和洞察力?
  • 原文地址:https://www.cnblogs.com/Erick-L/p/6938009.html
Copyright © 2020-2023  润新知