文档章节

Flask开发轻博客(六):用户首页和发布博客

AllenOR灵感
 AllenOR灵感
发布于 2017/09/10 01:23
字数 2475
阅读 0
收藏 0
点赞 0
评论 0

目录

Flask开发轻博客(一):欢迎来到 Flask 的世界

Flask开发轻博客(二):Flask 模板

Flask开发轻博客(三):Flask 的 Web 表单

Flask开发轻博客(四):数据库

Flask开发轻博客(五):用户登录

Flask开发轻博客(六):用户首页和发布博客

Flask开发轻博客(七):分页


上节回顾

上一章中,我们已经完成了登录系统,因此我们可以使用昵称或邮件登录以及登出。

今天,我们将要完成个人信息页。首先,我们将创建用户信息页,显示用户信息以及最近的 blog。作为其中一部分,我们将会学习到显示用户头像。接着,我们将要用户 web 表单用来编辑用户信息

一、用户信息首页

创建一个用户信息不需要引入新的概念。我们只要创建一个新的视图函数以及与它配套的 HTML 模版。

添加用户信息类,并定义用户信息字段(修改forms.py文件):

class AboutMeForm(Form):
    describe = TextAreaField('about me', validators=[
        Required(), Length(max=140)])
    submit = SubmitField('YES!')

添加用户新信息的视图函数(文件 app/views.py )

@app.route('/user/<int:user_id>', methods=["POST", "GET"])
@login_required
def users(user_id):
    form = AboutMeForm()
    user = User.query.filter(User.id == user_id).first()
    if not user:
        flash("The user is not exist.")
        redirect("/index")
    blogs = user.posts.all()

    return render_template(
        "user.html",
        form=form,
        user=user,
        blogs=blogs)

我们用于这个视图函数的装饰器与之前的有些不同。在这个例子中,我们有一个 参数 在里面,用 <int: user_id> 来表示。这将转化为一个同名的参数添加到视图函数。比如当客户端以URL /user/1 请求的时候,视图函数将收到一个 user_id = 1参数从而而被调用。

视图函数的实现没有让人惊喜的。首先,我们使用接收到参数 user_id 试着从数据库载入用户。如果没有找到用户的话,我们将会抛出错误信息,重定向到主页,我们还添加了@login_required装饰器,如果没有登陆的用户,向通过URL直接访问该页面,那么我们会直接在页面上报错,阻止其访问。

一旦我们找到用户,我们把它传入到 render_template 调用,并且传入user.posts.all()找出的该用户的blogs。注意如果没有找到用户,模板会显示小小的提示The user is not exist.,并跳转到主页。

我们最初的视图模版是十分简单的(创建文件 app/templates/user.html )

{% extends "base.html" %}

{% block content %}
<p>Name: {{ user.nickname }}</p>
<p>Email: {{ user.email }}</p>

<hr>
{% if blogs | length %}
    {% for blog in blogs %}
    <p>{{ blog.body }}</p>
    <p>{{ blog.timestamp.strftime("%a, %d %b %Y %H:%M:%S") }}</p>
    <hr />
    {% endfor %}
{% else %}
    <p style="color:blue;">the guy is so lazy.....</p>
{% endif %}
{% endblock %}

用户信息页现在已经完成了,但是缺少对它的链接。为了让用户很容易地检查他的或者她的信息,我们直接把用户信息页的链接放在导航栏中(修改文件 app/templates/base.html)

<div>Microblog: 
    <a href="{{ url_for('index') }}">Home</a>
    {% if not current_user.is_authenticated() %}
    | <a href="{{ url_for('login') }}">Log in</a>
    or <a href="{{ url_for('sign_up') }}">Sign up</a>
    {% else %}
    | <a href="{{ url_for('users', user_id = current_user.id) }}">Profile</a>
    | <a href="{{ url_for('logout') }}">Logout</a>
    {% endif %}
</div>

试试应用程序吧。注册登陆后点击导航栏中的个人资料链接,会把你带到用户信息页。但是我们还没有添加博客发布页面,所以可能会出现:the guy is so lazy.....


二、博客发布

好的,我们就下来就来实现 publish blogs 的功能。

首先在 forms.py 文件中添加博客内容的字段:

class PublishBlogForm(Form):
    body = TextAreaField('blog content', validators=[Required()])
    submit = SubmitField('Submit')

并我们需要在app/views.py中加入如下函数:

from string import strip
import datetime

from forms import LoginForm,  SignUpForm, AboutMeForm, PublishBlogForm

@app.route('/publish/<int:user_id>', methods=["POST", "GET"])
@login_required
def publish(user_id):
    form = PublishBlogForm()
    posts = Post()
    if form.validate_on_submit():
        blog_body = request.form.get("body")
        if not len(strip(blog_body)):
            flash("The content is necessray!")
            return redirect(url_for("publish", user_id=user_id))
        posts.body = blog_body
        posts.timestamp = datetime.datetime.now()
        posts.user_id = user_id

        try:
            db.session.add(posts)
            db.session.commit()
        except:
            flash("Database error!")
            return redirect(url_for("publish", user_id=user_id))

        flash("Publish Successful!")
        return redirect(url_for("publish", user_id=user_id))

    return render_template(
        "publish.html",
        form=form)

同样接收当前用户的user_id用于填充Post表的user_id字段,以便在用户主页显示该用户所属的blogs。为了防止blog内容为空,除了在forms.py里添加validator的限制外,我们还要在后台再一次对输入数据的验证strip(blog_body)就是为了防止用户只输入空格的情况,它会将字符串两边的空格去掉,如果内容仅仅为空格的话,那么长度肯定是为0的,一旦这种事情发生了,就立即报错,并刷新当前页面。

将数据库的对应的字段赋值完毕之后,使用db.session.add(posts)db.session.commint()将值写入数据库中,因为操作数据库的时候可能会出现一些意想不到的问题,所以我们应该用try....except....
来处理这些问题,提高适用性。

publish的页面十分的简单,只是需要一个TextAreaFiled,和submit就行了。(app/publish.html)

{% extends "base.html" %}

{% block content %}
<form action="{{ url_for("publish", user_id=current_user.id) }}" method="POST" name="publish">
    {{ form.hidden_tag() }}
<p>{{ form.body }}</p>
<p>{{ form.submit }}</p>
</form>
{% endblock %}

效果图如下:


三、在子模板中重用

 1. 非常实用的小技巧

我们已经实现了用户信息页,它能够显示用户的 blog。我们的首页也应该显示任何一个用户这个时候的 blog 。这样我们有两个页需要显示用户的 blog。当然我们可以直接拷贝和复制处理渲染 blog 的模板,但这不是最理想的。因为当我们决定要修改 blog 的布局的时候,我们要更新所有使用它的模板。

相反,我们将要制作一个渲染 blog 的子模板,我们在使用它的模板中包含这个子模板。

我们创建一个 blog 的子模板,这是一个再普通不过的模板(文件 /app/templates/post.html):

    <table>
        <tr valign="top">
            <td>![]({{post.author.avatar(50)}})</td><td><i>{{post.author.nickname}} says:</i><br>{{post.body}}</td>
        </tr>
    </table>

接着我们使用 Jinja2 的 include 命令在我们的用户模板中调用这个子模板(文件app/templates/user.html)

{% extends "base.html" %}

{% block content %}
  <table>
      <tr valign="top">
          <td><h1>User: {{ user.nickname }}</h1></td>
          <td><h1>User: {{ user.email }}</h1></td>
      </tr>
  </table>
<hr>
{% for post in posts %}
    {% include 'post.html' %}
{% endfor %}
{% endblock %}

一旦我们有一个功能上完全实现的首页,我们将会调用这个子模板,但是现在不准备这么做,将会把它留在后面的章节。

四、更多有趣的信息

尽然我们现在已经有一个不错的用户信息页,我们还有更多的信息需要在上面显示。像用户自我说明可以显示在用户信息页上,因此我们将会让用户写一些自我介绍,并将它们显示在用户资料页上。我们也将追踪每个用户访问页面的最后一次的时间,因此我们将会把它显示在用户信息页上。

为了增加这些,我们必须开始修改数据库。更具体地说,我们必须在我们的 User 类上增加两个字段(文件 app/models.py)

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    nickname = db.Column(db.String(15), index=True, unique=True)
    email = db.Column(db.String(128), index=True, unique=True)
    role = db.Column(db.SmallInteger, default=ROLE_USER)
    posts = db.relationship('Post', backref='author', lazy='dynamic')
    about_me = db.Column(db.String(140))
    last_seen = db.Column(db.DateTime)

前面的章节我们已经讲述过数据库的迁移。因此为了增加这两个新字段到数据库,需要运行升级脚本

python db_migrate.py

脚本会返回如下信息:

New migration saved as db_repository/versions/003_migration.py
Current database version: 3

我们的两个新字段加入到我们的数据库。如果我们没有迁移的支持,我们必须手动地编辑数据库,最差的方式就是删除表再重新创建。接着,让我们修改用户信息页模板来展示这些字段(文件 app/templates/user.html):

{% extends "base.html" %}

{% block content %}
<p>Name: {{ user.nickname }}</p>
<p>Email: {{ user.email }}</p>

{% if user.about_me %}
<p onclick="about_me()">about me: {{ user.about_me }}</p>
{% else %}
<p style="color:#4499EE;" onclick="about_me()">about me: I'm a person. ---- this info from the system.</p>
{% endif %}

<div id="aboutMe" style="display:none;">
    <form action="{{ url_for('about_me', user_id=current_user.id) }}" method="POST">
        {{ form.hidden_tag() }}
        {{ form.describe }}
        {{ form.submit }}
    </form>
</div>

<p style="color:#4c4c4c;">last log: {{ user.last_seen.strftime("%a, %d %b %Y %H:%M:%S") }}</p>

<a href="{{ url_for('publish', user_id=user.id) }}">Want to publish blogs?</a>

<hr />
{% if blogs | length %}
    {% for blog in blogs %}
    <p>{{ blog.body }}</p>
    <p>{{ blog.timestamp.strftime("%a, %d %b %Y %H:%M:%S") }}</p>
    <hr />
    {% endfor %}
{% else %}
    <p style="color:blue;">the guy is so lazy.....</p>
{% endif %}

{% endblock %}

{% block js %}
<script>
function about_me() {
    target = document.getElementById("aboutMe");
    if (target.style.display == "block") {
        target.style.display = "none";
    } else {
        target.style.display = "block";
    }
}
</script>
{% endblock %}

注意,在user.html中多出了一段js代码,这段js代码可以使的我们点击about me的时候,弹出一个编辑框以便我们修改自己的个人描述,当然我们得在base.html中添加一个block:

<html>
  <head>
    {% if title %}
    <title>{{title}} - microblog</title>
    {% else %}
    <title>microblog</title>
    {% endif %}
  </head>
  <body>
    <div>Microblog: 
        <a href="{{ url_for('index') }}">Home</a>
        {% if not current_user.is_authenticated() %}
        | <a href="{{ url_for('login') }}">Log in</a>
        or <a href="{{ url_for('sign_up') }}">Sign up</a>
        {% else %}
        | <a href="{{ url_for('users', user_id = current_user.id) }}">Profile</a>
        | <a href="{{ url_for('logout') }}">Logout</a>
        {% endif %}
    </div>
    <hr />
    {% with messages = get_flashed_messages() %}
    {% if messages %}
    <ul>
        {% for message in messages %}
        <li>{{ message }}</li>
        {% endfor %}
    </ul>
    {% endif %}
    {% endwith %}
    {% block content %}{% endblock %}
  </body>

  {% block js %}{% endblock %}
</html>

最后,我们希望输入新的个人信息,击yes后,能将够刷新当前页面并且显示新的个人描述,我们看看views.py:

@app.route('/user/about-me/<int:user_id>', methods=["POST", "GET"])
@login_required
def about_me(user_id):
    user = User.query.filter(User.id == user_id).first()
    if request.method == "POST":
        content = request.form.get("describe")
        if len(content) and len(content) <= 140:
            user.about_me = content
            try:
                db.session.add(user)
                db.session.commit()
            except:
                flash("Database error!")
                return redirect(url_for("users", user_id=user_id))
        else:
            flash("Sorry, May be your data have some error.")
    return redirect(url_for("users", user_id=user_id))

我们这里和原来写的不太一样,原来我们的表单提交都是在当前页面进行处理的,当我们点击yes后,会通过post的方式将数据发送到/user/about-me/2页面上去处理,所以我们使用request.method == "POST"进行判定之后,获取表单数据,当然也要判断content的长度,并进行相应的处理,最后跳转回用户主页面。


本文转载自:http://www.jianshu.com/p/ddb0232749a5

共有 人打赏支持
AllenOR灵感
粉丝 10
博文 2139
码字总数 82983
作品 0
程序员
Tumblr、点点、新浪Qing的比较

轻博客是一种介于博客和微博之间的一种网络服务。在国外,2007年4月推出的Tumblr一直在轻博客市场中居于领先地位,很多知名人士和大型媒体公司都使用Tumblr网站。 因为种种原因,Tumblr并不支...

清凌渡
2011/07/05
1K
13
云边 0.5 发布——国内首个开源轻博客

站长下载9月13日消息,云边轻博客系统将于本月下旬正式开源发布,有望成为国内首个开源发布的轻博客系统,云边致力于打造最好用的中文轻博客开源系统。 大家可以到云边官网先体验体验功能,站...

幻之羽翼
2011/09/20
8K
11
Python网站推荐

Python编程 赖勇浩的编程私伙局 TechParty:珠三角技术沙龙 | 打造泛珠三角技术圈线上线下交流的平台 TopCoder,Inc. Code Golf | Home 蜻蜓点水 举重若轻 – 沈崴 – 网易博客 The Python Cha...

未来十年
2012/12/20
0
0
JFBlog 1.0 发布,基于 JFinal 的 Java 轻博客

JFBlog Java 轻博客 1.0 发布,此版本是首个发布版本。 JFBlog 是基于 JFinal 开发的 Java 开源轻博客,使用了 PHP 开源轻博客Typecho的一些样式,包含大多数博客的一些基本功能:文章管理、...

Realfighter
2014/12/26
3K
34
路过秋天版博客 V2.0 测试版发布 公测一周[支持多语言、多用户、多数据库、目录级URL]

路过秋天版博客发布历史回顾: 1:2010年11月08日---支持多语言、多用户、多数据库、目录级URL之路过秋天版博客发布[绝对有杀伤力的博客] 2:2010年11月10日---基础却容易被忽略的那点事--w...

晨曦之光
2012/03/09
0
0
《Django企业开发实战》大纲-草稿

《Django企业开发实战》大纲-草稿 the5fire的技术博客2017-07-2016 阅读 在国内写技术书籍可能是件吃力不讨好的事情,弄不好还会被骂,所以大部分有能力写书的人,不想在这个上面花那么多时间...

the5fire的技术博客
2017/07/20
0
0
[雪峰磁针石博客]flask构建自动化测试平台1-hello

简介 第一部分 Flask实例。学习使用Flask开发,构建功能完备的Web应用程序。我们开发了动态的头条新闻应用程序,可显示最新的新闻标题以及最新的货币和天气信息。在项目二中,我们构建了由M...

Python测试开发人工智能
06/09
0
0
分享一下快速排名到百度首页的基本方法

每一位站长辛辛苦苦把网站搭建好以后,接下来最最核心的事情就是如何把排名做到百度的首页上去,以获得精准的定向流量,产生价值。今天就把快速排名六字经给大家分享一下:   一、外链   ...

建站教程
2015/05/06
1K
4
如何在51CTO博客展示自己发布的视频课程?【讲师帮助文档】

【前面的话】咱们不少51CTO的专家博主、博客之星、推荐博主在51CTO学院发布了自己精心录制的视频课程,那么如何让自己的博客宣传展示自己的课程,让更多的博客粉丝在浏览博客首页、博客文章页...

视频课程
06/26
0
0
Flask框架 —— 从入门到精通

更新日期 :2016 - 2 - 26 有开源网友提醒,故为了可阅读性更新排版。 Hello World 作者背景 应用程序简介 要求 安装 Flask 在 Flask 中的 “Hello, World” 下一步? 模板 回顾 为什么我们需...

水果糖
2016/02/26
402
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

sklearn学习笔记之简单线性回归

简单线性回归 线性回归是数据挖掘中的基础算法之一,从某种意义上来说,在学习函数的时候已经开始接触线性回归了,只不过那时候并没有涉及到误差项。线性回归的思想其实就是解一组方程,得到...

wangxuwei
9分钟前
0
0
feign之动态interceptor(二)

背景 上文提到了按照不同的feignClient可以根据多个不同的key来进行多个不同的bean的配置 那么我们如何完成多个interceptor的配置呢? 分析 我们刚提到多个配置的玄机就在FeignClientProper...

Mr_Qi
11分钟前
1
0
Linux Kernel 4.16 系列停止维护,用户应升级至 4.17

知名 Linux 内核维护人员兼开发人员 Greg Kroah-Hartman 近日在发布 4.16.18 版本的同时,宣布这是 4.16 系列的最后一个维护版本,强烈建议用户立即升级至 4.17 系列。 Linux 4.16 于 2018 年...

问题终结者
36分钟前
0
0
Apache配置时.htaccess失效不起作用的原因分析

.htaccess 失效的原因 1. 重写规则有问题,检查自己的重写规则 2.Apache配置问题,配置中没有配置启用 rewrite a2enmod rewrite 3.网站配置文件没有启用配置需要配置 000-default.conf <Dire...

TU-DESGIN
56分钟前
1
0
两个求最大公约数C/C++算法实现

#include<stdio.h> #include<time.h> #include <iostream>using namespace std;//求最大公约数 LCD(Largest Common Division)//短除法 //m=8251, n=6105; int LCD_ShortDiv(int m, ......

失落的艺术
今天
1
0
QueryPerformanceCounter

windows的Sleep函数,睡眠线程指定毫秒数,可以用来做毫秒延时。 对于微秒延时,没有一个现成的函数,但是可以通过 QueryPerformanceFrequency QueryPerformanceCounter 来间接实现。原理就是...

开飞色
今天
1
0
log4j2使用AsyncRoot不显示行号问题处理

<AsyncRoot level="info" includeLocation="true"> <AppenderRef ref="File"/></AsyncRoot><!--1.异步logger,还需要在pom.xml中添加disruptor的依赖。2.includeLocation结合异......

小翔
今天
3
0
安卓手机上 K 歌,声音延迟怎么解决?

这篇文章可以为你提供一个解决录音和播放同步问题的思路,而且解决了声音从手机传输到耳机上有延时的问题。 初识音频 在开始之前,我先简单介绍一下音频相关的基础知识,方便下文理解。 我们...

编辑部的故事
今天
2
0
使用token实现在有效期内APP自动登录功能

使用token实现在有效期内APP自动登录功能 http://sevennight.cc/2016/07/19/auto_login_impl.html

风云海滩
今天
3
0
Spring Boot集成RabbitMQ发送接收JSON

默认情况下RabbitMQ发送的消息是转换为字节码,这里介绍一下如何发送JSON数据。 ObjectMapper 最简单发送JSON数据的方式是把对象使用ObjectMapper等JSON工具类把对象转换为JSON格式,然后发送...

小致dad
今天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部