照着視頻寫代碼!由於底子緣由,進度太慢,對其中的部分代碼和知識點進行記錄html
本着簡單的原則設計,只包函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"))
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("發表")
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"提交")
註冊和修改密碼對安全性要求較高,作了一些限制:郵箱有效性、用戶名規則、用戶名是否存在、密碼長度等git
第二彈:對項目的結構進行分析!使用blueprint進行分組,減小單個文件的大小傳送門github
第三彈:對jinja2 網頁模板進行分析,使用bootstrap+wtf快速佈局(待續)sql
第四彈,整個項目的總結以及擴展,qrcode等一些小工具的介紹(...)flask