当前位置:   article > 正文

万字长文 Flask搭建大型博客网站_flask开发的大型网站

flask开发的大型网站

前言

基础知识

python flask
着摸不透的js
丑到爆的网页
不,这才是你需要的:

  1. 一颗会肝的心
  2. 网页与服务器的传输原理(ajax)
  3. 若有不懂,会自行研究,会在评论区爆揍作者
  4. [狗头保命]

项目概述

这是一个博客网站,用户可以登录 注册 写博客 发评论

实现大吞吐量,高并发!

前期准备

安装python虚拟环境及支持库

pip install venv::安装venv支持库,python3.3后自带
python -m venv [虚拟环境名称]
venv/bin/scripts/active.bat::激活环境,可以看到命令行左侧出现 (venv) 字样
pip install [第三方支持库名称]
  • 1
  • 2
  • 3
  • 4

我们需要的第三方支持库有flask pymysql
内置库有hashlib uuid

安装mysql及navicat15

基本功能

项目部署

登录注册:/login?goto=[重定向]
看文章:/article/< int:id >
编辑文章:/editor?id=[文章id]

start.py最初版本

from flask import Flask,route,render_template

def runcom(form):
    '''解析post请求'''
    return " "
    #不能返回空值,否则flask会报错
app=Flask(__name__)
@app.route("/",methods=["GET"])
def index():
    return render_template("index.html")

@app.route("/login")
def login():
    return render_template("login.html")

@app.route("/editor")
def editor():
    return render_template("login html")

@app.route("/article/<int:id>")
def read(id):
    return render_template("article.html",id=id)
    
@app.route("/post",methods=["POST"])
def postHandler():
    data=request.form#获取post报文
    return runcom(data)
if __name__="__main__":
    app.run(host="0.0.0.0")
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

runcom这个函数会解析网站post请求,目前什么也没写,到下一节就会写功能

基本功一一验证模块

验证模块,即登录注册功能,是一个网站必不可少的功能

登录注册需要 (前端 服务器 数据库) 三者交互

userinfo

登录功能

使用form表单发送POST请求

<form action="/post" type="post" target="/">
    <input type="hidden" name="command" value="login">
    <input type="text" name="username" id="id">
    <input type="password" name="password" id="pw">
    <input type="submit">
</form>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

或者使用jQ中的ajax

id=document.getElementById("id")
pw=document.getElementById("pw")
$.ajax({"type":"POST",
        data:{"command":"login","id":id,"password":pw}
})
  • 1
  • 2
  • 3
  • 4
  • 5

同时,我们在start.py中的runcom函数中加几行代码。

import uuid

cursor=pymysql.connect(host="127.0.0.1",database="web",user="root",password="root")
def runcom(form):
    command=form.get("command")
    if command==None:
        return{"success":"false","content":"请指定command项"}
    if command=="login":
        id=from.get("id")
        pw=from.get("password")
        if un==None or pw==None:             
            return{"success":"false","content":"请指定id项或password项"}
        cursor.execute("SELECT pw FROM userinfo WHERE id="+id)
        passwd=cursor.fetchone()
        if passwd==None:
            return{"success":"false","content":"用户不存在"}
        if passwd[0]!=pw:
            return{"success":"false","content":"密码错误"}
        #以上为验证登录
        #成功后的操作--分配uuid
        uid=uuid.uuid4().replace("-","")#不要与uuid重名
        cursor.execute("UPDATE userinfo uuid VALUES("{}") WHERE id={}".format(uid,id))     
           return{"success":"false","uuid":uid}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

为什么要用uuid?

UUID 是 通用唯一识别码(Universally Unique Identifier)的缩写,是一种软件建构的标准,亦为开放软件基金会组织在分布式计算环境领域的一部分。其目的是,让分布式系统中的所有元素,都能有唯一的辨识信息,而不需要通过中央控制端来做辨识信息的指定。如此一来,每个人都可以创建不与其它人冲突的UUID。 一一 百度百科

每一个用户有自己唯一的uuid,服务器只需在用户每次操作时判断 用户和uuid
是否匹配就行了,而不是每次都要用户输密码。
但是,uuid要不断更新(一般是在用户登录的时候),这样可以防止uuid滥用,否则,一但别人拿到了你的uuid,就可以用你账号为所欲为[手动滑稽]

顺便一提,前端接受uuid后会放在cookie,所以破解 某某云限速 的方法就是让用户先登录,取cookie中的uuid,然后为所欲为……

注册功能

使用form表单发送POST请求

<form action="/post" type="post" target="/">
    <input type="hidden" name="command" value="register">
    <input type="text" name="username" id="username">
    <input type="submit">
</form>
  • 1
  • 2
  • 3
  • 4
  • 5

或者使用jQ中的ajax

name=document.getElementById("username")
$.ajax({"type":"POST",
        data:{"command":"register","username":name}
})
  • 1
  • 2
  • 3
  • 4

同样,我们在start.py中的runcom函数中加几行代码。

def runcom(form):
    #--(前略)--
    if command=="register":
        un=form.get("username")
        pw=form.get("password")
        if un==None or pw==None:
            return{"success":"false","content":"请指定username项或password项"}
        cursor.execute("SELECT pw FROM userinfo WHERE username="+str(un))
        passwd=cursor.fetchone()
        if passwd!=None:
            return{"success":"false","content":"用户已存在"}
            
        cursor.execute("INSERT INTO userinfo(username,password) VALUES("{}","{}")".format(un,pw))
        id=cursor.lastrowid#分配id
        return{"success":"true","id":id,"username":username}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

UUID

补充下uuid的优点:

  • 重复率低(其中uuid1,uuid4重复率为0)
  • 难以硬凑(uuid长32位)
#判断id,uuid是否匹配
def isNum(string):
    for s in string:
        if s<"0" or s>"9":
            return False
    return True
    
def isMatch(id,uuid):
    if isNum(id)==False:
        return{"success":"false","content":"id不是纯数字"}
    cursor.execute("SELECT uuid FROM userinfo WHERE id="+id)
    uid=cursor.fetchone()
    if None==uid:
        return{"success":"false","content":"用户不存在"}
    if uuid!=uid[0]:
        return{"success":"false","content":"id和uuid不匹配(登录失效)"}
    return True
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

以后用户操作,比如发动态
post请求就可以这么写:

{"commamd":"bling","id":用户id,"uuid":"uuid","say":"评论内容"}
  • 1

这样服务器就可以识别用户了

大核心一一文章模块

文章模块才是重头戏。
文章模块分 读文章,写文章和展示文章列表,以及点赞、评论、收藏 等功能

读文章

读文章很容易,我们在[网站根目录]/static下创建一个文件夹,就叫articles好了,它用于存放写好的文章,每篇文章存放在 [对应的id].html里

网站取的时候,直接GET请求拿到文章就ok了

用iframe嵌入文章

<iframe src="/static/articles/{{id}}.html">
<!文章内容-->
</iframe>
  • 1
  • 2
  • 3

注意! articles文件夹不要放在除static及其子目录的其它地方,否则GET请求时就算给出文章路径,flask也会识别为路由请求,而不是static(静态文件)

什么是路由请求?什么是路由请求?
如果你想知道答案,且看:

from flask import Flask,route
app=Flask(__name__)

@app.route("/hello")
def func1():
    '''当访问/hello时,会返回Hello World!'''
    return "Hello World!"
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

flask用Flask对象(app是一个Flask对象)的route装饰器设定访问路径

route装饰器还可以传参

@app.route("/hello/<str:name>")
def func2(name):#住意参数
    '''当访问/hello/<name>时,会返回"Hello "+name '''
    return "Hello "+name
  • 1
  • 2
  • 3
  • 4

根据这个设定,我们可以设定读文章的路径:/article/< int:id >

@app.route("/article/<int:id>")
def readArticle():
    return render_template("article.html",id=id)
#flask模板函数,"id=id"会把网页里{{id}}渲染成变量id
  • 1
  • 2
  • 3
  • 4
<iframe src="/static/articles/{{id}}.html"></iframe>
  • 1

就ok了

写文章

需求分析:
路由为/editor?id=[文章id]
文章id不为空,则判断用户是否为文章作者,否则无权编辑
文章id为空,新建一篇文章

POST请求是

{"command":"publish","id":[用户id],"uuid":[uuid],"article":[文章内容],"artID":[文章id,可空]}
  • 1

我们可以这么写路由

@app.route("/editor")
def editor():
    return render_template("editor.html")
  • 1
  • 2
  • 3

/editor?id=[用户id]中的 id参数 可以用getParameters([arg])获取,这个函数网上一搜一大堆

function getParameter(name) {
    var reg = new RegExp((^&) + name + =([^&])(&$), i);
    var r = window.location.search.substr(1).match(reg);
    if (r != null) return unescape(r[2]); 
    return null;
}

//然后就是判断是否为文章作者
function checkAuthor(){
   userID=getCookie("id")
   if(userID==""){windows.location.herf="/login?goto="+windows.location.herf}
   artID=getParameter("id")
   if(artID==null) return;
   $.ajax({data:{"command":"article","id":id}
   success: function(res){
       if(res["author"]!=userID){
           alret("您无权编辑这篇文章")
           windows.location.href="/"
       }
   }
   })
}

function publish(){
    id=getCookie("id")
    uuid=getCookie("uuid")
    content=document.getElementById("content").innerHTML
    $.ajax({url:"/post",
    data:{"command":"publish","id":id,"uuid":uuid,"content":content}})
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

html方面,就放一个textarea和一个用于发布的Button

<textarea id="content"></textarea>
<button action="publish()"></button>
  • 1
  • 2

辅助一一用户交友

在mysql建一张relations的表,用于保存用户关系
relations{
userA int(32) ;用户A < 用户B
userB int(32)
isFriend tinyint
isFollow tinyint ;关注
isFollowing tinyint ;粉丝
}

SELECT 属性 FROM relations WHERE userA=用户A and userB=用户B

UPDATE 属性 VALUES() FROM relations WHERE userA=用户A and userB=用户B
  • 1
  • 2
  • 3

界面美化(思路)

登录注册:/login?goto=[重定向]
看文章:/article/< int:id >
编辑文章:/editor?id=[文章id]

开始我们主要讲了后端代码,而前端基本都是“三行论”

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/article/detail/51570?site
推荐阅读
相关标签