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

----------系統概要-------------
1. 基於python3版本,flask框架開發的新聞平臺,採用先後端不分離的方式
2. 具備基本登錄,註冊
3. 用戶能夠進行新聞的發佈修改
4. 用戶能夠修改我的信息
5. 在新聞詳細頁具體關注新聞,關注做者,發表評論,回覆評論等功能
6. 後臺管理,管理員能夠對新聞進行審覈,並新增新聞分類html

---------網站結構設計-------------
1.新聞主頁,能夠查看新聞列表,最熱新聞,查看不一樣分類的新聞,經過ajax進行局部刷新,往下滑自動加載下一頁
2.用戶登錄,註冊
3.新聞詳細頁,有評論點贊,做者信息
4.用戶我的中心,修改我的信息,發佈信息,查看關注做者
5.後臺管理,新聞所有信息,審覈新聞,增長分類vue

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

登錄註冊模塊

登錄
@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
新聞修改
展現
視圖:查詢數據
模板:展現
處理
視圖:接收並保存
轉到列表頁mysql


2. 新聞views_news.py模塊jquery

功能分析
首頁
新聞列表
分頁(向下滑動,到底部時加載)
顯示分類
指定分類的列表+分頁
登陸狀態
點擊量排行列表
模板繼承
詳情頁
模板繼承
根據新聞編號查詢新聞並展現
收藏與取消收藏
評論
評論列表
回覆評論
點贊評論
做者信息
關注與取消關注
點擊排行(重用:宏)
首頁
定義視圖,顯示頁面
模板繼承
繼承自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
展現ajax

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

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數據庫提高數據查詢效率
。。。。。。。sql


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

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. 評論

相關文章
相關標籤/搜索