1. 程式人生 > >管理信息系統第二學期課程設計

管理信息系統第二學期課程設計

tlist get 短信 ogg redis aso 登陸註冊 sel 用戶表

----------系統概要-------------
1. 基於python3版本,flask框架開發的新聞平臺,采用前後端不分離的方式
2. 具有基本登陸,註冊
3. 用戶可以進行新聞的發布修改
4. 用戶可以修改個人信息
5. 在新聞詳細頁具體關註新聞,關註作者,發表評論,回復評論等功能
6. 後臺管理,管理員可以對新聞進行審核,並新增新聞分類

---------網站結構設計-------------
1.新聞主頁,可以查看新聞列表,最熱新聞,查看不同分類的新聞,通過ajax進行局部刷新,往下滑自動加載下一頁
2.用戶登陸,註冊
3.新聞詳細頁,有評論點贊,作者信息
4.用戶個人中心,修改個人信息,發布信息,查看關註作者
5.後臺管理,新聞全部信息,審核新聞,增加分類

------------模塊詳細設計-----------

登陸註冊模塊

登陸
@user_blueprint.route(/login, methods=[POST])
def login():
    # 接收數據
    dict1 = request.form
    mobile = dict1.get(mobile)
    pwd = dict1.get(pwd)

    # 驗證有效性
    if not all([mobile, pwd]):
        return jsonify(result=1)

    # 查詢判斷、響應
    user = UserInfo.query.filter_by(mobile=mobile).first()
    
# 判斷mobile是否正確 if user: # 進行密碼對比,flask內部提供了密碼加密、對比的函數 if user.check_pwd(pwd): # 將當前時段的登錄數量+1 login_time_count() # 狀態保持 session[user_id] = user.id # 返回成功的結果 return jsonify(result=4, avatar=user.avatar_url, nick_name=user.nick_name)
else: # 密碼錯誤 return jsonify(result=3) else: # 如果查詢不到數據返回None,表示mobile錯誤 return jsonify(result=2) 註冊模塊 ef register(): # 接收數據 dict1 = request.form mobile = dict1.get(mobile) yzm_image = dict1.get(yzm_image) yzm_sms = dict1.get(yzm_sms) pwd = dict1.get(pwd) # 驗證數據的有效性 # 保證所有的數據都被填寫,列表中只要有一個值為False,則結果為False if not all([mobile, yzm_image, yzm_sms, pwd]): return jsonify(result=1) # 對比圖片驗證碼 if yzm_image != session[image_yzm]: return jsonify(result=2) # 對比短信驗證碼 if int(yzm_sms) != session[sms_yzm]: return jsonify(result=3) # 判斷密碼的長度 import re if not re.match(r[a-zA-Z0-9_]{6,20}, pwd): return jsonify(result=4) # 驗證mobile是否存在 mobile_count = UserInfo.query.filter_by(mobile=mobile).count() if mobile_count > 0: return jsonify(result=5) # 創建對象 user = UserInfo() user.nick_name = mobile user.mobile = mobile user.password = pwd # user.avatar = ‘cat.jpg‘ # 提交到數據庫 try: db.session.add(user) db.session.commit() except: current_app.logger_xjzx.error(用戶註冊訪問數據庫失敗) return jsonify(result=7) # 返回響應 return jsonify(result=6) 訪問其他視圖時,驗證是否登陸(裝飾器) def login_required(view_fun): @functools.wraps(view_fun) # 保持view_fun的函數名稱不變,不會被fun2這個名稱代替 def fun2(*args, **kwargs): # 判斷用戶是否登錄 if user_id not in session: return redirect(/) # 視圖執行完,會返回response對象,此處需要將response對象繼續return,最終交給瀏覽器 return view_fun(*args, **kwargs) return fun2 管理員模塊 管理員登陸 @admin_blueprint.route(/login, methods=[GET, POST]) def login(): if request.method == GET: return render_template(admin/login.html) elif request.method == POST: # 接收 dict1 = request.form mobile = dict1.get(username) pwd = dict1.get(password) # 驗證 if not all([mobile, pwd]): return render_template( admin/login.html, msg=請填寫用戶名、密碼 ) # 處理 user = UserInfo.query.filter_by(isAdmin=True, mobile=mobile).first() if user is None: return render_template( admin/login.html, mobile=mobile, pwd=pwd, msg=用戶名錯誤 ) if not user.check_pwd(pwd): return render_template( admin/login.html, mobile=mobile, pwd=pwd, msg=密碼錯誤 ) # 登錄成功後,進行狀態保持 session[admin_user_id] = user.id # 響應 return redirect(/admin/) 訪問其他視圖,驗證是否登陸狀態(請求勾子) @admin_blueprint.before_request def login_validate(): # 對於不執行這段代碼的視圖,可以進行排除 except_path_list = [/admin/login] if request.path not in except_path_list: if admin_user_id not in session: return redirect(/admin/login) g.user = UserInfo.query.get(session[admin_user_id]) 新聞模塊 展示新聞列表 @news_blueprint.route(/newslist) def newslist(): # 查詢新聞數據==>[news,news,...]==>json # 接收請求的頁碼值 page = int(request.args.get(page, 1)) # 查詢新聞信息 pagination = NewsInfo.query.filter_by(status=2) # 接收分類的編號 category_id = int(request.args.get(category_id, 0)) if category_id: pagination = pagination.filter_by(category_id=category_id) # 排序,分頁 pagination = pagination. order_by(NewsInfo.update_time.desc()). paginate(page, 4, False) # 獲取當前頁的數據 news_list = pagination.items # pagination.pages # 將python語言中的類型轉換為json news_list2 = [] for news in news_list: # print(news.pic_url) news_dict = { id: news.id, pic: news.pic_url, title: news.title, summary: news.summary, user_avatar: news.user.avatar_url, user_nick_name: news.user.nick_name, update_time: news.update_time.strftime(%Y-%m-%d), user_id: news.user.id, category_id: news.category_id } news_list2.append(news_dict) return jsonify(news_list=news_list2) 新聞首頁 @news_blueprint.route(/) def index(): # 查詢分類,用於顯示 category_list = NewsCategory.query.all() # 判斷用戶是否登錄 if user_id in session: user = UserInfo.query.get(session[user_id]) else: user = None # 獲取分類排行前6條數據select * from ... where ... order ... limit 6 count_list = NewsInfo.query. filter_by(status=2). order_by(NewsInfo.click_count.desc())[0:6] return render_template( news/index.html, category_list=category_list, user=user, count_list=count_list )


1. 用戶views_user.py模塊
註冊
本質:向用戶表中加入數據
展示頁面
views_news.py
index.html
圖片驗證碼
使用python的繪圖工具PIL進行繪制,返回給瀏覽器
pip install pillow
拷貝captcha到utils包
在views_user.py定義視圖
在index.html中調用
看不清換一張
短信驗證碼
調用第三方的接口進行短信處理
拷貝sdk
定義調用代碼ytx_send.py
在views_user.py中定義視圖
在js中調用
註冊處理views_user.py
使用post方式請求
CSRF保護
在app對象上進行保護
csrf_token()
接收數據
驗證數據的有效性
創建user對象並賦值
提交到數據庫
響應
調用
登錄
本質:根據用戶名密碼查詢數據
視圖處理
獲取數據
有效性判斷
處理:查詢
判斷響應:用戶名、密碼
登錄成功後狀態保持
調用
退出
右上角信息顯示
登錄視圖中返回用戶信息
登錄處理中顯示信息
視圖:刪除cookie值
調用
用戶中心
視圖index
模板user.html
展示昵稱、頭像
完善鏈接
user.html
定義相關視圖
user.html代碼重用
定義base.html,封裝頭、尾
在user.html中繼承
登錄驗證
在訪問用戶中心的相關視圖時,必須登錄,否則轉到首頁
定義裝飾器
添加到視圖函數上
在用戶中心退出時轉到首頁
基本資料
顯示原有數據
視圖:查詢
模板:展示
提交處理
使用ajax+post
視圖:接收數據並修改對象
調用:提交,成功後修改頁面
頭像設置
展示
視圖:查詢
模板:展示
如何在flask中進行圖片上傳
將文件上傳到服務器,保存在磁盤上,然後將文件名保存在表的字段上
HTML要求
form表單的method="post"
表單的 enctype="multipart/form-data"
flask處理
接收文件request.files.get(‘與input的name一致‘)
保存:文件對象.save(路徑)
將文件名賦給對象的屬性:文件對象.name
將文件上傳到七牛雲
如何使用ajax方式進行文件上傳:jquery.form.min.js
提交
視圖處理
調用及成功後顯示
訪問騰訊雲的圖片
我的關註
查詢數據並展示
視圖中查詢
模板中展示
添加示例數據:
user_info,tb_user_follow
分頁
查詢語句中有方法paginate(頁碼,頁大小,False)
在視圖中分頁查詢
在模板中調用jquery.pagination.min.js
我的收藏
視圖:查詢並分頁
模板:展示,頁碼控制
新聞列表
視圖:查詢並分頁
模板:展示,頁碼控制
密碼修改
展示
定義視圖
模板顯示
處理
post
問題分析
視圖處理
響應
新聞發布
展示
定義視圖:查詢新聞分類
模板顯示
處理
視圖接收添加
頁面news_list.html
main.js
新聞修改
展示
視圖:查詢數據
模板:展示
處理
視圖:接收並保存
轉到列表頁


2. 新聞views_news.py模塊

功能分析
首頁
新聞列表
分頁(向下滑動,到底部時加載)
顯示分類
指定分類的列表+分頁
登錄狀態
點擊量排行列表
模板繼承
詳情頁
模板繼承
根據新聞編號查詢新聞並展示
收藏與取消收藏
評論
評論列表
回復評論
點贊評論
作者信息
關註與取消關註
點擊排行(重用:宏)
首頁
定義視圖,顯示頁面
模板繼承
繼承自base.html
index.html
所有分類
視圖
模板
登錄狀態
視圖
模板base.html
main.js
views_user中的login視圖
新聞列表
使用ajax方式查詢數據
使用vue渲染頁面
視圖news_list:查詢
復制vue.js到項目中
顯示:index.html
index.js
函數updateNewsData
分頁
當進行$.get()請求後,數據不會立即返回,但是<100的判斷還在執行,這樣會發起多次請求,解決:增加一個請求標誌
視圖
index.js
分類數據查詢
視圖
如果請求是第一頁,則直接為vue賦值
如果請求非第一頁,則為vue的數組進行拼接
index.js中請求調用
分頁的完善:index.js
updateNewsData
點擊排行
在index.html中顯示
詳情頁
定義視圖,展示頁面
app.py中處理404
視圖函數detail
模板繼承
登錄狀態
顯示新聞信息{{news.***}}
點擊排行:重用(宏)
macro.html
index.html使用
detail.html使用
視圖中查詢點擊排行數據
收藏
如果當前新聞的作者與當前登錄的用戶是同一個賬戶,則不顯示收藏的按鈕
定義視圖:數據添加
在detail.html中加入新聞編號、口令
使用ajax請求視圖
取消收藏-視圖
取消收藏-調用
添加評論
定義視圖,添加數據
js調用
界面提示
評論列表
ajax+vue
定義視圖,查詢數據,返回json
js調用:$.get()
vue模板定義
在js中創建vue對象並調用
點贊
post,局部刷新
定義視圖,處理數據,user_id-comment_id,存儲在redis中
js調用
界面樣式切換
commentlist視圖
app.py
detail.html中的vue模板
取消點贊
視圖中處理
js中調用
回復
定義視圖,添加數據
js調用$.post
展示

關註
定義視圖,處理數據
默認展示效果
$.post()調用

3. 後臺views_admin.py 模塊


後臺views_admin.py
功能分析
登錄
登出
後臺管理頁面
訪問驗證
用戶統計
用戶列表
新聞審核列表
新聞審核
新聞版式編輯列表
新聞版式編輯
新聞分類管理(局部刷新)
創建管理員
方案一:直接在數據庫中執行insert語句
方案二:直接在前臺註冊,在表中修改isAdmin屬性
解決:擴展終端命令,進行添加管理員
創建命令類super_command.py
添加擴展命令xjzx.py
登錄
定義視圖,展示頁面
模板login.html
接收post請求,查詢數據,狀態保持
後臺主頁
定義視圖
修改模板:維護鏈接
用戶信息
菜單的修改
退出
定義視圖
登錄驗證
判斷是否登錄,如果未登錄則轉到登錄頁面
大部分視圖都要進行這個驗證,除了/admin/login
方案一:裝飾器(已經在用戶中心中使用過)
方案二:請求勾子before_request
用戶統計
定義視圖
展示頁面
需要展示的數據
用戶總數
用戶月新增數
用戶日新增數
用戶登錄活躍數
註冊登錄
登錄分時統計
登錄成功時寫數據(views_user.py==>login)
在用戶統計時讀數據
用戶列表
定義視圖:展示頁面
展示模板vue
定義視圖:返回json數據
新聞審核列表
展示視圖
展示模板
列表視圖
新聞版式編輯列表
展示視圖
展示模板
列表視圖
新聞審核列表-搜索
視圖
html
js調用
新聞版式編輯列表-搜索
視圖
html
js調用
新聞審核
get請求視圖,展示頁面
模板
post請求視圖,修改新聞狀態
新聞版式編輯
get視圖
模板
post視圖
新聞分類管理
無刷新
頁面視圖
模板vue
json視圖
js調用news_type.js
添加
視圖
js
修改
視圖
js

-----------數據結構和算法-------------
1. 將常用的數據存入redis數據庫提升數據查詢效率
。。。。。。。


-----------數據庫設計--------------

ORM(數據庫設計)

import pymysql
from flask import current_app
from werkzeug.security import generate_password_hash, check_password_hash

pymysql.install_as_MySQLdb()

from flask_sqlalchemy import SQLAlchemy

db=SQLAlchemy()

from datetime import datetime
class BaseModel(object):
    create_time=db.Column(db.DateTime,default=datetime.now)
    update_time=db.Column(db.DateTime,default=datetime.now)
    isDelete=db.Column(db.Boolean,default=False)

tb_news_collect = db.Table(
    tb_news_collect,
    db.Column(user_id, db.Integer, db.ForeignKey(user_info.id), primary_key=True),
    db.Column(news_id, db.Integer, db.ForeignKey(news_info.id), primary_key=True)
)
tb_user_follow = db.Table(
    tb_user_follow,
    db.Column(origin_user_id, db.Integer, db.ForeignKey(user_info.id), primary_key=True),
    db.Column(follow_user_id, db.Integer, db.ForeignKey(user_info.id), primary_key=True)
)


class NewsCategory(db.Model, BaseModel):
    __tablename__ = news_category
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(10))
    #關系屬性:不會在表中生成字段
    #lazy=dynamic惰性加載category.news
    #category=NewsCategory.query.get(1)
    #當使用lazy=dynamic時不會查詢分類的新聞信息
    #這樣設置的好處:可能本次只是使用分類對象,不想使用新聞對象,則可以減少數據庫的查詢量
    news = db.relationship(NewsInfo, backref=category, lazy=dynamic)


class NewsInfo(db.Model, BaseModel):
    __tablename__ = news_info
    id = db.Column(db.Integer, primary_key=True)
    category_id = db.Column(db.Integer, db.ForeignKey(news_category.id))
    pic = db.Column(db.String(50))
    title = db.Column(db.String(30))
    summary = db.Column(db.String(200))
    content = db.Column(db.Text)
    user_id = db.Column(db.Integer, db.ForeignKey(user_info.id))
    click_count = db.Column(db.Integer, default=0)
    comment_count = db.Column(db.Integer, default=0)
    #1--待審核,2--通過,3--拒絕
    status = db.Column(db.SmallInteger, default=1)
    reason=db.Column(db.String(100),default=‘‘)
    comments = db.relationship(NewsComment, backref=news, lazy=dynamic, order_by=NewsComment.id.desc())

    @property
    def pic_url(self):
        from config import Config
        return Config.tengxun_URL + self.pic

    # def to_index_dict(self):
    #     return {
    #         id: self.id,
    #         pic_url: self.pic_url,
    #         title: self.title,
    #         summary: self.summary,
    #         author: self.user.nick_name,
    #         author_avatar: self.user.avatar_url,
    #         author_id: self.user_id,
    #         udpate_time: self.update_time.strftime(%Y-%m-%d)
    #     }


class UserInfo(db.Model,BaseModel):
    __tablename__ = user_info
    id = db.Column(db.Integer, primary_key=True)
    avatar = db.Column(db.String(50), default=user_pic.png)
    nick_name = db.Column(db.String(20))
    signature = db.Column(db.String(200),default=這貨很懶,什麽也沒寫)
    public_count = db.Column(db.Integer, default=0)
    follow_count = db.Column(db.Integer, default=0)
    mobile = db.Column(db.String(11))
    password_hash = db.Column(db.String(200))
    gender = db.Column(db.Boolean, default=False)
    isAdmin = db.Column(db.Boolean, default=False)
    #用戶發布新聞為1:多,所以將新聞關聯屬性定義在User類中
    news = db.relationship(NewsInfo, backref=user, lazy=dynamic)
    #用戶對評論為1:多,所以將評論關聯屬性定義在User類中
    comments = db.relationship(NewsComment, backref=user, lazy=dynamic)
    #用戶對收藏新聞為多:多,此時關系屬性可以定義在任意類中,當前寫在了User類中
    news_collect = db.relationship(
        NewsInfo,
        #多對多時,指定關系表,因為外鍵存儲在這個關系表中
        secondary=tb_news_collect,
        lazy=dynamic
        #此處沒有定義backref,作用是根據新聞找用戶,因為不需要使用這個功能,所以可以不定義
    )
    #用戶關註用戶為自關聯多對多,關系屬性只能定義在User類中
    #使用user.follow_user可以獲得當前user用戶關註的用戶列表
    #select * from users inner join tb_user_follow on user.id=origin_user_id
    follow_user = db.relationship(
        UserInfo,
        #多對多,所以指定關系表
        secondary=tb_user_follow,
        lazy=dynamic,
        #user.follow_by_user可以獲得當前user用戶的粉絲用戶列表
        backref=db.backref(follow_by_user, lazy=dynamic),
        #在使用user.follow_user時,user.id與關系表中哪個字段判等
        primaryjoin=id == tb_user_follow.c.origin_user_id,
        #在使用user.follow_by_user時,user.id與關系表中的哪個字段判等
        secondaryjoin=id == tb_user_follow.c.follow_user_id
    )

    @property
    def password(self):
        pass

    @password.setter
    def password(self, pwd):
        self.password_hash = generate_password_hash(pwd)

    def check_pwd(self, pwd):
        return check_password_hash(self.password_hash, pwd)

    @property#user.avatar_url()==>user.avatar_url
    def avatar_url(self):
        from config import Config
        # print(Config.tengxun_URL)
        return Config.tengxun_URL+self.avatar

class NewsComment(db.Model, BaseModel):
    __tablename__ = news_comment
    id = db.Column(db.Integer, primary_key=True)
    news_id = db.Column(db.Integer, db.ForeignKey(news_info.id))
    user_id = db.Column(db.Integer, db.ForeignKey(user_info.id))
    like_count = db.Column(db.Integer, default=0)
    comment_id = db.Column(db.Integer, db.ForeignKey(news_comment.id))
    msg = db.Column(db.String(200))
    #關聯屬性,用於獲取當前評論的回復數據
    comments = db.relationship(NewsComment, lazy=dynamic)

1. 新聞分類(category)
id, name, is_delete
2.新聞(news_info)
id, title, category_id(category外鍵) ,pic ,summary ,context ,user_id(user外鍵) ,source ,click_count ,comment_count ,status ,reason

3.用戶關註用戶關系
用戶關註用戶,自關聯多對多

4. 用戶收藏新聞關系表
用戶與新聞一對多

5, 用戶

6. 評論

技術分享圖片技術分享圖片技術分享圖片技術分享圖片技術分享圖片技術分享圖片


管理信息系統第二學期課程設計