Maison développement back-end Tutoriel Python 在Python的框架中为MySQL实现restful接口的教程

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

Jun 10, 2016 pm 03:15 PM
mysql python

最近在做游戏服务分层的时候,一直想把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版自带了一个可视化的操作页面,如下:

201548172936523.png (600×545)

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',
  ]
}

Copier après la connexion

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)

Copier après la connexion

4. 在demo下新建serializers.py

<p>from rest_framework import serializers<br />from models import User</p>
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
Copier après la connexion


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

Copier après la connexion

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)),
)

Copier après la connexion

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'))
)

Copier après la connexion

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

python manage.py syncdb
 
python manage.py syncdb

Copier après la connexion

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

201548173034739.png (600×353)

对应的测试代码如下:

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

Copier après la connexion

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

OK,就这样。

Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn

Article chaud

Musée de deux points: Guide de localisation de Bungle Wasteland
4 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
Combien de temps faut-il pour battre Split Fiction?
3 Il y a quelques semaines By DDD
Repo: Comment relancer ses coéquipiers
3 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island Adventure: Comment obtenir des graines géantes
3 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌

Article chaud

Musée de deux points: Guide de localisation de Bungle Wasteland
4 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
Combien de temps faut-il pour battre Split Fiction?
3 Il y a quelques semaines By DDD
Repo: Comment relancer ses coéquipiers
3 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island Adventure: Comment obtenir des graines géantes
3 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌

Tags d'article chaud

Bloc-notes++7.3.1

Bloc-notes++7.3.1

Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise

SublimeText3 version chinoise

Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1

Envoyer Studio 13.0.1

Puissant environnement de développement intégré PHP

Dreamweaver CS6

Dreamweaver CS6

Outils de développement Web visuel

SublimeText3 version Mac

SublimeText3 version Mac

Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Comment télécharger Deepseek Xiaomi Comment télécharger Deepseek Xiaomi Feb 19, 2025 pm 05:27 PM

Comment télécharger Deepseek Xiaomi

Comment optimiser les performances des requêtes MySQL en PHP ? Comment optimiser les performances des requêtes MySQL en PHP ? Jun 03, 2024 pm 08:11 PM

Comment optimiser les performances des requêtes MySQL en PHP ?

Google AI annonce Gemini 1.5 Pro et Gemma 2 pour les développeurs Google AI annonce Gemini 1.5 Pro et Gemma 2 pour les développeurs Jul 01, 2024 am 07:22 AM

Google AI annonce Gemini 1.5 Pro et Gemma 2 pour les développeurs

Comment utiliser la sauvegarde et la restauration MySQL en PHP ? Comment utiliser la sauvegarde et la restauration MySQL en PHP ? Jun 03, 2024 pm 12:19 PM

Comment utiliser la sauvegarde et la restauration MySQL en PHP ?

Comment insérer des données dans une table MySQL en utilisant PHP ? Comment insérer des données dans une table MySQL en utilisant PHP ? Jun 02, 2024 pm 02:26 PM

Comment insérer des données dans une table MySQL en utilisant PHP ?

Comment corriger les erreurs mysql_native_password non chargé sur MySQL 8.4 Comment corriger les erreurs mysql_native_password non chargé sur MySQL 8.4 Dec 09, 2024 am 11:42 AM

Comment corriger les erreurs mysql_native_password non chargé sur MySQL 8.4

Comment utiliser les procédures stockées MySQL en PHP ? Comment utiliser les procédures stockées MySQL en PHP ? Jun 02, 2024 pm 02:13 PM

Comment utiliser les procédures stockées MySQL en PHP ?

Comment lui demandez-vous Deepseek Comment lui demandez-vous Deepseek Feb 19, 2025 pm 04:42 PM

Comment lui demandez-vous Deepseek

See all articles