代碼地址以下:<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 部署,提升程序性能
參考連接:
- Flask 文檔:https://dormousehole.readthedocs.io/en/latest/
- Flask-Admin 教程:http://flask123.sinaapp.com/article/57/
- Flask-RESTplus 教程:https://www.cnblogs.com/leejack/p/9162367.htmlPython-Flask實現電影系統管理後臺
代碼地址以下:<br>http://www.demodashi.com/demo/14850.html