在Python的框架中为MySQL实现restful接口的教程


Posted in Python onApril 08, 2015

最近在做游戏服务分层的时候,一直想把mysql的访问独立成一个单独的服务DBGate,原因如下:

  1.     请求收拢到DBGate,可以使DBGate变为无状态的,方便横向扩展
  2.     当请求量或者存储量变大时,mysql需要做分库分表,DBGate可以内部直接处理,外界无感知
  3.     通过restful限制对数据请求的形式,仅支持简单的get/post/patch/put 进行增删改查,并不支持复杂查询。这个也是和游戏业务的特性有关,如果网站等需要复杂查询的业务,对此并不适合
  4.     DBGate使用多进程模式,方便控制与mysql之间的链接数,进行mysql访问量阀值保护
  5.     方便在DBGate上进行访问量统计,慢查询统计、权限控制等等一系列逻辑
  6.     目前是使用python,以后要使用其他语言进行mysql操作时,只要进行标准的http请求即可,不会出现不兼容的情况

当然坏处也是有的:

  1.     首当其冲就是单次请求的响应时间变长,毕竟中间加了一层服务,并且还是http格式
  2.     部署上比原来复杂了一些,很多对mysql直接操作的思维需要进行转变,一开始可能会有些不适

不过总的来说,还是利大于弊,所以最终还是决定搭建DBGate

当然,我们不可能去手工挨个写每个库表对应的restful服务,值得庆幸的是django和flask都提供了对应的解决方案,我们一个个介绍.
Flask

参考链接: flask-restless

flask-restless使用方法比较简单,我直接贴一下代码即可:

# -*- coding: utf-8 -*-

import datetime
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_restless import APIManager

app = Flask(__name__)
db = SQLAlchemy(app)
restless = APIManager(app, flask_sqlalchemy_db=db)

class User(db.Model):
    """
    user
    """

    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(255), unique=True, nullable=False)
    password = db.Column(db.String(255), nullable=False)
    create_time = db.Column(db.DateTime, nullable=False, default=datetime.datetime.utcnow)
    login_time = db.Column(db.DateTime)

restless.create_api(User, methods=['GET', 'POST', 'DELETE', 'PATCH', 'PUT'], results_per_page=100)

db.create_all()

if __name__ == '__main__':
    app.run(port=25000)
 
# -*- coding: utf-8 -*-
 
import datetime
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_restless import APIManager
 
 
app = Flask(__name__)
db = SQLAlchemy(app)
restless = APIManager(app, flask_sqlalchemy_db=db)
 
 
class User(db.Model):
    """
    user
    """
 
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(255), unique=True, nullable=False)
    password = db.Column(db.String(255), nullable=False)
    create_time = db.Column(db.DateTime, nullable=False, default=datetime.datetime.utcnow)
    login_time = db.Column(db.DateTime)
 
 
restless.create_api(User, methods=['GET', 'POST', 'DELETE', 'PATCH', 'PUT'], results_per_page=100)
 
db.create_all()
 
if __name__ == '__main__':
    app.run(port=25000)

其对应的restful操作如下:

获取用户列表:   GET /user
添加用户:       POST /user
获取单个用户:   GET /user/1
覆盖单个用户:   PUT /user/1
修改单个用户:   PATCH /user/1

获取用户列表:   GET /user
添加用户:       POST /user
获取单个用户:   GET /user/1
覆盖单个用户:   PUT /user/1
修改单个用户:   PATCH /user/1

注意:

  •     在http请求中,记得加入header: Content-Type: application/json
  •     flask-restless中,PUT和PATCH一样,都是传入什么字段,只修改什么字段,不会完全覆盖

Django

参考链接: Django REST framework

Django用起来要更复杂一些,也因为django版自带了一个可视化的操作页面,如下:

在Python的框架中为MySQL实现restful接口的教程

1. 在settings中添加:

REST_FRAMEWORK = {
  # Use hyperlinked styles by default.
  # Only used if the `serializer_class` attribute is not set on a view.
  'DEFAULT_MODEL_SERIALIZER_CLASS':
    'rest_framework.serializers.HyperlinkedModelSerializer',

  # Use Django's standard `django.contrib.auth` permissions,
  # or allow read-only access for unauthenticated users.
  'DEFAULT_PERMISSION_CLASSES': [
    #'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly',
    'rest_framework.permissions.IsAdminUser',
  ]
}
 
REST_FRAMEWORK = {
  # Use hyperlinked styles by default.
  # Only used if the `serializer_class` attribute is not set on a view.
  'DEFAULT_MODEL_SERIALIZER_CLASS':
    'rest_framework.serializers.HyperlinkedModelSerializer',
 
  # Use Django's standard `django.contrib.auth` permissions,
  # or allow read-only access for unauthenticated users.
  'DEFAULT_PERMISSION_CLASSES': [
    #'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly',
    'rest_framework.permissions.IsAdminUser',
  ]
}

2. 通过startapp建立一个app: demo
3. 修改demo的models:

class User(models.Model):
  # key是保留字
  password = models.IntegerField()
  nick = models.CharField(max_length=255)
  create_time = models.DateTimeField(default=datetime.datetime.now)
 
class User(models.Model):
  # key是保留字
  password = models.IntegerField()
  nick = models.CharField(max_length=255)
  create_time = models.DateTimeField(default=datetime.datetime.now)

4. 在demo下新建serializers.py

from rest_framework import serializers
from models import User
class UserSerializer(serializers.ModelSerializer):
  class Meta:
    model = User
 
from rest_framework import serializers
from models import User
 
 
class UserSerializer(serializers.ModelSerializer):
  class Meta:
    model = User

5. 在demo下修改views.py

from django.shortcuts import render
from rest_framework import viewsets

from serializers import UserSerializer
from models import User


class UserViewSet(viewsets.ModelViewSet):
  queryset = User.objects.all()
  serializer_class = UserSerializer
 
from django.shortcuts import render
from rest_framework import viewsets
 
from serializers import UserSerializer
from models import User
 
 
class UserViewSet(viewsets.ModelViewSet):
  queryset = User.objects.all()
  serializer_class = UserSerializer

6. 在demo下新建urls.py

import os.path
from django.conf.urls import patterns, include, url
from django.conf.urls.static import static
from django.conf import settings
import views

from rest_framework import routers

appname = os.path.basename(os.path.dirname(os.path.abspath(__file__)))

router = routers.DefaultRouter()
router.register('users', views.UserViewSet, appname)

urlpatterns = patterns('',
            url(r'^', include(router.urls)),
)
 
import os.path
from django.conf.urls import patterns, include, url
from django.conf.urls.static import static
from django.conf import settings
import views
 
from rest_framework import routers
 
appname = os.path.basename(os.path.dirname(os.path.abspath(__file__)))
 
router = routers.DefaultRouter()
router.register('users', views.UserViewSet, appname)
 
urlpatterns = patterns('',
            url(r'^', include(router.urls)),
)

7. 在mysite.urls下include demo.urls和rest_framework.urls

urlpatterns = patterns('',
  url(r'^demo/', include('demo.urls')),
  url(r'^admin/', include(admin.site.urls)),
  url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))
)
 
urlpatterns = patterns('',
  url(r'^demo/', include('demo.urls')),
  url(r'^admin/', include(admin.site.urls)),
  url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))
)

8. 执行初始化数据操作:

python manage.py syncdb
 
python manage.py syncdb

之后访问: http://127.0.0.1:8000/demo 即可看到如下界面了:

在Python的框架中为MySQL实现restful接口的教程

对应的测试代码如下:

import json
import requests
from urlparse import urljoin

BASE_URL = 'http://127.0.0.1:16500/'
AUTH = ('admin', 'admin')


def test_get_user_list():
  rsp = requests.get(urljoin(BASE_URL, '/demo/users/'), auth=AUTH, headers={
    'Accept': 'application/json'
  })
  assert rsp.ok


def test_post_user_list():
  json_data = dict(
    password=0,
    nick='oo',
    create_time='2014-03-3T03:3:3'
  )
  rsp = requests.post(urljoin(BASE_URL, '/demo/users/'), auth=AUTH, headers={
    'Accept': 'application/json',
    'Content-Type': 'application/json',
  }, data=json.dumps(json_data))
  assert rsp.ok


def test_get_user():
  rsp = requests.get(urljoin(BASE_URL, '/demo/users/1'), auth=AUTH, headers={
    'Accept': 'application/json',
    'Content-Type': 'application/json',
  })
  assert rsp.ok


def test_put_user():
  json_data = dict(
    password=100,
    nick='xx',
    create_time='2014-03-3T03:3:3'
  )
  # 注意最后的 /
  rsp = requests.put(urljoin(BASE_URL, '/demo/users/1/'), auth=AUTH, headers={
    'Accept': 'application/json',
    'Content-Type': 'application/json',
    }, data=json.dumps(json_data),
  )
  assert rsp.ok, rsp.status_code

Django REST framework 是严格区分PUT和PATCH的,这一点和flask-restless 不一样,需要注意。

OK,就这样。

Python 相关文章推荐
详解python并发获取snmp信息及性能测试
Mar 27 Python
python利用MethodType绑定方法到类示例代码
Aug 27 Python
Python 3实战爬虫之爬取京东图书的图片详解
Oct 09 Python
Python实现pdf文档转txt的方法示例
Jan 19 Python
使用Python的toolz库开始函数式编程的方法
Nov 15 Python
Python实现的合并两个有序数组算法示例
Mar 04 Python
Python+OpenCv制作证件图片生成器的操作方法
Aug 21 Python
Python 3.6 中使用pdfminer解析pdf文件的实现
Sep 25 Python
解决pyCharm中 module 调用失败的问题
Feb 12 Python
python 实现非极大值抑制算法(Non-maximum suppression, NMS)
Oct 15 Python
教你使用Sublime text3搭建Python开发环境及常用插件安装另分享Sublime text3最新激活注册码
Nov 12 Python
彻底弄懂Python中的回调函数(callback)
Jun 25 Python
简单介绍Python的轻便web框架Bottle
Apr 08 #Python
常见的在Python中实现单例模式的三种方法
Apr 08 #Python
分析Python的Django框架的运行方式及处理流程
Apr 08 #Python
给Python的Django框架下搭建的BLOG添加RSS功能的教程
Apr 08 #Python
在Python中使用NLTK库实现对词干的提取的教程
Apr 08 #Python
使用Python操作Elasticsearch数据索引的教程
Apr 08 #Python
用Python实现协同过滤的教程
Apr 08 #Python
You might like
几个php应用技巧
2008/03/27 PHP
php获取客户端电脑屏幕参数的方法
2015/01/09 PHP
在Linux系统的服务器上隐藏PHP版本号的方法
2015/06/06 PHP
PHP基于DOMDocument解析和生成xml的方法分析
2017/07/17 PHP
PHP+redis实现的悲观锁机制示例
2018/06/12 PHP
laravel excel 上传文件保存到本地服务器功能
2019/11/14 PHP
从新浪弄下来的全屏广告代码 与使用说明
2007/03/15 Javascript
传智播客学习之java 反射
2009/11/22 Javascript
jQuery下的几个你可能没用过的功能
2010/08/29 Javascript
javascript getElementsByClassName实现代码
2010/10/11 Javascript
基于jQuery实现左右div自适应高度完全相同的代码
2012/08/09 Javascript
用js实现table单元格高宽调整,兼容合并单元格(兼容IE6、7、8、FF)实例
2013/06/25 Javascript
多种方法判断Javascript对象是否存在
2013/09/22 Javascript
ExtJS4 表格的嵌套 rowExpander应用
2014/05/02 Javascript
JavaScript分页功能的实现方法
2015/04/25 Javascript
jQuery多选框选择数量限制方法
2017/02/08 Javascript
JavaScript中运算符规则和隐式类型转换示例详解
2017/09/06 Javascript
JS实现调用本地摄像头功能示例
2018/05/18 Javascript
Vue防止白屏添加首屏动画的实例
2019/10/31 Javascript
vue-video-player视频播放器使用配置详解
2020/10/23 Javascript
[38:51]2014 DOTA2国际邀请赛中国区预选赛 Orenda VS LGD-CDEC
2014/05/22 DOTA
[43:24]完美世界DOTA2联赛PWL S3 INK ICE vs DLG 第二场 12.12
2020/12/17 DOTA
Python CSV模块使用实例
2015/04/09 Python
Python多线程、异步+多进程爬虫实现代码
2016/02/17 Python
python中找出numpy array数组的最值及其索引方法
2018/04/17 Python
Python使用LDAP做用户认证的方法
2019/06/20 Python
python GUI库图形界面开发之PyQt5窗口类QMainWindow详细使用方法
2020/02/26 Python
django项目中新增app的2种实现方法
2020/04/01 Python
Django celery异步任务实现代码示例
2020/11/26 Python
HTML5中FileReader接口使用方法实例详解
2017/08/26 HTML / CSS
英国蛋糕装饰用品一站式商店:Craft Company
2019/03/18 全球购物
电大物流学生的自我评价
2013/10/25 职场文书
路政管理毕业自荐书范文
2014/02/10 职场文书
小露珠教学反思
2014/04/30 职场文书
2014年幼儿园园长工作总结
2014/12/17 职场文书
Spring Boot mybatis-config 和 log4j 输出sql 日志的方式
2021/07/26 Java/Android