用flask编写自己的博客(1)

news/2024/7/8 3:58:13 标签: python, markdown, javascript

照着视频写代码!因为底子原因,进度太慢,对其中的部分代码和知识点进行记录

一、设计models:

​ 本着简单的原则设计,只包函user、post、comments 三个表格,user为用户信息,post为文章列表,comments为评论列表,代码如下:

python">from . import db, login_manager
from flask_login import UserMixin
# import datetime
from datetime import datetime
from markdown import markdown
from werkzeug.security import generate_password_hash, check_password_hash
import bleach

class Role(db.Model):
    __tablename__ = "roles"
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(255), nullable=True)
    users = db.relationship("User", backref='roles')

    @staticmethod
    def seed():
        db.session.add_all(map(lambda r: Role(name=r), ["Guest", "Administrator"]))
        db.session.commit()

class User(db.Model, UserMixin):
    __tablename__ = "users"
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(255), nullable=True)
    nickname = db.Column(db.String(64), nullable=True)
    email = db.Column(db.String(255))
    password_hash = db.Column(db.String(255), nullable=True)
    role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))

    posts = db.relationship("Post", backref='author')
    commnets = db.relationship("Comment", backref='comment')

    @staticmethod
    def on_created(target, value, oldvalue, initiator):
        target.role = Role.query.filter_by(name="Guest").first()
    #设置禁止读取password
    @property
    def password(self):
        raise AttributeError('Password is not a readable attribute')
    #hash密码
    @password.setter
    def password(self, password):
        self.password_hash = generate_password_hash(password)
    #检查密码是否匹配,返回bool值
    def check_password(self, password):
        return check_password_hash(self.password_hash, password)

@login_manager.user_loader
def load_user(user_id):
    return User.query.get(int(user_id))

#监听创建用户事件
db.event.listen(User.name, "set", User.on_created)

class Post(db.Model):
    __tablename__ = "posts"
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(64), nullable=True)#MySQL需要字符串长度,sqlite可以不设
    body = db.Column(db.String(5000), nullable=True)
    body_html = db.Column(db.String(5000), nullable=True)
    created = db.Column(db.DateTime, index=True, default=datetime.utcnow)
    comments = db.relationship("Comment", backref="posts")
    author_id = db.Column(db.Integer, db.ForeignKey("users.id"))

    @staticmethod
    def on_body_changed(target, value, oldvalue, initiator):
        allowed_tags = ['a', 'abbr', 'acronym', 'b', 'blockquote', 'code', 'em', 'i', 'li', 'ol', 'pre', 'strong', 'ul',
                        'h1', 'h2', 'h3', 'p']
        target.body_html = bleach.linkify(
            bleach.clean(markdown(value, output_format='html'), tags=allowed_tags, strip=True))

#监听修改文章事件
db.event.listen(Post.body, "set", Post.on_body_changed)

class Comment(db.Model):
    __tablename__ = "comments"
    id = db.Column(db.Integer, primary_key=True)
    body = db.Column(db.String(200), nullable=True)
    created = db.Column(db.DateTime, index=True, default=datetime.utcnow)
    post_id = db.Column(db.Integer, db.ForeignKey("posts.id"))
    author_id = db.Column(db.Integer, db.ForeignKey("users.id"))

二、创建wtf表单:登陆、注册、修改密码、新增(修改)、评论

python">from flask_wtf import FlaskForm
from wtforms import StringField,SubmitField
from wtforms.validators import DataRequired
from flask_pagedown.fields import PageDownField
#新增(修改)表单
class PostForm(FlaskForm):
    title = StringField('标题',validators=[DataRequired()])
    body=PageDownField("正文",validators=[DataRequired()])
    submit=SubmitField("发布")
#评论表单
class CommentForm(FlaskForm):
    body=PageDownField("评论",validators=[DataRequired()])
    submit=SubmitField("发表")
python">from flask_wtf import FlaskForm as Form
from wtforms import StringField, PasswordField, SubmitField, SelectField
from wtforms.validators import DataRequired, EqualTo, Email, Regexp, Length
from app.models import Role

class LoginForm(Form):
    username = StringField(validators=[DataRequired()], label="用户名")
    password = PasswordField(validators=[DataRequired()], label="密 码")
    submit = SubmitField(label="提交")

class RegistrationFrom(Form):
    email = StringField(u"邮箱地址", validators=[DataRequired(), Length(1, 64), Email()])
    nickname = StringField("昵称", validators=[DataRequired()])
    username = StringField(u"用户名", validators=[DataRequired(), Length(1, 64), Regexp('^[A-Za-z][A-Za-z0-9_.]*$', 0,
                                                                                     u"用户名必须由字母开头,字母、数字、下划线或 . 组成")])
    password = PasswordField(u"密码", validators=[DataRequired(), EqualTo('password2', message=u'两次密码不一致')])
    password2 = PasswordField(u"确认密码", validators=[DataRequired()])
    authed = SelectField(u'权限', coerce=int)
    submit = SubmitField(u"立即注册")

    # SelectFrom Data 数据需要注意,多个列表直接在init里面添加
    def __init__(self, *args, **kwargs):
        super(RegistrationFrom, self).__init__(*args, **kwargs)
        self.authed.choices = [(role.id, role.name) for role in Role.query.order_by(Role.id).all()]

class PasswdChangeFrom(Form):
    user = StringField(u"用户名", validators=None)
    nickname = StringField("昵称")
    # old_password = HiddenField(validators=[DataRequired()])
    password = PasswordField(u'新密码', validators=[DataRequired(), Length(6, 16, message="密码长度不合适,请输入6-16位密码"),
                                                 EqualTo("password2", message=u"两次密码不一致")])
    password2 = PasswordField(u"重复密码", validators=[DataRequired()])
    submit = SubmitField(u"提交")

注册和修改密码对安全性要求较高,做了一些限制:邮箱有效性、用户名规则、用户名是否存在、密码长度等

第二弹:对项目的结构进行分析!使用blueprint进行分组,减少单个文件的大小传送门

第三弹:对jinja2 网页模板进行分析,使用bootstrap+wtf快速布局(待续)

第四弹,整个项目的总结以及扩展,qrcode等一些小工具的介绍(...)

项目源码地址:github
教学视频地址:Flask入门

转载于:https://blog.51cto.com/5353088/2105564


http://www.niftyadmin.cn/n/593949.html

相关文章

Android之浮动小窗口

//创建创建全局变量类 1 public class MyApplication extends Application {2 3 /**4 * 创建全局变量 5 * 全局变量一般都比较倾向于创建一个单独的数据类文件,并使用static静态变量 6 * 7 * 这里使用了在Application中添加数据的方法实现全局变量 8 * 注意…

java全部小写_使Java字符串全部大写或全部小写。

的toUpperCase()使用默认语言环境的规则转换方法的所有字符的在该字符串为大写的toLowerCase()方法转换所有的在该字符串中的字符使用默认语言环境的规则为小写。示例import java.lang.*;public class StringDemo {public static void main(String[] args) {//将所有大写字母转…

Android利用VideoView实现VideoPlayer

在其他的平台上面可能VideoPlayer开发是一个比较有挑战性的工作,但是在Android上面VideoPlayer的开发,基本上可以做到傻瓜式啦。本文简单对VideoPlayer的开发进行简单的介绍。 在Android系统中,是通过MediaPalyer类播放媒体文件的&#xff08…

对Java多线程技术中所有方法的详细解析

一、run()和start() 这两个方法应该都比较熟悉,把需要并行处理的代码放在run()方法中,start()方法启动线程将自动调用 run()方法,这是由Java的内存机制规定的。并且run()方法必须是public访问权限,返回值类型为void。 二、关键字…

JavaScript的数组知识案例之随机点名器

本次分享JavaScript主要知识点涉及到for循环、if选择结构判断语句、数组的定义、定时器、清除定时器、日期对象的使用。 执行后效果图: 思路: 1.网页结构搭建: HTML 2.网页布局美化: CSS   3.随机功能实现: JavaScript 分析后案…

java web 局部刷新页面_实现Web页面的局部动态更新

本例中实现的是页面中局部动态更新的效果,对应页面的显示效果如图5-5所示,在该页面中实现的相当于商品信息的后台维护页面,在该页面中用户可以动态增加新的品牌信息到数据库中,增加后的品牌信息将会直接在动态表格中进行显示。同时…

android VideoView播放视频,MediaRecorder 录音

1. 在Android系统中,是通过MediaPalyer类播放媒体文件的(包括视频和音频)。虽然这个类已经比较简单了,但是还需要控制各种状态,对于视频还需要设置输出窗口,还是需要仔细研究的。为了避免这些麻烦事儿&…

android悬浮窗口的实现

当我们在手机上使用360安全卫士时,手机屏幕上时刻都会出现一个小浮动窗口,点击该浮动窗口可跳转到安全卫士的操作界面,而且该浮动窗口不受其他activity的覆盖影响仍然可见(多米音乐也有相关的和主界面交互的悬浮小窗口)。那么这种不受Activit…