Python-Flask實現電影系統管理後臺

代碼地址以下:<br>http://www.demodashi.com/demo/14850.htmlhtml

項目描述

該項目實現電影系統的後臺接口,包括用戶,電影,場次,訂單,評論,優惠券,推薦,收藏等多個模塊,同時提供一個管理後臺進行操做和管理。使用Swagger使用接口的可視化,方便測試。python

項目截圖

項目結構

MovieAdmin
├── requirements.txt         # 第三方庫依賴文件
└── src
    ├── app
    │   ├── admin                # 管理後臺文件
    │   │   ├── admin.py
    │   │   ├── __init__.py
    │   │   └── views.py
    │   ├── api                    # 接口文件
    │   │   ├── comment.py
    │   │   ├── coupon.py
    │   │   ├── favorite.py
    │   │   ├── __init__.py
    │   │   ├── movie.py
    │   │   ├── order.py
    │   │   ├── password.py
    │   │   ├── screen.py
    │   │   ├── session.py
    │   │   └── user.py
    │   ├── __init__.py
    │   ├── models.py       # 數據庫模型
    │   ├── static               # 靜態文件,保存用戶頭像和電影海報等
    │   │   ├── images
    │   │   │   ├── poster
    │   │   │   └── user
    │   │   │       └── default.jpg
    │   │   └── js
    │   │       ├── jquery-3.2.1.min.js
    │   │       └── md5.min.js
    │   ├── templates
    │   │   ├── admin
    │   │   │   └── index.html
    │   │   └── admin.html
    │   └── utils.py
    ├── instance                    # 私密配置文件夾
    │   ├── __init__.py
    │   └── secure_conf.py
    └── server.py                  # 主服務運行文件

項目運行

安裝Python2.7環境

安裝第三方依賴

pip install -r requirements.txt

運行

python server.py

運行後會在 src 目錄下生成 data.sqlite 文件,存儲數據庫相關數據,訪問 http://localhost:5000/admin/ 進入後臺管理系統,管理系統帳號密碼保存在 src/instance/secure_conf.py 中,可自行更改。mysql

項目實現

數據庫建模

電影系統的主要功能是用戶能夠瀏覽電影信息並選擇場次和座位進行下單購票,完成支付後會隨機贈送優惠券,可在下次購票時使用。觀看完電影以後可進行電影評論,用戶也能夠收藏電影,首頁會按期推薦新上映的熱門電影,所以該項目至少涉及如下幾張數據表:用戶表,電影表,場次表,訂單表,評論表,優惠券表,推薦表,收藏表。 完整的數據庫模型以下圖: 以上數據庫模型,以users爲例,對應的sql語句以下:jquery

-- ----------------------------
-- Table structure for users 用戶表
-- ----------------------------
DROP TABLE IF EXISTS `users`;
CREATE TABLE `users` (
  `id` varchar(11) NOT NULL COMMENT '用戶id(手機號碼)',
  `password` varchar(32) NOT NULL COMMENT '登陸密碼',
  `payPassword` varchar(32) NOT NULL COMMENT '支付密碼',
  `nickname` varchar(20) NOT NULL DEFAULT '' COMMENT '暱稱',
  `money` float NOT NULL COMMENT '餘額',
  `description` varchar(50) NOT NULL DEFAULT '' COMMENT '個性簽名',
  `avatar` varchar(32) NOT NULL DEFAULT '' COMMENT '頭像路徑',
  `isAdmin` tinyint(1) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

對象關係映射 ORM

對象關係映射(Object Relational Mapping,簡稱ORM),用於實現面向對象編程語言裏不一樣類型系統的數據之間的轉換。從效果上說,它實際上是建立了一個可在編程語言裏使用的「虛擬對象數據庫」。對象關係映射(Object-Relational Mapping)提供了概念性的、易於理解的模型化數據的方法。在大多數的 Web 應用中,都會將數據存儲在關係型數據庫中,使用 ORM 技術能夠在代碼經過操做對象實現數據庫操做,無需本身寫sql語句,如前面一大段建表的語句,ORM模型的簡單性簡化了數據庫查詢過程。使用ORM查詢工具,用戶能夠訪問指望數據,而沒必要理解數據庫的底層結構。Flask 中可以使用Flask-SQLAlchemy來實現 ORM。sql

models.py 中定義了每張數據庫表對應的對象,經過對這些對象的操做,能夠直接實現對數據庫的增刪改查,無需編寫sql語句。以訂單表爲例:數據庫

# -*- coding: utf-8 -*-
from datetime import datetime, date
from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()

class Order(db.Model):
    """訂單"""
    __tablename__ = 'orders'
    __table_args__ = {'mysql_engine': 'InnoDB'}  # 支持事務操做和外鍵

    id = db.Column(db.String(32), primary_key=True)
    screenId = db.Column(db.String(32), db.ForeignKey('screens.id'), nullable=False)
    seat = db.Column(db.PickleType, doc='座位號(逗號分隔)', nullable=False)
    username = db.Column(db.String(32), db.ForeignKey('users.id'), nullable=False)
    createTime = db.Column(db.DateTime, doc='建立時間', nullable=False)
    status = db.Column(db.Boolean, doc='訂單狀態(0:未支付,1:已支付)', default=0, nullable=False)
    couponId = db.Column(db.String(32), db.ForeignKey('coupons.id'))
    payPrice = db.Column(db.Float, doc='實際支付', nullable=False)
    totalPrice = db.Column(db.Float, doc='原價', nullable=False)

管理系統

成功使用 ORM 建了項目所需的數據庫表,如今咱們要考慮一個問題,咱們要怎麼管理數據庫中的數據呢,好比一個電影系統,確定會有電影的信息和上映的場次信息,這個時候就須要一個後臺管理系統,登陸該系統後能夠對數據庫中的數據進行增刪改查。使用Flask-Admin能夠很方便的構建一個後臺管理系統編程

初始化

from flask import Flask
from flask_admin import Admin
    
app = Flask(__name__)
admin = Admin(app, name=u'電影管理系統')  # 等價於下面兩句
# admin = Admin(name=u'電影管理系統')
# admin.init_app(app)
app.run()

運行以後訪問 http://localhost:5000/admin/ 就能夠看到一個簡單的管理界面。json

增長視圖

做爲後臺管理系統,固然須要添加登陸界面,保證管理系統的安全性,用Flask-Login作身份驗證,Flask-WTF防止跨站請求僞造攻擊(CSRF)。flask

views.py文件中,添加一個登陸表單的類,其中的 User 類就是數據模型中的用戶表,此時 User 類還須要繼承 flask_login 中的UserMixin類。bootstrap

from models import User
from flask_wtf import FlaskForm
from wtforms import fields, validators, ValidationError
    
class LoginForm(FlaskForm):
    """登陸表單"""
    username = fields.StringField(validators=[validators.data_required()])
    password = fields.PasswordField(validators=[validators.data_required()])
    
    def validate_username(self, field):
        """登陸校驗"""
        user = self.get_user()
    
        if user is None:
            raise ValidationError('Invalid user')
        if self.password.data != user.password:
            raise ValidationError('Invalid password')
    
    def get_user(self):
        return User.query.filter_by(id=self.username.data, isAdmin=1).first()

有了登陸表單以後,增長一個視圖,若是未登陸就重定向到登陸界面,已登陸就顯示管理系統首頁,這裏須要在templates文件夾中添加模板文件。

import flask_login as login
from flask_login import login_required
from flask_admin import expose, AdminIndexView, helpers
    
class MyAdminIndexView(AdminIndexView):
    @expose('/')
    def index(self):
        if not isAdmin():
            return redirect(url_for('.login_view'))
        return super(MyAdminIndexView, self).index()
    
    @expose('/login/', methods=('GET', 'POST'))
    def login_view(self):
        form = LoginForm(request.form)
    
        if helpers.validate_form_on_submit(form):
            user = form.get_user()
            login.login_user(user)
    
        if isAdmin():
            return redirect(url_for('.index'))
    
        self._template_args['form'] = form
        return super(MyAdminIndexView, self).index()
    
    @expose('/logout/')
    @login_required
    def logout_view(self):
        login.logout_user()
        return redirect(url_for('.login_view'))

數據庫模型視圖

爲數據庫中的每一個張表增長專用的管理頁面。好比如今要爲電影單獨添加一個管理頁面,只需新建一個繼承ModelView的類

from wtforms import fields
from flask_admin.contrib.sqla import ModelView
    
class MovieModelView(ModelView):
    column_exclude_list = ('description',)    # 不顯示的字段
    # 表單字段
    form_columns = ('expired', 'name', 'poster', 'description',
                    'playingTime', 'duration', 'movieType', 'playingType')
    form_create_rules = form_columns[1:]   # 新建時顯示的字段
    form_overrides = {'poster': fields.FileField}   # 重寫表單類型
    
    # 自定義字段顯示
    form_args = {
        'movieType': {
            'render_kw': {
                'placeholder': '電影類型, 中文逗號分隔'
            }
        }
    }
    
    # 當模型的數據改變時觸發(新建或修改)
    def on_model_change(self, form, movie, is_created):
        # do something
        pass

而後初始化登陸,添加模型視圖便可

# -*- coding: utf-8 -*-
from views import *
import flask_login as login
from flask_admin import Admin
from models import db, Movie, User
    
def init_login(app):
    """初始化登陸"""
    login_manager = login.LoginManager()
    login_manager.init_app(app)
    
    # Create user loader function
    @login_manager.user_loader
    def load_user(id):
        return User.query.get(id)
    
admin = Admin(name='管理系統', template_mode='bootstrap3',
              index_view=MyAdminIndexView(), base_template='admin.html')
movieModelView = MovieModelView(Movie, db.session, name='電影管理')
admin.add_view(movieModelView)

效果以下:

SwaggerUI

有了管理後臺,就能夠開始編寫後臺接口了,Flask-RESTPlus 增長了對快速構建 REST API的支持。它配置很是簡單,很容易上手,並且它提供了裝飾器和工具集合來描述API 而且集成了 Swagger UI 界面。

在 REST 中,一個 URI 標識一個資源,Flask-RESTPlus 中有一個Resource類,繼承這個類並實現get,post,delete,patch等函數便可處理對應的 HTTP 請求。下面以收藏模塊爲例:

# *-* coding: utf-8 *-*
from flask import request
from app.utils import UUID
from app.models import Favorite, Movie, db
from flask_restplus import Namespace, Resource
from flask_login import current_user, login_required
    
api = Namespace('favorite', description='收藏模塊')
    
        
@api.route('/')
class FavoritesResource(Resource):
    @login_required
    def get(self):
        """獲取收藏列表(需登陸)"""
        return [f.__json__() for f in current_user.favorites], 200
    
    @api.doc(parser=api.parser().add_argument(
      'movieId', type=str, required=True, help='電影id', location='form')
    )
    @login_required
    def post(self):
        """收藏電影(需登陸)"""
        mid = request.form.get('movieId', '')
        movie = Movie.query.get(mid)
        if movie is None:
            return {'message': '電影不存在'}, 233
        movie = current_user.favorites.filter_by(movieId=mid).first()
        if movie is not None:
            return {'message': '不能重複收藏同部電影'}, 233
    
        favorite = Favorite()
        favorite.id = UUID()
        favorite.username = current_user.id
        favorite.movieId = mid
        db.session.add(favorite)
        db.session.commit()
    
        return {'message': '收藏成功', 'id': favorite.id}, 200
    
    
@api.route('/<id>')
@api.doc(params={'id': '收藏id'})
class FavoriteResource(Resource):
    @login_required
    def delete(self, id):
        """取消收藏(需登陸)"""
        favorite = current_user.favorites.filter_by(id=id).first()
        if favorite is None:
            return {'message': '您沒有這個收藏'}, 233
        db.session.delete(favorite)
        db.session.commit()
        return {'message': '取消收藏成功'}, 200

@api.route裝飾器是路由監聽,@login_required裝飾器來自於 Flask-Login ,被裝飾的函數須要用戶登陸,@api.doc 是文檔說明,在後面的 Swagger UI 部分就能看到它的做用了。

建立了資源以後,只須要進行初始化便可實現 RESTful 服務。

# *-* coding: utf-8 *-*
from flask import Flask
from flask_restplus import Api
from favorite import api as ns1
    
api = Api(
    title='MonkeyEye',
    version='1.0',
    description='電影系統API',
    doc='/swagger/',             # Swagger UI: http://localhost:5000/swagger/
    catch_all_404s=True,
    serve_challenge_on_401=True
)
    
api.add_namespace(ns1, path='/api/favorites')
    
app = Flask(__name__)
api.init_app(app)
    
if __name__ == '__main__':
    app.run()

實現了 REST API 以後,咱們要怎麼測試這些接口呢,有沒有一種操做簡便的方法呢? Flask-RESTPlus 中就自帶了 Swagger UI 界面,能夠直接訪問該界面查看 API 並進行測試,前面咱們用@api.doc修飾的資源和方法都會在 Swagger UI 界面呈現出來,Api(doc=/swagger/) 指定了 Swagger UI 的路徑,效果以下圖:

改進優化

爲了例子可以簡單快速運行,減小環境依賴,刪除了原項目不少的功能點:

  • MySQL數據庫,例子中改用sqlite,可自行安裝其餘數據庫,修改配置文件中的數據庫URL便可。
  • 手機號註冊,短信驗證碼功能
  • 使用QQ郵箱發送重置密碼右鍵功能
  • gunicorn + Nginx 部署,提升程序性能

參考連接:

代碼地址以下:<br>http://www.demodashi.com/demo/14850.html

相關文章
相關標籤/搜索