(一)新經資訊css
一、新聞展現的Web項目html
二、以抓取其餘網站數據爲新聞、用戶發佈數據爲來源前端
三、基於Flask框架,先後端不分離python
(二)技術實現ajax
一、使用Flask框架實現redis
二、使用Redis + MySQL 進行數據存儲數據庫
三、使用第三方擴展json
(1)雲通訊flask
(2)七牛雲後端
(三)功能模塊分類
一、新聞模塊
二、用戶模塊
三、後臺管理模塊
(四)項目目錄說明
一、項目根目錄 說明
/info 項目應用核心目錄
/logs 項目日誌目錄
config.py 項目配置文件--保存session信息、調試模式、密鑰等
manage.py 項目啓動文件
requirements.txt 項目依賴文件
二、項目/info目錄 說明
/libs 項目用到的資源庫--第三方擴展(雲通訊)
/modules 項目模塊--全部的藍圖對象和視圖函數
/static 項目靜態文件夾
/template 項目模板文件夾
/utils 項目通用設施--自定義狀態碼、上傳圖片等
__init__.py 項目應用初始化文件--應用程序實例、數據庫實例、註冊藍圖、日誌等
constants.py 項目常量信息--數據庫緩存信息、驗證碼、房屋信息等
models.py 項目模型類
三、項目/info/libs目錄 說明
/yuntongxun 第三方擴展--發送短信
sms.py 發送短信
四、項目/info/static目錄 說明
/admin/ 項目admin模塊的靜態文件,css/html/js等
/news/ 項目admin模塊的靜態文件,css/html/js等
favicon.ico 項目logo
五、項目/info/utils目錄 說明
image_storage.py 雲存儲設施文件--七牛雲
response_code.py 自定義狀態碼
注意:
1、用工廠方法來實例化應用對象app
def create_app(config_name):
app = Flask(__name__) //實例化啓動app
app.config.from_object(config[config_name]) //導入配置信息並動態傳入配置信息
db.init_app(app) //關聯db和app
Session(app) //把Session對象和app關聯
CSRFProtect(app) // csrf保護關聯app
**此處使用請求鉤子,在每次請求以後將csrf_token的值傳給前端頁面**
**此處用來註冊藍圖對象
from pro_info.modules.news import news_blue
app.register_blueprint(news_blue)
……
**註冊模板使用的過濾器**
from pro_info.utils.common import do_index_class
app.add_template_filter(do_index_class, 'index_class')
return app
2、每次的請求都須要設置跨站保護,該方法可使用請求鉤子的方法,即每次請求以後執行,這個功能能夠設置在實例化應用對象的時候就定義,即放在__init__.py文件中的實例化app對象的工廠方法中
@app.after_request
def after_request(response):
csrf_token = csrf.generate_csrf()
response.set_cookie('csrf_token',csrf_token)
return response
並在前端的ajax中設置請求頭
headers:{
X-CSRFToken:getCookie('csrf_token')
}
3、因爲不少接口須要判斷用戶是否在線的狀況,對此咱們採用的是用裝飾器的方式實現這一功能的。
def login_required(f): è 定義一個方法,方便被調用
@functools.wraps(f) è 這是一個python內置的裝飾器工具,目的是讓被裝飾的函數的屬性不會被改變
def wrapper(*args,**kwargs):
user_id = session.get('user_id') è 嘗試獲取用戶的登陸信息
user = None
if user_id:
try:
user = User.query.get(user_id)
except Exception as e:
current_app.logger.error(e)
g.user = user è 使用引用上下文的g變量來保存用戶的信息
return f(*args,**kwargs)
//具體的實現方式是讓被裝飾的函數的名稱在返回wrapper以前賦值給wrapper的__name__ è wrapper.__name__ = f.__name__
return wrapper
4、統一設置返回的錯誤頁面
因爲用戶的不少不恰當的操做,或者服務器的緣由,致使頁面沒法顯示等錯誤,咱們能夠設置指定的錯誤頁面,可使用
app.errorhandle(code_or_exception) 裝飾器來實現這一功能,來達到與用戶的更加友好的交互頁面,寫在__init__文件的工廠方法中
@app.errorhandle(錯誤碼)
@user_login_data
def page_not_found(_):
user = g.user
data = {「user_info」:user.to_dict() if user else None}
return render_template(‘指定的錯誤頁面的模板文件’,data=data)
5、爲了更直觀的展現後臺數據效果,須要添加一些測試用戶到數據庫中,再目錄下新建一個.py文件,複製以下代碼直接運行便可
import datetime
import random
from info import db
from info.models import User
from manage import app
def add_test_users():
users = []
now = datetime.datetime.now()
for num in range(0, 10000):
try:
user = User()
user.nick_name = "%011d" % num
user.mobile = "%011d" % num
user.password_hash="pbkdf2:sha256:50000$SgZPAbEj$a253b9220b7a916e03bf27119d401c48ff4a1c81d7e00644e0aaf6f3a8c55829"
user.last_login = now - datetime.timedelta(seconds=random.randint(0, 2678400))
users.append(user)
print(user.mobile)
except Exception as e:
print(e)
# 手動開啓一個app的上下文
with app.app_context():
db.session.add_all(users)
db.session.commit()
print('OK')
if __name__ == '__main__':
add_test_users()
1、註冊相關接口
(一)圖片驗證碼
一、獲取前端生成的UUID編碼
image_code_id = generate()前端調用該方法生成UUID編號,併發送給服務器
因爲這是一個imp標籤因此服務器能夠request.args.get()獲取到這個編碼
二、調用captcha(圖靈測試)擴展生成圖片驗證碼
對獲取到的參數進行驗證,判斷是否存在
存在則:name,text,image = captcha.generate_captcha()調用captcha生成圖片驗證碼
三、之前端獲取的UUID爲鍵,captcha生成的text爲值,存儲到Redis數據庫中
使用Redis數據庫redis_store.setex(imageCodeId,time,text)將數據進行保存
四、使用flask中的make_response將圖片返回給前端頁面
response = make_response(image)
五、修改前端相應報頭並返回
response. headers['Content-Type'] = 'image/jpg'
return….
(二)發送手機短信
一、根據接口文檔指定請求方式,以及肯定須要接受的參數
二、對接受的參數進行校驗
(1)確認參數的完整性
if not all([mobile,image_code,image_code_id])
return…
(2)確認手機號是否符合規範(採用正則的方式驗證)
if not re.match(r‘1[3456789]\d{9}’,mobile)
return…
(3)確認驗證碼是否正確,從Redis數據庫中取出以前保存的text值進行比對,爲防止二次使用驗證碼,取出後刪除數據庫中數據
real_image_code = redis_store.get(image_code_id)
redis_store. delete(…)
if not real_image_code.lower() != image_code.lower()
return…
三、參數校驗完成後判斷用戶是否已經註冊
查詢MySQL數據庫中是否存在該用戶
user = User.query.filter_by(mobile=mobile).first()
if user 表示用戶存在已經註冊
return…
四、生成6位隨機數,並以用戶手機號位鍵,隨機數位值將數據存儲到Redis數據庫
sms_code = '%06d' % random.randint(0,999999)
redis_store.setex(mobile,time,sms_code)
5、調用第三方雲通信接口發送生成的6位隨機數給用戶手機,
生成6位隨機數:sms_code = '%06d' % random.randint(0,999999)
調用雲通信發送短信:ccp = sms.CCP()
result = ccp.send_template_sms(mobile,[sms_code,time / 60],1)
若是result == 0 表示發送成功,else發送失敗
(三)註冊按鈕
一、根據接口文檔指定請求方式,以及肯定須要接受的參數
二、對接受的參數進行校驗
(1)確認參數的完整性
if not all([mobile,sms_code,password])
return…
(2)確認手機號是否符合規範(採用正則的方式驗證)
if not re.match(r‘1[3456789]\d{9}’,mobile)
return…
(3)確認手機驗證碼是否正確,從Redis數據庫中取出以前保存的sms_code值進行比對,爲防止二次使用,取出後刪除數據庫中數據
real_sms_code = redis_store.get(mobile)
因爲以前設置的是有時效的數據,所以須要判斷是否還存在該sms_code
redis_store.delete(…)
if not real_sms_code != str(sms_code)
return…
三、將用戶的數據存儲到MySQL數據庫
user = User()
user.moblie = mobile
user.password = password(加密存儲)
user.nike_name = mobile(給用戶默認設置一個暱稱)
db.session.add(user)
db.session,commit()
4、爲實現狀態保持,將用戶的註冊的信息存儲到Reids數據庫中,並提示註冊完成
session['user_id'] = user.id
session['mobile'] = user.mobile
session['nick_name'] = mobile
2、登陸相關接口
一、根據接口文檔肯定須要接受的參數以及請求方式
二、校驗參數的完整性
if not all([mobile,password])
三、判斷手機號碼是否符合規則
if not re.match(r‘1[3456789]\d{9}’,mobile)
return…
四、根據手機號碼進行MySQL的數據查找
user = User.query.filter_by(mobile=mobile).first()
五、判斷是否存在用戶或則密碼是否正確
if user is None or not user.check_password(password)(調用加密密碼的檢查匹對方法)
return
六、保存用戶的登陸信息並記錄用戶的最後登陸時間
session['user_id'] = user.id
session['mobile'] = mobile
session['nick_name'] = user.nick_name
user.last_login = datetime.now()
七、記錄的用戶登陸時間須要提交到數據庫中
db.session.commit()
八、返回提示用戶登陸成功
3、退出相關接口
退出即刪除用戶的登陸信息
session.pop('user_id')
session.pop('mobile')
session.pop('nick_name')
此處建議使用pop()方法,不建議使用clear()方法
4、主頁相關接口
採用模板的方式,因此須要導入render_template
一、確認用戶是否登陸在線
user = g.user //此處是定義的裝飾器
二、展現點擊排行按點擊量進行排序查找,且根據前端的設計是顯示的六條信息
news_list = News.query.order_by(News.clicks.desc()).limit(6)
三、判斷點擊排行數據查找結果是否存在
if not news_list:
return…
四、定義一個列表容器保存查詢結果
news_dict_list = []
5、遍歷全部的查詢對象並添加到列表容器中,並調用模型類中to.dict()的方法將之轉換成字符串
for news in news_list:
news_dict_list.append(news.to_dict())
六、展現新聞分類數據需搜索全部分類信息
categories = Category.query.all()
七、判斷分類數據是否存在
if not categories:
return
八、定義一個列表容器保存查詢結果
category_list = []
9、遍歷全部的查詢對象並添加到列表容器中,並調用模型類中to.dict()的方法將之轉換成字典
for category in categories:
category_list.append(category.to_dict())
十、定義一個字典保存全部數據,並將之傳給模板進行數據填充
data = {
"user":user.to_dict() if user else None,//表示若是用戶未登陸的狀況下也是能夠訪問主頁面的
"news_dict_list":news_dict_list,
"category_list":category_list
}
return render_template(‘模板’,data=data)
5、首頁新聞數據列表接口
一、根據接口文檔定義路由,請求方式以及須要哪些參數等(備註:ajax/get請求)
二、接受所須要參數並進行校驗(cid,page,per_page)
爲實現友好的交互,即便後端沒傳過來數據,在首頁也是須要展現新聞的,因此咱們默認會給其定義一個參數
cid = request.args.get('cid','1') è分類id
page = request.args.get('page','1')
per_page = request.args.get('per_page','10')
三、校驗參數,並將數字參數轉換成整型值(爲了和數據庫進行查找)
try:
cid,page,per_page = int(cid),int(page),int(per_page)
except Exception as e:
return
四、根據參數進行查詢數據庫
(1)定義變量,存儲過濾條件è根據分類id
filters = []
if cid > 1: => filters.append(News.category_id == cid)
(2)默認按照分類id進行過濾,按新聞發佈時間進行排序,對查詢數據進行分頁
paginate = News.query.filter(*filters).order_by(News.create_time.desc()).paginate(page,per_page,False)
paginate(頁數,每頁多少條目數,分頁異常不報錯)
五、獲取分頁後的新聞數據模型對象,總頁數以及當前頁數
news_list = paginate.items //模型對象
total_page = paginate.pages //總頁數
current_page = paginate.page //當前頁數
六、遍歷模型對象並添加到一個列表容器,使用to_dict()方法轉換成字典
for news in news_list:
news_dict_list.append(news.to_dict())
七、準備返回數據:
(1) data = {
(2) 'news_dict_list':news_dict_list,
(3) 'total_page':total_page,
(4) 'current_page':current_page
(5) }
八、進行返回 return jsonify(errno=RET.OK,errmsg='OK',data=data)
1、詳情頁模板接口
一、獲取參數以url傳參的形式獲取參數
@藍圖對象.route(‘/<int:news_id>’)
def get_news_detail(news_id):
二、判斷用戶是否登陸在線,並獲取用戶信息
user = g.user
三、根據news_id進行查詢數據庫
news = News.query.get(news_id)
四、檢查查詢的結果
if not news:
return…
五、展現詳情頁的分類數據,查詢數據庫
categories = Category.query.all()
六、檢查查詢的結果,並定義容器保存遍歷的查詢對象
if not categories:
return…
七、將新聞詳情的點擊次數 +1
news.clicks += 1
八、判斷是否收藏,默認狀況爲False,若是用戶已經登陸,而且被該用戶收藏
is_collected = False
if user and news in user.collection_news:
is_collected = True
九、評論內容,查詢數據庫獲取當前新聞的全部評論
comments = []
comments = Comment.query.filter(Comment.news_id == news_id).order_by(Comment.create_time.desc()).all()
十、判斷用戶登陸
if user:
獲取全部的評論id
comment_ids = [comment.id for comment in comments]
再查詢當前用戶點讚了哪些評論
comment_likes = CommentLike.query.filter(CommentLike.comment_id.in_(comment_ids),CommentLike.user_id == g.user.id).all()
獲取當前用戶點讚的評論id
comment_like_ids = [comment_like.comment_id for comment_like in comment_likes]
十一、定義一個列表用戶來保存評論數據
comment_dict_li = []
十二、遍歷查詢到全部評論數據
for comment in comments:
comment_dict = comment.to_dict()
判斷評論是否被點贊,默認爲False
comment_dict['is_like'] = False
if comment.id in comment_like_ids:
comment_dict['is_like'] = True
將查詢到的點讚的評論數據保存到以前定義的列表中
comment_dict_li.append(comment_dict)
13、若是用戶是登陸的,查詢用戶關注的新聞發佈者,默認爲Falas
is_followed = False
if news.user and user:
if news.user in user.followers:
is_followed = True
1四、將全部數據添加到一個字典容器中
data = {
"news":news.to_dict(),
"category_list":category_list,
'user': user.to_dict() if user else None,//若是用戶未登陸,那麼有關用戶的信息就爲False,新聞詳情頁不必規定用戶必須在線
'is_collected': is_collected,
'is_followed': is_followed,
'comments': comment_dict_li
}
1五、調用模板頁面返回數據,並對模板進行數據填充顯示
return render_template('news/detail.html',data=data)
2、收藏和取消收藏接口
根據接口文檔進行路由分析,指定請求方式
一、嘗試獲取用戶信息,若是用戶未登陸,需提示用戶登陸,才能進行收藏
user = g.user
if not user:
return…
2、獲取參數news_id,action(collect,cancle_collect)
request.json.get()方法獲取
三、檢查參數,對news_id強轉爲整型值,對數據庫進行查詢,若是強轉出錯返回錯誤信息
四、檢查action的值是否存在
if action not in ['collect', 'cancel_collect']:
return…
五、判斷新聞是否存在數據庫中
news = News.query.get(news_id)
if not news:
return…
6、判斷選擇的是collect仍是cancle_collect,並判斷用戶是否收藏過該新聞,未收藏過添加到收藏,收藏過返回已收藏
if action == collect:
if news not in user.collection_news:
user.collection_news.append(news)
else:
If news in user.collection_news:
User.collection_news.remove(news)
七、提交數據庫
八、返回ajax響應信息
3、關注和取消關注接口
與收藏接口相似,只需根據接口文檔定好路由以及請求方式,不過多贅述
4、新聞評論接口
根據接口文檔肯定路由及請求方式
一、獲取用戶登陸信息,若是用戶未登陸直接返回並提示登陸
user = g.user
二、獲取參數,news_id,comment,parent_id(回覆的評論的id)
request.json.get()方法
三、校驗參數完整性
if not all([news_id,comment]):
return…
4、對news_id進行強轉,並判斷是否有parent_id,若是強轉失敗返回錯誤信息
news_id = int(news_id)
if parent_id:
parent_id = int(parent_id)
五、查詢新聞並判斷新聞是否存在
news = News.query.get(news_id)
if not news:
return…
六、實例化評論模型的對象,並添加數據
comment = Comment()
comment.user_id = user.id
comment.news_id = news.id
comment.content = comment_conent
七、判斷父評論是否存在,存在則添加父評論的信息
if parent_id:
comment.parent_id = parent_id
八、提交數據到數據庫
try:
db.session.add(comment)
db.session.commit()
except Exception as e:
current_app.logger.error(e)
db.session.rollback()
九、返回評論數據給前端ajax
5、點贊和取消點贊接口
根據接口文檔肯定路由及請求方式
一、獲取用戶登陸信息,若是用戶未登陸直接返回並提示登陸
user = g.user
二、獲取參數,comment_id,action(add,remove)
request.json.get()方法
三、校驗參數完整性
if not all([comment_id,action])
return…
if action not in [add,remove]
return…
四、把comment_id轉成整型,強轉錯返回錯誤信息
五、根據comment_id查詢數據
comment = Comment.query.get(comment_id)
六、判斷查詢結果,若是不存在,返回錯誤信息
七、判斷action參數是否爲add或者remove
(1)若是爲add,判斷行爲是點贊仍是取消點贊,使用CommentLike進行過濾查詢(user_id,comment.id)
comment_like_model = CommentLike.query.filter(CommentLike.user_id == user.id, CommentLike.comment_id == comment.id).first()
if not comment_like_model:è 點贊行爲,點贊數加1
comment_like_model = CommentLike()
comment_like_model.user_id = user.id
comment_like_model.comment_id = comment.id
db.session.add(comment_like_model)
comment.like_count += 1
(2)不然爲取消點贊 è 取消點贊,點贊數減1
db.session.delete(comment_like_model)
comment.like_count -= 1
八、將數據提交到數據庫中
db.session.commit()
九、返回結果給ajax
基於iframe進行實現,子頁面的數據更新以後須要同步主頁面相關聯數據,能夠採用js進行實現,本項目即採用了ajax的數據交互方式
1、用戶頁面接口
這裏咱們用到的是以前就定義好的裝飾器來獲取的用戶信息
一、獲取用戶信息
user = g.user
二、判斷是否得到了用戶的信息,若是沒有則重定向到主頁
if not user:
return redirect(‘/’)
三、將獲取的用戶信息使用字典容器保存起來
四、將數據返回給user.html模板,進行頁面顯示
2、用戶基本信息展現和修改接口
根據接口文檔肯定路由以及請求方式[‘GET’,‘POST’]
1、判斷請求方式,默認GET請求加載模板頁面,能夠直接以裝飾器獲取到用戶的信息進行返回
user = g.user
if request.method == ‘GET’:
將用戶信息返回給模板
return… è 模板爲:user_base_info.html
二、獲取參數(signature,nick_name,gender(男,女))
request.json.get()方法
三、校驗參數的完整性
if not all([signature,nick_name,gender])
return…
4、檢查參數gender參數
if gender not in [‘MAN’,‘WOMEN’]
return…
5、使用user對象將用戶的基本信息保存到數據庫
user.signature = signature
user.nick_name = nick_name
user.gender = gender
try:
db.session.add(user)
db.session.commit()
except Exception as e:
current_app.logger.error(e)
db.session.rollback()
六、返回結果
3、上傳用戶頭像接口
根據接口文檔肯定路由以及請求方式[‘GET’,‘POST’]
1、判斷請求方式,默認GET請求加載模板頁面,能夠直接以裝飾器獲取到用戶的信息進行返回
user = g.user
if request.method == ‘GET’:
將用戶信息返回給模板
return… è 模板爲:user_pic_info.html
2、獲取參數(avatar)
request.files.get()方法
三、校驗參數是否存在
if not avatar:
return…
4、使用read()方法讀取圖片的二進制數據並保存
avatar_data = avatar.read()
五、調用第三方接口storage(),將圖片上傳到七牛雲,並保存七牛雲返回的圖片名稱
image_name = storage(avatar_data)
六、給用戶保存圖片的名稱並提交到到數據庫
user.avatar_url = image_name
try:
db.session.add(user)
db.session.commit()
except Exception as e:
current_app.logger.error(e)
db.session.rollback()
七、拼接圖片的絕對路徑並返回給ajax
設置的七牛雲地址 + image_name
4、修改用戶密碼接口
根據接口文檔肯定路由以及請求方式[‘GET’,‘POST’]
1、判斷請求方式,默認GET請求加載模板頁面
if request.method == ‘GET’:
return… è 模板爲:user_pass_info.html
二、獲取參數(old_password,new_password)
request.json.get()方法
三、檢查參數完整性
if not all([old_password,new_password])
return…
四、獲取用戶信息,並比較用戶輸入的舊密碼,驗證是否正確
user = g.user
if not user.check_password(old_password):
return…
五、驗證成功後保存用戶的新密碼,並提交到數據庫
user.password = new_password
try:
db.session.add(user)
db.session.commit()
except Exception as e:
current_app.logger.error(e)
db.session.rollback()
6、返回結果給ajax
5、新聞發佈接口
根據接口文檔肯定路由以及請求方式[‘GET’,‘POST’]
1、判斷請求方式,默認GET請求加載模板頁面
if request.method == 'GET':
查詢新聞分類,與新聞首頁模塊的主頁相關接口六、七、八、9雷同
return… è 模板爲:user_ news_release.html
二、獲取請求參數
request.form.get()方法獲取表單參數
request.files.get()方法獲取新聞圖片參數
三、校驗參數完整性
if not all([title,category_id,digest,index_image,content]):
return…
4、強轉分類id,若是報錯直接返回錯誤信息
五、read()方法讀取獲取的新聞圖片的二進制數據並調用第三方七牛雲接口上傳圖片,並保存返回的圖片名稱
image_data = index_image.read()
image_name = storage(image_data)
六、實例化新聞類對象,用來保存新聞數據
news = News() è 新聞類對象
news.title = title è 新聞標題
news.source = '我的發佈' è 新聞發佈機構
news.category_id = category_id è 新聞分類id
news.digest = digest è 新聞摘要
news.index_image_url = 設置的七牛雲地址 + image_name è 新聞圖片絕對路徑
news.content = content è 新聞內容
news.status = 1 è 新聞狀態,1表示待審覈,0表示審覈經過,-1表示未經過審覈
七、提交數據到數據庫中
6、用戶新聞列表接口
根據接口文檔肯定路由和請求方式
一、獲取參數,頁數,默認1
request.args.get()方法
二、校驗參數,將page強轉爲整型,若是報錯直接返回錯誤信息
三、獲取用戶信息,定義容器存儲查詢結果,總頁數默認1,當前頁默認1
四、查詢數據庫,查詢新聞數據並進行分頁,
user = g.user
paginate = News.query.filter(News.user_id==user.id).paginate(page,每頁數據數目 ,False)
**可參看新聞首頁模塊的新聞列表接口**
五、返回數據給模板:user_news_list.html
7、用戶關注信息接口
根據接口文檔肯定路由和請求方式
**與用戶新聞列別接口流程相似**
返回數據給模板:user_follow.html
8、查詢用戶關注的其餘用戶信息
根據接口文檔肯定路由和請求方式
一、獲取用戶的登陸信息
user = g.user
二、獲取參數other_id(用戶關注的用戶)
request.args.get()方法
三、校驗參數是否存在,若是不存在,返回錯誤信息
四、查詢信息
other = User.query.get(other_id)
五、判斷新聞是否有做者,且用戶關注過做者,默認爲False
is_follwed = False
if other and user:
if other in user.followed:
is_follwed = True
六、返回數據給模板:other.html
9、返回指定用戶發佈的新聞接口
根據接口文檔肯定路由和請求方式
一、獲取參數(user_id,頁數默認爲1)
request.args.get()方法獲取
二、校驗參數,強轉頁數的參數,若是報錯,直接返回錯誤信息
三、判斷用戶是否存在
other = User.query.get(user_id)
if not other:
return…
四、若是用戶存在,分頁用戶發佈的新聞數據
paginate = other.news_list.paginate(page,每頁條目數,False)
五、獲取分頁數據,並遍歷數據
news_list = paginate.items
current_page = paginate.page
total_page = paginate.pages
六、返回數據給ajax
主要是爲了方便網站的管理而建立的後臺管理員模塊。管理員與普通用戶公用一張表,管理員也具備普通用戶的功能,用指定的字段區分普通用戶和管理員用戶,管理員能夠登陸到後臺管理頁面對新聞以及相應的數據進行操做。
1、建立管理員
使用flask-script擴展自定義腳本命令,以自定義函數的形式實現建立管理員用戶
@manage.option('-n','-name',dest='name')
@manage.option('-p','-password',dest='password') //使用腳本擴展必需要的裝飾器函數
def create_supperuser(name,password): //定義建立管理員的函數,並傳入用戶名和密碼參數
if not all([name,password]): //校驗參數完整性
print('參數缺失')
user = User() //建立模型類User的對象
user.nick_name = name // 添加相應的數據
user.mobile = name
user.password = password
user.is_admin = True
try: //提交數據到數據庫
db.session.add(user)
db.session.commit()
except Exception as e:
db.session.rollback()
print(e)
print('管理員建立成功')
最後使用終端命令行建立管理員用戶
python manage.py 函數名 -n 用戶名 -p 密碼
2、管理員登陸請求鉤子的應用 è 判斷當前登陸的用戶是不是管理員,而且判斷當前訪問的url是不是管理員登陸的頁面url
由於後臺管理不須要讓每一個普通用戶都知道,因此在每次請求前先判斷,在後臺管理的模塊中的建立藍圖的模塊中就可以使用before_request請求鉤子實現該功能。具體方式以下:(在後臺管理模塊的 __init__.py 文件中)
@admin_blu.before_request //每次的請求以前執行的請求鉤子
def check_admin():
is_admin = session.get("is_admin", False) //從Redis數據庫中獲取用戶登陸狀態的信息,默認爲False
//判斷獲取的is_admin,若是不是False表示是管理員,並判斷訪問的頁面是不是管理員登陸頁面的url,不然返回主頁,終止後續操做。
if not is_admin and not request.url.endswith(url_for('admin.login')):
return redirect('/') //使用重定向返回到主頁頁面
3、後臺管理首頁接口
定義路由,返回後臺管理首頁模板頁面
@admin_blu.route('/index') //定義路由
@login_required //確認用戶是否登陸
def index():
user = g.user //獲取用戶相關信息
return render_template('admin/index.html',user=user.to_dict()) //返回後臺管理首頁模板
4、後臺管理員登陸接口
定義路由,指定請求方式(GET,POST)
一、若是爲GET請求,使用session獲取登陸信息。
request.method == ‘GET’
二、判斷用戶是否登陸而且是管理員,則重定向到後臺管理頁面
if user_id and is_admin:
return redirect(url_for(‘後臺管理頁面模板’)
三、不然返回後臺管理登陸頁面模板
return render_template(‘後臺管理登陸頁面’)
四、POST請求方式下獲取參數(user_name,password)
request.form.get()方法
五、校驗參數完整性
if not all([user_name,password]):
return…
六、查詢數據庫,並判斷用戶密碼是否正確
user = User.query.filter(User.mobile==user_name,User.is_admin==True).first()
if user is None or not user.check_password(password):
return…
七、緩存用戶信息,實現狀態保持
session['user_id'] = user.id
session['mobile'] = user.mobile
session['nick_name'] = user.nick_name
session['is_admin'] = user.is_admin
八、重定向到後來管理首頁
return redirect(url_for('admin.index'))
5、後臺用戶數據展現接口
定義路由,獲取數據通常默認爲GET請求
一、根據頁面顯示內容包括總人數,月新增人數,日新增人數
二、查詢數據庫統計總人數,排除管理員用戶的全部普通用戶
總人數 = User.query.filter(User.is_admin == False).count()
三、查詢數據庫統計月新增人數,排除管理員用戶的全部普通用戶
(1)使用time模塊獲取時間對象(tm_year=2018, tm_mon=6, tm_mday=9)
t = time.localtime()
(2)經過時間對象生成每個月開始日期的字符串
mon_begin_date_str = '%d-%02d-01' %(t.tm_year,t.tm_mon)
(3)使用strptime()方法將日期的字符串轉換成日期對象
mon_begin_date = datetime.strptime(mon_begin_date_str,'%Y-%m-%d')
(4)做爲過濾條件查詢數據庫,獲取月新增人數
mon_count = User.query.filter(User.is_admin == False,User.create_time > mon_begin_date).count()
四、查詢數據庫統計日新增人數,排除管理員用戶的全部普通用戶
具體步驟同統計月新增人數方式,先獲取當前日期,生成字符串,再轉換成日期對象,查詢數據庫加上過濾條件,獲取日新增用戶數據
五、實現統計活躍人數/活躍日期
定義列表容器存儲活躍人數,和活躍日期
(1)獲取當前日期,生成字符串,再轉換成日期對象
today_begin_date_str = '%d-%02d-%02d' %(t.tm_year,t.tm_mon,t.tm_mday)
today_begin_date = datetime.strptime(today_begin_date_str,'%Y-%m-%d')
(2)遍歷日期,獲取天天的開始日期和結束日期
for x in range(0,31): //一個月按30天
//開始時間,即天天的0時0分
begin_date = today_begin_date - timedelta(days=x) //timedelta()表明兩個時間之間的時間差,兩個data或datatime
//結束時間,即次日的0時0分 //對象相減就能夠返回一個timedelta對象,傳入的參數表示前多少天
end_date = today_begin_date - timedelta(days=(x-1))
(3)使用時間的過濾條件查詢數據庫統計活躍日期的活躍人數
count = User.query.filter(User.is_admin == False, User.last_login >= begin_date, User.last_login < end_date).count()
(4)將須要的數據添加到以前定義的列表中
active_time.append(begin_date_str)
active_count.append(count)
六、定義字典保存所需數據,將之返回給指定的模板進行渲染
data = {……}
return render_template('admin/user_count.html',data=data)
6、後臺用戶列表展現接口
一、獲取參數,頁數,默認爲1
request.args.get()方法
二、校驗參數,強轉爲int類型,若是錯誤,直接返回錯誤信息
三、查詢數據庫獲取用戶列表信息採用分頁查找方式
paginate = User.query.filter(User.is_admin==False).paginate(page, 每頁數目, False)
提取查詢結果
current_page = paginate.page
total_page = paginate.pages
users = paginate.items
四、定義容器,遍歷查詢結果,並添加到容器中
for user in users:
user_dict_list.append(user.to_admin_dict())
五、返回數據到指定的模板進行渲染
return render_template('admin/user_list.html', data=data)
7、後臺新聞審覈展現接口
一、獲取參數,(頁數,默認爲1,關鍵字參數,默認爲None)
request.args.get()方法
二、校驗參數,強轉頁數爲int類型,若是錯誤,直接返回錯誤信息
三、初始化變量,news_list[],current_page = 1,total_page = 1
四、設置過濾查詢條件,當新聞狀態不爲0的狀況下查詢新聞數據
filters = [News.status != 0]
五、判斷關鍵字參數是否存在,若是存則添加關鍵字搜索到過濾查詢條件中
if keywords:
filters.append(News.title.contains(keywords))
六、根據參數,進行分頁過濾查詢數據庫並提取查詢結果
paginate = News.query.filter(*filters).order_by(News.create_time.desc()).paginate(page, constants.ADMIN_NEWS_PAGE_MAX_COUNT, False)
提取查詢結果
news_list = paginate.items
current_page = paginate.page
total_page = paginate.pages
七、遍歷查詢到的對象,組織數據返回給指定模板渲染
return render_template('admin/news_review.html', data=data)
8、後臺新聞詳情展現接口
經過url傳入新聞id的參數,以下定義路由
@admin_blu.route('/news_review_detail/<int:news_id>')
def news_review_detail(news_id):
……
1、根據news_id查詢新聞詳情數據
news = News.query.get(news_id)
二、校驗查詢結果,若是未查到返回給指定模板錯誤信息
if not news:
return render_template('admin/news_review_detail.html',data={'errmsg':'未查到數據'})
三、查詢到結果調用to_dict()方法再傳回指定模板渲染數據
return render_template('admin/news_review_detail.html',data= {"news":news.to_dict()})
9、後臺新聞審覈接口
根據需求,應該爲POST請求,定義路由指定請求方式
一、獲取參數(新聞id,action)
request.json.get()方法
二、校驗參數完整性
if not all([news_id,action]):
return…
3、校驗action參數是否爲accept或reject
if action not in [accept,reject]:
return…
4、根據新聞id查詢數據庫
news = News.query.get(news_id)
五、判斷是否查詢到數據
if not news:
return…
6、判斷action的具體值,accept表示接受,reject表示拒絕
若是爲accept修改新聞狀態爲 0
若是爲reject修改新聞狀態爲 -1
七、若是拒絕,接受拒絕緣由
request.json.get()方法,獲取拒絕內容
八、判斷是否接受到接受緣由,未接受到返回錯誤信息
九、將數據提交到數據庫
try:
db.session.commit()
except Exception as e:
current_app.logger.error(e)
db.session.rollback()
十、返回信息
10、後臺新聞版式編輯接口
一、獲取參數(頁數默認爲1,關鍵字參數默認爲None)
request.args.get()方法獲取
二、校驗參數,強轉頁數爲int類型,若是錯誤,直接返回錯誤信息
三、初始化變量,news_list[],current_page = 1,total_page = 1
四、定義過濾條件,並判斷關鍵字參數是否存在,若是存在,添加到過濾條件中
filters = [News.status != 0]
if keywords:
filters.append(News.title.contains(keywords))
五、根據相關數據進行分頁查詢數據庫,並保存到以前初始化的遍歷中
paginate = News.query.filter(*filters).paginate(page,每頁數目,False)
news_list = paginate.items
current_page = paginate.page
total_page = paginate.pages
六、遍歷查詢數據對象,調用to_basic_dict()方法
news_dict_list = [] //定義一個容器接受
for news in news_list:
news_dict_list.append(news.to_basic_dict())
七、組織好數據返回給指定的模板進行渲染
return render_template('admin/news_edit.html',data=data)
11、後臺新聞編輯詳情接口
根據需求判斷,應該是GET請求和POST請求,定義路由,和請求方式
一、判斷是不是GET請求
二、獲取參數新聞id,校驗參數存在,強轉int,若是錯誤,返回錯誤
三、根據新聞id獲取新聞數據
四、校驗查詢數據是否存在,查詢錯誤或則查詢失敗直接返回給指定模板錯誤信息
五、查詢分類信息並移除最新分類,使用pop方法
六、遍歷分類信息,並判斷當前遍歷到的分類和新聞所屬分類是否一致
八、全部條件成立的狀況下,組織數據返回給指定模板進行渲染
九、若是爲POST請求,獲取參數(news_id,title,digest,content,index_image,category_id)
request.form.get()獲取表單中的數據
request.files.get()獲取圖片文件
十、校驗參數完整性,與以前大同小異
十一、根據新聞id查詢數據庫,確認新聞是否存在,與以前大同小異
十二、讀取圖片數據,調用第三方接口(七牛雲)上傳圖片並保存七牛雲返回的圖片名稱,拼接圖片的絕對路徑
1三、將數據保存到數據庫進行提交
1四、返回結果。(***大部分操做可參照我的中心模塊新聞發佈接口***)
12、後臺新聞分類修改接口
根據需求判斷請求方式應該爲GET和POST,定義路由
一、判斷若是是GET請求
二、查詢全部分類數據,遍歷查詢結果,並移除最新分類(使用pop()方法)
三、組織數據返回給指定模板進行渲染
四、若是是POST請求
五、獲取參數(name,cid) //若是有cid表示編輯已存在的分類
request.json.get()方法獲取
六、校驗參數name的存在
七、判斷cid是否存在,若是存在即修改已有的分類,強轉爲int類型
八、根據分類cid查詢數據庫,校驗查詢結果
九、修改cid的分類信息爲name的值
十、實例化分類模型類的對象,保存分類名稱,並將數據庫提交到數據庫
十一、返回結果