前天研究了一番Django,果然很好使,今天就使用Django设计一个简单API Server试试。
目标
Model类型
以一个旅游日志App为例,我们需要两个Model分别为Trip和Day。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| Trip { id : AutoField(primary_key=True) trip_title : CharField(max_length=100) trip_subtitle : CharField(max_length=100) cover : TextField() pub_time : DateTimeField('date published') place : CharField(max_length=100) likeCount : IntegerField(default=0) } /保存每段旅程具体日子的相关信息 Day { id : AutoField(primary_key=True) trip_title : CharField(max_length=100) trip_subtitle : CharField(max_length=100) trip_day : IntegerField(default=1) cover : TextField() pub_time : DateTimeField('date published') place : CharField(max_length=100) likeCount : IntegerField(default=0) content : TextField() trip : ForeignKey(Trip) }
|
URL分配
实现过程
创建Project和App
首先使用$ django-admin startproject sampleapi
创建一个Project,按照Django学习笔记中方法设置数据库。
使用$ python manage.py startapp api001
来创建第一版API。并且Project配置文件samplepai/settings.py
中增加api001
1 2 3 4 5 6 7 8 9
| INSTALLED_APPS = ( 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'api001' )
|
Models
创建Model
编辑sampleapi/api001/models.py
文件,增加两个model
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| from django.db import models
class Trip(models.Model): id = models.AutoField(primary_key=True) trip_title = models. CharField(max_length=100) trip_subtitle = models.CharField(max_length=100) cover = models.TextField() pub_time = models.DateTimeField('date published') place = models.CharField(max_length=100) likeCount = models.IntegerField(default=0) def __str__(self): return self.trip_title
class Day(models.Model): id = models.AutoField(primary_key=True) trip_title = models.CharField(max_length=100) trip_subtitle = models.CharField(max_length=100) trip_day = models.IntegerField(default=1) cover = models.TextField() pub_time = models.DateTimeField('date published') place = models.CharField(max_length=100) likeCount = models.IntegerField(default=0) content = models.TextField() trip = models.ForeignKey(Trip) def __str__(self): return self.trip_title
|
创建迁移(migrations)文件,如果成功则会产生名称为0001_initial.py的文件。
1 2 3 4 5 6
| $ python manage.py makemigrations api001 Migrations for 'api001': 0001_initial.py: - Create model Day - Create model Trip - Add field trip to day
|
1 2 3 4
| $ python manage.py sqlmigrate api001 0001 $ python manage.py migrate
|
增加若干数据
使用shell
模式很方便的操作数据和熟悉Django的API,现在我们也用Shell增加几条数据。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| $ python manage.py shell
>>> from api001.models import Trip,Day
>>> Trip.objects.all() []
>>> from django.utils import timezone
>>> firsttrip = Trip(trip_title = 'trip_title',trip_subtitle = "subtitle", cover = 'notyet.png',pub_time = timezone.now(),place = "I don't know")
>>> firsttrip.save()
>>> firsttrip.id
>>> firsttrip.trip_title 'trip_title' >>> firsttrip.cover 'notyet.png' >>> firsttrip.pub_time datetime.datetime(2015, 10, 31, 9, 17, 0, 497149, tzinfo=<UTC>)
>>> t = Trip.objects.get(pk=1)
>>> t.day_set.create(trip_title = "day1", trip_day = 1 ,trip_subtitle = "subTitleHere", cover = "notyet.png", pub_time = timezone.now(),place = "I still havar no clue", content = "comments.") <Day: day1> >>> t.day_set.create(trip_title = "day2", trip_day = 2 ,trip_subtitle = "subTitleHere", cover = "notyet.png", pub_time = timezone.now(),place = "I still havar no clue", content = "comments.") <Day: day2>
>>> t.day_set.all() [<Day: day1>, <Day: day2>]
|
View & URL
配置View
打开api001/views.py
,增加下面三行
1 2 3 4 5 6
| from django.http import HttpResponse
def index(request): return HttpResponse("Hello, world. You're at the api001 index.")
|
配置URL
为了调用该目录,还需要配置URL路由表,在api001
文件夹下面增加一个urls.py
文件。此时目录结构应该如下。
1 2 3 4 5 6 7 8
| api001/ ├── admin.py ├── __init__.py ├── migrations ├── models.py ├── tests.py ├── urls.py └── views.py
|
编辑api001/urls.py
,增加下面几行
1 2 3 4 5 6 7 8 9 10
| from django.conf.urls import url
from . import views
urlpatterns = [ url(r'^$', views.index, name='index'), ]
|
编辑上级目录中的项目路由表配置文件,即sampleapi/sampleapi/urls.py
,增加下面几行
1 2 3 4 5 6
| from django.conf.urls import include, url
urlpatterns = [ url(r'^api001/', include('api001.urls')), ]
|
此时运行python manager.py 0.0.0.0:8000
,然后访问http://xxx.xxx.xxx.xxx:8000/api001/
即可看到欢迎提示。说明URL和View配置正常。
1
| Hello, world. You're at the api001 index.
|
完善
前面的工作只是为了学习配置View和URl,现在正式配置View和URL。代码如下。
views.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| from django.shortcuts import render from django.http import HttpResponse
def index(request): return HttpResponse("Hello, world. You're at the trips index.")
def tripList(request): return HttpResponse("This is the view for tripList")
def tripDetail(request,trip_id): return HttpResponse("This is the view for tripDetail %s." % trip_id)
def tripDayDetail(request,trip_id,day_id): return HttpResponse("This is the view for tripDayDetail %s-%s." % (trip_id,day_id))
|
urls.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| from django.conf.urls import url
from . import views
urlpatterns = [ url(r'^$', views.index, name='index'), url(r'^trips/$', views.tripList, name='tripList'), url(r'^trips/(?P<trip_id>[0-9]+)/$', views.tripDetail, name='tripDetail'), url(r'^trips/(?P<trip_id>[0-9]+)/(?P<day_id>[0-9]+)/$', views.tripDayDetail, name='tripDayDetail'), ]
|
配置完成后可以通过目标里的三种url访问到三个页面并且传递相应的参数。接下来要以Json形式返回数据库中的数据。
返回Json数据
Django中可以使用Django REST framework来生成Json文件。不过自己生成也没什么难度。
Python自带Json函数库能够把字典数据格式化为Json数据,所以首先我们在model中写一个相应的方法,用来把model转换成字典。
以Trip Model为例
models.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| ··· class Trip(models.Model): id = models.AutoField(primary_key=True) trip_title = models. CharField(max_length=100) trip_subtitle = models.CharField(max_length=100) cover = models.TextField() pub_time = models.DateTimeField('date published') place = models.CharField(max_length=100) likeCount = models.IntegerField(default=0)
def __str__(self): return self.trip_title
def toDict(self): tmstp = int(time.mktime(self.pub_time.timetuple())) return { 'trip_title':self.trip_title, 'trip_subtitle':self.trip_subtitle, 'cover':self.cover, 'place':self.place, 'likeCount':self.likeCount, 'pub_time' : tmstp, 'day_Count' : self.day_set.count() }
···
|
urls.py
1 2 3 4 5 6 7
| ··· def tripList(request): all_objs=Trip.objects.all() all_dicts=toDicts(all_objs) all_jsons=json.dumps(all_dicts) return HttpResponse(all_jsons) ···
|
保存后再次访问http://xxx.xxx.xxx.xxx:8000/api001/trips
即可看到相应的Json数据。
1
| [{"pub_time": 1446283020, "trip_title": "trip_title", "cover": "notyet.png", "likeCount": 0, "dayCount": 2, "place": "I don't know", "trip_subtitle": "subtitle"}]
|
进阶
关联查询
第一个API接口完成,接下来的端口需要根据Trip ID获取具体Trip和包含日程信息。可以用一下代码来实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| import json as JSON
··· def tripDetail(request,trip_id): trip = Trip.objects.get(pk=trip_id) tripDic = trip.toDict() days = trip.day_set.all() tripDic["days"] = toDicts(days) jsonObj = JSON.dumps(tripDic) return HttpResponse(jsonObj)
···
|
try-catch
有时候可能会请求一些不存在的数据,这种情况下需要做错误处理。Python自带的try/catch功能就能很好的处理这些错误。
我们首先定义一个函数来优化JSon结构,在models.py
增加函数
1 2 3 4 5 6 7 8
| def toJson(status,info,dic): jsonDic = { 'success' : status, 'info' : info, 'data' : dic } return JSON.dumps(jsonDic)
|
tripDetail方法改为
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| def tripDetail(request,trip_id): json = "" try: trip = Trip.objects.get(pk=trip_id) tripDic = trip.toDict() days = trip.day_set.all() tripDic["days"] = toDicts(days) json = toJson(True,"Success",tripDic)
except Trip.DoesNotExist: json = toJson(False,"DoesNotExist",[]) return HttpResponse(json)
|
Admin Panel
Django自带的Admin panel不需要些几行代码就允许我们很方便的管理数据。
首先设置管理员帐号
1
| python manage.py createsuperuser
|
输入帐号密码邮箱即可。创建帐号后启动服务,打开http://xxx.xxx.xxx.xxx:8000/admin/
,然后刚刚创建的帐号登录。可以看到Groups和Users两组数据。
此时我们需要把Trip和Days数据引入到admin panel。编辑api001/admin.py
,增加一下语句
1 2 3 4 5 6
| from .models import Trip, Day
admin.site.register(Trip) admin.site.register(Day)
|
刷新Admin页面就可以看到Day和Trip数据,并且能够直接在网页进行删增编辑操作。关于Admin Panel可以查阅Writing your first Django app, part 2
参考