Python利用Django如何寫(xiě)restful api接口詳解
前言
用Python如何寫(xiě)一個(gè)接口呢,首先得要有數(shù)據(jù),可以用我們?cè)诰W(wǎng)站上爬的數(shù)據(jù),在上一篇文章中寫(xiě)了如何用Python爬蟲(chóng),有興趣的可以看看:http://www.fzitv.net/article/141661.htm
大量的數(shù)據(jù)保存到數(shù)據(jù)庫(kù)比較方便。我用的pymsql,pymsql是Python中操作MySQL的模塊,其使用方法和MySQLdb幾乎相同。但目前在python3.x中,PyMySQL取代了MySQLdb。
1.連接數(shù)據(jù)庫(kù)
# 連接數(shù)據(jù)庫(kù),需指定charset否則可能會(huì)報(bào)錯(cuò) db = pymysql.connect(host="localhost", user="root", password="123", db="mysql", charset="utf8mb4") cursor = db.cursor() # 創(chuàng)建一個(gè)游標(biāo)對(duì)象
2.創(chuàng)建數(shù)據(jù)庫(kù)
cursor.execute("DROP TABLE IF EXISTS meizi_meizis") # 如果表存在則刪除
# 創(chuàng)建表sql語(yǔ)句
createTab = """create table meizi_meizis(
id int primary key auto_increment,
mid varchar(10) not null,
title varchar(50),
picname varchar(10),
page_url varchar(50),
img_url varchar(50)
);"""
cursor.execute(createTab) # 執(zhí)行創(chuàng)建數(shù)據(jù)表操作
3.爬取數(shù)據(jù)
def html(self, href, title):
lists = []
meiziid = href.split('/')[-1]
html = self.request(href)
max_span = BeautifulSoup(html.text, 'lxml').find('div', class_='pagenavi').find_all('span')[-2].get_text()
for page in range(1, int(max_span) + 1):
meizi = {}
page_url = href + '/' + str(page)
img_html = self.request(page_url)
img_url = BeautifulSoup(img_html.text, 'lxml').find('div', class_='main-image').find('img')['src']
picname = img_url[-9:-4]
meizi['meiziid'] = meiziid
meizi['title'] = title
meizi['picname'] = picname
meizi['page_url'] = page_url
meizi['img_url'] = img_url
lists.append(meizi) # 保存到返回?cái)?shù)組中
return lists
4.保存到數(shù)據(jù)庫(kù)
def all_url(self, url):
html = self.request(url)
all_a = BeautifulSoup(html.text, 'lxml').find('div', class_='all').find_all('a')
for index, a in enumerate(all_a):
title = a.get_text()
href = a['href']
lists = self.html(href, title)
for i in lists:
# print(i['meiziid'], i['title'], i['picname'], i['page_url'], i['img_url'])
# 插入數(shù)據(jù)到數(shù)據(jù)庫(kù)sql語(yǔ)句,%s用作字符串占位
sql = "INSERT INTO `meizi_meizis`(`mid`,`title`,`picname`,`page_url`,`img_url`) VALUES(%s,%s,%s,%s,%s)"
try:
cursor.execute(sql, (i['meiziid'], i['title'], i['picname'], i['page_url'], i['img_url']))
db.commit()
print(i[0] + " is success")
except:
db.rollback()
db.close() # 關(guān)閉數(shù)據(jù)庫(kù)
5.創(chuàng)建Web工程
運(yùn)行我們的爬蟲(chóng),很快數(shù)據(jù)庫(kù)表里就有數(shù)據(jù)了。

然后開(kāi)始寫(xiě)接口。我是通過(guò)Django+rest_framework來(lái)寫(xiě)的。
Django 是用Python開(kāi)發(fā)的一個(gè)免費(fèi)開(kāi)源的Web框架,可以用于快速搭建高性能,優(yōu)雅的網(wǎng)站。Django 中提供了開(kāi)發(fā)網(wǎng)站經(jīng)常用到的模塊,常見(jiàn)的代碼都為你寫(xiě)好了,減少重復(fù)的代碼。
Django 目錄結(jié)構(gòu)
urls.py
網(wǎng)址入口,關(guān)聯(lián)到對(duì)應(yīng)的views.py中的一個(gè)函數(shù)(或者generic類(lèi)),訪問(wèn)網(wǎng)址就對(duì)應(yīng)一個(gè)函數(shù)。
views.py
處理用戶發(fā)出的請(qǐng)求,從urls.py中對(duì)應(yīng)過(guò)來(lái), 通過(guò)渲染templates中的網(wǎng)頁(yè)可以將顯示內(nèi)容,比如登陸后的用戶名,用戶請(qǐng)求的數(shù)據(jù),輸出到網(wǎng)頁(yè)。
models.py
與數(shù)據(jù)庫(kù)操作相關(guān),存入或讀取數(shù)據(jù)時(shí)用到這個(gè),當(dāng)然用不到數(shù)據(jù)庫(kù)的時(shí)候 你可以不使用。
forms.py
表單,用戶在瀏覽器上輸入數(shù)據(jù)提交,對(duì)數(shù)據(jù)的驗(yàn)證工作以及輸入框的生成等工作,當(dāng)然你也可以不使用。
templates 文件夾
views.py 中的函數(shù)渲染templates中的Html模板,得到動(dòng)態(tài)內(nèi)容的網(wǎng)頁(yè),當(dāng)然可以用緩存來(lái)提高速度。
admin.py
后臺(tái),可以用很少量的代碼就擁有一個(gè)強(qiáng)大的后臺(tái)。
settings.py
Django 的設(shè)置,配置文件,比如 DEBUG 的開(kāi)關(guān),靜態(tài)文件的位置等。
Django 常用操作
1)新建一個(gè) django project
django-admin.py startproject project_name
2)新建 app
python manage.py startapp app_name
一般一個(gè)項(xiàng)目有多個(gè)app, 當(dāng)然通用的app也可以在多個(gè)項(xiàng)目中使用。
還得在工程目錄的settings.py文件在配置
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'rest_framework', 'meizi', ]
在app/views.py下編寫(xiě)代碼
def index(request): return HttpResponse(u"你好")
在工程目錄urls.py配置
from learn import views as learn_views urlpatterns = [ url(r'^$', learn_views.index), ]
通過(guò)python manage.py runserver啟動(dòng),就會(huì)看到我們輸出的“你好”了
3)創(chuàng)建數(shù)據(jù)庫(kù)表 或 更改數(shù)據(jù)庫(kù)表或字段
在app下的models.py創(chuàng)建表
class Person(models.Model): name = models.CharField(max_length=30) age = models.IntegerField() def __unicode__(self): # 在Python3中使用 def __str__(self): return self.name
運(yùn)行命令,就可以生成對(duì)應(yīng)的表
Django 1.7.1及以上 用以下命令 # 1. 創(chuàng)建更改的文件 python manage.py makemigrations # 2. 將生成的py文件應(yīng)用到數(shù)據(jù)庫(kù) python manage.py migrate
在views.py文件里就可以獲取數(shù)據(jù)庫(kù)的數(shù)據(jù)
def create(request): # 新建一個(gè)對(duì)象的方法有以下幾種: Person.objects.create(name='xiaoli', age=18) # p = Person(name="WZ", age=23) # p = Person(name="TWZ") # p.age = 23 # p.save() # 這種方法是防止重復(fù)很好的方法,但是速度要相對(duì)慢些,返回一個(gè)元組,第一個(gè)為Person對(duì)象, # 第二個(gè)為T(mén)rue或False, 新建時(shí)返回的是True, 已經(jīng)存在時(shí)返回False # Person.objects.get_or_create(name="WZT", age=23) s = Person.objects.get(name='xiaoli') return HttpResponse(str(s))
6.寫(xiě)接口
接口使用rest_framework,rest_framework是一套基于Django 的 REST 框架,是一個(gè)強(qiáng)大靈活的構(gòu)建 Web API 的工具包。
寫(xiě)接口三步完成:連接數(shù)據(jù)庫(kù)、取數(shù)據(jù)、數(shù)據(jù)輸出
1)連接數(shù)據(jù)庫(kù)
在工程目錄下的settings.py文件下配置
DATABASES = {
# 'default': {
# 'ENGINE': 'django.db.backends.sqlite3',
# 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
# }
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'mysql',
'USER': 'root',
'HOST': '127.0.0.1',
'PASSWORD': '123',
'PORT': 3306,
# show variables like 'character_set_database';
# 修改字段字符編碼
# alter table spiders_weibo modify text longtext charset utf8mb4 collate utf8mb4_unicode_ci;
'OPTIONS': {'charset': 'utf8mb4'},
}
}
2)取數(shù)據(jù)
既然要取數(shù)據(jù),那model肯定得和數(shù)據(jù)庫(kù)的一致,我發(fā)現(xiàn)一個(gè)快捷的方式可以把數(shù)據(jù)庫(kù)中的表生成對(duì)應(yīng)的model,在項(xiàng)目目錄下執(zhí)行命令
python manage.py inspectdb
可以看到下圖

取我們表的model拷貝到app下的models.py里
class Meizis(models.Model): mid = models.CharField(max_length=10) title = models.CharField(max_length=50, blank=True, null=True) picname = models.CharField(max_length=10, blank=True, null=True) page_url = models.CharField(max_length=50, blank=True, null=True) img_url = models.CharField(max_length=50, blank=True, null=True) class Meta: managed = False db_table = 'meizi_meizis'
創(chuàng)建一個(gè)序列化Serializer類(lèi)
提供序列化和反序列化的途徑,使之可以轉(zhuǎn)化為,某種表現(xiàn)形式如json。我們可以借助serializer來(lái)實(shí)現(xiàn),類(lèi)似于Django表單(form)的運(yùn)作方式。在app目錄下,創(chuàng)建文件serializers.py。
class MeiziSerializer(serializers.ModelSerializer):
# ModelSerializer和Django中ModelForm功能相似
# Serializer和Django中Form功能相似
class Meta:
model = Meizis
# 和"__all__"等價(jià)
fields = ('mid', 'title', 'picname', 'page_url', 'img_url')
這樣在views.py就可以來(lái)獲取數(shù)據(jù)庫(kù)的數(shù)據(jù)了
meizis = Meizis.objects.all() serializer = MeiziSerializer(meizis, many=True) return Response(serializer.data)
3) 數(shù)據(jù)輸出客戶端或前端
REST框架提供了兩種編寫(xiě)API視圖的封裝。
- @api_view裝飾器,基于方法的視圖。
- 繼承APIView類(lèi),基于類(lèi)的視圖。
request.data會(huì)自行處理輸入的json請(qǐng)求
使用格式后綴明確的指向指定的格式,需要添加一個(gè)format關(guān)鍵字參數(shù)
http http://127.0.0.1:8000/getlist.json # JSON 后綴
http://127.0.0.1:8000/getlist.api # 可視化 API 后綴
http://127.0.0.1:8000/getlist/ code="print 123"post
@api_view(['GET', 'POST']) def getlist(request, format=None): if request.method == 'GET': meizis = Meizis.objects.all() serializer = MeiziSerializer(meizis, many=True) return Response(serializer.data) elif request.method == 'POST': serializer = MeiziSerializer(data=request.data) if serializer.is_valid(): serializer.save() return Response(serializer.data, status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
4)分頁(yè)
最后別忘了在urls.py配置URL,通過(guò)瀏覽器就可以看到j(luò)son數(shù)據(jù)了。


當(dāng)然app也是可以調(diào)用我們的接口的


還有個(gè)問(wèn)題
我們的數(shù)據(jù)有好幾千條,一塊返回來(lái)很不合理,所以需要分頁(yè),當(dāng)然rest_framework框架提供了這個(gè)功能,post請(qǐng)求不支持,需要自己查數(shù)據(jù)庫(kù)或者切片來(lái)進(jìn)行返回。來(lái)看看rest_framework是如何來(lái)分頁(yè)的。在models.py里創(chuàng)建一個(gè)類(lèi)
class StandardResultSetPagination(LimitOffsetPagination): # 默認(rèn)每頁(yè)顯示的條數(shù) default_limit = 20 # url 中傳入的顯示數(shù)據(jù)條數(shù)的參數(shù) limit_query_param = 'limit' # url中傳入的數(shù)據(jù)位置的參數(shù) offset_query_param = 'offset' # 最大每頁(yè)顯示條數(shù) max_limit = None
在serializers.py創(chuàng)建倆個(gè)類(lèi),為什么是倆個(gè)?因?yàn)槲覀冇袀z個(gè)接口,一個(gè)明細(xì),一個(gè)列表,而列表是不需要把字段的所有數(shù)據(jù)都返回的
class ListSerialize(serializers.ModelSerializer):
class Meta:
model = Meizis
fields = ('mid', 'title')
class ListPicSerialize(serializers.ModelSerializer):
class Meta:
model = Meizis
fields = "__all__"
在views.py里編寫(xiě)
@api_view(['GET'])
def getlist(request, format=None):
if request.method == 'GET':
meizis = Meizis.objects.values('mid','title').distinct()
# http: // 127.0.0.1:8000 / getlist?limit = 20
# http: // 127.0.0.1:8000 / getlist?limit = 20 & offset = 20
# http: // 127.0.0.1:8000 / getlist?limit = 20 & offset = 40
# 根據(jù)url參數(shù) 獲取分頁(yè)數(shù)據(jù)
obj = StandardResultSetPagination()
page_list = obj.paginate_queryset(meizis, request)
# 對(duì)數(shù)據(jù)序列化 普通序列化 顯示的只是數(shù)據(jù)
ser = ListSerialize(instance=page_list, many=True) # 多個(gè)many=True # instance:把對(duì)象序列化
response = obj.get_paginated_response(ser.data)
return response
@api_view(['GET', 'POST'])
def getlispic(request, format=None):
if request.method == 'GET':
mid = request.GET['mid']
if mid is not None:
# get是用來(lái)獲取一個(gè)對(duì)象的,如果需要獲取滿足條件的一些數(shù)據(jù),就要用到filter
meizis = Meizis.objects.filter(mid=mid)
obj = StandardResultSetPagination()
page_list = obj.paginate_queryset(meizis, request)
ser = ListPicSerialize(instance=page_list, many=True)
response = obj.get_paginated_response(ser.data)
return response
else:
return Response(str('請(qǐng)傳mid'))
到這里就完成了接口的編寫(xiě),都是對(duì)框架的簡(jiǎn)單使用,希望對(duì)大家有幫助。
GitHub地址,歡迎star
爬蟲(chóng)項(xiàng)目:https://github.com/peiniwan/CreeperTest(本地下載)
Web項(xiàng)目:https://github.com/peiniwan/mysite (本地下載)
APP項(xiàng)目:https://github.com/peiniwan/Ganhuo (本地下載)
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)腳本之家的支持。
- python模塊restful使用方法實(shí)例
- 在Python的框架中為MySQL實(shí)現(xiàn)restful接口的教程
- Python restful框架接口開(kāi)發(fā)實(shí)現(xiàn)
- Python實(shí)現(xiàn)Restful API的例子
- Python中Flask-RESTful編寫(xiě)API接口(小白入門(mén))
- 使用Python & Flask 實(shí)現(xiàn)RESTful Web API的實(shí)例
- Python進(jìn)行Restful?API開(kāi)發(fā)實(shí)例詳解
- python用post訪問(wèn)restful服務(wù)接口的方法
- python Flask實(shí)現(xiàn)restful api service
- 探索?Python?Restful?接口測(cè)試的奧秘
相關(guān)文章
python中的reduce內(nèi)建函數(shù)使用方法指南
python中的reduce內(nèi)建函數(shù)是一個(gè)二元操作函數(shù),他用來(lái)將一個(gè)數(shù)據(jù)集合(鏈表,元組等)中的所有數(shù)據(jù)進(jìn)行下列操作:用傳給reduce中的函數(shù) func()(必須是一個(gè)二元操作函數(shù))先對(duì)集合中的第1,2個(gè)數(shù)據(jù)進(jìn)行操作,得到的結(jié)果再與第三個(gè)數(shù)據(jù)用func()函數(shù)運(yùn)算,最后得到一個(gè)結(jié)果2014-08-08
對(duì)Tensorflow中的矩陣運(yùn)算函數(shù)詳解
今天小編就為大家分享一篇對(duì)Tensorflow中的矩陣運(yùn)算函數(shù)詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-07-07
python修改linux中文件(文件夾)的權(quán)限屬性操作
這篇文章主要介紹了python修改linux中文件(文件夾)的權(quán)限屬性操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-03-03
Python 中的判斷語(yǔ)句,循環(huán)語(yǔ)句,函數(shù)
這篇文章主要介紹了Python 中的判斷語(yǔ)句,循環(huán)語(yǔ)句,函數(shù),文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-08-08
python多進(jìn)程日志以及分布式日志的實(shí)現(xiàn)方式
這篇文章主要介紹了python多進(jìn)程日志以及分布式日志的實(shí)現(xiàn)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-06-06
Python天氣預(yù)報(bào)采集器實(shí)現(xiàn)代碼(網(wǎng)頁(yè)爬蟲(chóng))
這個(gè)天氣預(yù)報(bào)采集是從中國(guó)天氣網(wǎng)提取廣東省內(nèi)主要城市的天氣并回顯。本來(lái)是打算采集騰訊天氣的,但是貌似它的數(shù)據(jù)是用js寫(xiě)上去還是什么的,得到的html文本中不包含數(shù)據(jù),所以就算了2012-10-10
Python+wxauto實(shí)現(xiàn)微信自動(dòng)化操作
在眾多自動(dòng)化工具中,Python的wxauto庫(kù)以其強(qiáng)大的功能和簡(jiǎn)單易用的特點(diǎn),為我們打開(kāi)了微信自動(dòng)化操作的大門(mén),下面我們就來(lái)看看它的具體操作吧2025-02-02

