美文网首页我爱编程
(十一)日志创建页

(十一)日志创建页

作者: 顽强的猫尾草 | 来源:发表于2018-05-23 09:38 被阅读13次

    首先安装markdown2库来支持markdown语言:

    $ sudo pip install markdown2
    $ sudo pip install pygments
    

    注意要把安装后的markdown2.py和pygments文件夹放到www文件夹下,因为我们想支持代码块以及表格等额外的markdown语言,而默认这些特性是关闭的,因此需要稍微修改一下markdown2.py

    ...
    def markdown_path(path, encoding="utf-8", html4tags=False, tab_width=DEFAULT_TAB_WIDTH,
                      safe_mode=None, extras=["fenced-code-blocks", "tables"], 
                      link_patterns=None, use_file_vars=False):
    ...
    

    需要什么就在这里找到然后填在extras后面。
    还需要下载至少一种pygments-css来支持代码颜色:

    $ git clone https://github.com/richleland/pygments-css.git
    $ cd pygments-css
    

    把makefile文件里的.highlight替换成.codehilite,接着:

    $ make cssfiles
    

    当然还要在base.html里面添加这个css文件,不然也是显示不出来的:

    <link rel="stylesheet" href="/static/css/pygments-css/murphy.css">
    

    随便选了一个,好像不太好看,有空再换一换。另外需要在三个反引号后指出用的是什么语言,不然还是不能显示出颜色...(这是后话):

    然后修改handlers.py,添加如下内容:

    • 将输入文本转化成html文本
    • 检查用户是否为管理员
    • 获取页码
    • 呈现博客内容的网页处理函数
    • 根据博客id获取博客内容的网页处理函数
    • 创建/编辑博客的网页处理函数
    • 发布博客的网页处理函数
    import markdown2
    def text2html(text):
        # 先将text去除空行,再写成html格式
        lines = map(lambda s: '<p>%s</p>' % s.replace('&', '&amp;').replace('<', '&lt;').replace('>', '&gt;'), filter(lambda s: s.strip() != '', text.split('\n')))
        return ''.join(lines)
    
    def check_admin(request):
        if request.__user__ is None or not request.__user__.admin:
            raise APIPermissionError()
    
    def get_page_index(page_str):
        p = 1
        try:
            p = int(page_str)
        except ValueError as e:
            pass
        if p < 1:
            p = 1
        return p
    
    @get('/blog/{id}')
    async def get_blog(id):
        blog = await Blog.find(id)    # 根据id查询到blog对象
        comments = await Comment.findAll('blog_id=?', [id], orderBy='created_at desc')
        for c in comments:
            c.html_content = text2html(c.content)
        blog.html_content = markdown2.markdown(blog.content)
        return {
            '__template__': 'blog.html',
            'blog': blog,
            'comments': comments
        }
    
    @get('/manage/blogs/create')
    def manage_create_blogs():
        return {
            '__template__': 'manage_blog_edit.html',
            'id': '',
            'action': '/api/blogs'
        }
    
    @get('/api/blogs/{id}')
    async def api_get_blog(*, id):
        blog = await Blog.find(id)
        # 返回到manage_blog_edit.html中, 当需要编辑旧博客时
        return blog
    
    @post('/api/blogs')
    async def api_create_blog(request, *, name, summary, content):
        check_admin(request)    # 只有管理员才可以发布博客
        if not name or not name.strip():
            raise APIValueError('name', 'name cannot be empty.')
        if not summary or not summary.strip():
            raise APIValueError('summary', 'summary cannot be empty.')
        if not content or not content.strip():
            raise APIValueError('content', 'content cannot be empty.')
        blog = Blog(
            user_id=request.__user__.id,    # app.py中把cookie2user获取到的用户赋给了request.__user__
            user_name=request.__user__.name, 
            user_image=request.__user__.image, 
            name=name.strip(), 
            summary=summary.strip(), 
            content=content.strip()
        )
        await blog.save()
        return blog
    

    然后使用MVVM模式写一个创建博客的页面templates/manage_blog_edit.html,这种模式的好处是前后端分离,逻辑清晰:

    {% extends '__base__.html' %}
    
    {% block title %}编辑日志{% endblock %}
    
    {% block beforehead %}
    <script>
        var
            ID = '{{ id }}',    // 写博客时id还未被创建
            action = '{{ action }}';
        function initVM(blog) {
            var vm = new Vue({
                el: '#vm',    // 绑定的View, 这里是#vm, 即id为vm的DOM, 对应的是一个<div>标签
                data: blog,    // JS对象表示的Model, 在下面初始化为{name:'',summary:'',content:''}
                methods: {    // View可以触发的JS函数, submit就是提交表单时触发的函数
                    submit: function (event) {
                        event.preventDefault();
                        var $form = $('#vm').find('form');
                        $form.postJSON(action, this.$data, function (err, r) {
                            if (err) {
                                $form.showFormError(err);
                            }
                            else {
                                // 提交后跳转到的地址
                                return location.assign('/blog/' + r.id);    # 跳转到日志内容页
                            }
                        });
                    }
                }
            });
            $('#vm').show();
        }
        $(function () {
            if (ID) {    //旧博客, 调出来继续编辑
                getJSON('/api/blogs/' + ID, function (err, blog) {
                    if (err) {
                        return fatal(err);    // fatal函数?
                    }
                    $('#loading').hide();
                    initVM(blog);
                });
            }
            else {    // 新博客
                $('#loading').hide();
                initVM({
                    name: '',
                    summary: '',
                    content: ''
                });
            }
        });
    </script>
    {% endblock %}
    
    {% block content %}
        <div class="uk-width-1-1 uk-margin-bottom">
            <div class="uk-panel uk-panel-box">
                <ul class="uk-breadcrumb">
                    <li><a href="/manage/comments">评论</a></li>
                    <li><a href="/manage/blogs">日志</a></li>
                    <li><a href="/manage/users">用户</a></li>
                </ul>
            </div>
        </div>
        <div id="error" class="uk-width-1-1"></div>
        <div id="loading" class="uk-width-1-1 uk-text-center">
            <span><i class="uk-icon-spinner uk-icon-medium uk-icon-spin"></i> 正在加载...</span>
        </div>
        <div id="vm" class="uk-width-2-3">
            <!-- 把提交表单的事件关联到submit方法 -->
            <form v-on="submit: submit" class="uk-form uk-form-stacked">
                <div class="uk-alert uk-alert-danger uk-hidden"></div>
                <div class="uk-form-row">
                    <label class="uk-form-label">标题:</label>
                    <div class="uk-form-controls">
                        <input v-model="name" name="name" type="text" placeholder="标题" class="uk-width-1-1">
                    </div>
                </div>
                <div class="uk-form-row">
                    <label class="uk-form-label">摘要:</label>
                    <div class="uk-form-controls">
                        <textarea v-model="summary" rows="4" name="summary" type="text" placeholder="摘要" class="uk-width-1-1" style="resize:none;"></textarea>
                    </div>
                </div>
                <div class="uk-form-row">
                    <label class="uk-form-label">内容:</label>
                    <div class="uk-form-controls">
                        <textarea v-model="content" rows="16" name="content" type="text" placeholder="内容" class="uk-width-1-1" style="resize:none;"></textarea>
                    </div>
                </div>
                <div class="uk-form-row">
                    <button type="submit" class="uk-button uk-button-primary"><i class="uk-icon-save"></i> 保存</button>
                    <a href="/manage/blogs" class="uk-button"><i class="uk-icon-times"></i> 取消</a>
                </div>
            </form>
        </div>
    {% endblock %}
    

    注意我们默认注册的时候都不是admin账户,需要在数据库中修改权限:



    之所以admin两边要加反引号是因为admin是数据库的关键字,要避免冲突,不然会报“Error 1064”错误。
    然后登陆这个账户才是管理员权限,可以写博客。

    相关文章

      网友评论

        本文标题:(十一)日志创建页

        本文链接:https://www.haomeiwen.com/subject/jhplwxtx.html