在這個(gè)例子中,我們將使用Django編寫?zhàn)I了么高校外賣商家查詢API接口笼痹,并且使用AJAX技術(shù)來實(shí)現(xiàn)API接口的使用蹭沛,包括使用ajax get方法加載更多數(shù)據(jù)排截,使用ajax方法來更新娱节、修改挠蛉、新增、刪除數(shù)據(jù)肄满。利用API可以做到前后端分離谴古,為開發(fā)web應(yīng)用提供了便利。
安裝rest framework
首先使用Pycharm新建一個(gè)Django項(xiàng)目稠歉,并且使用virtualenv或者pipenv虛擬環(huán)境
創(chuàng)建成功會(huì)自動(dòng)安裝Django2.1和所需依賴掰担,restframework框架需要自己手動(dòng)安裝
//激活虛擬環(huán)境安裝以下
(venv)$ pip install djangorestframework
(venv)$ pip install django-filter
(venv)$ pip install pytest
(venv)$ pip install pytest-django
//由于筆者使用Postgresql數(shù)據(jù)庫,所以還需要安裝以下
(venv)$ pip install psycopg2
//使用mysql數(shù)據(jù)庫安裝如下
(venv)$ pip install pymysql
準(zhǔn)備數(shù)據(jù)來提供服務(wù)
數(shù)據(jù)來源:餓了么爬蟲
數(shù)據(jù)內(nèi)容:全國(guó)所有大學(xué)附近的外賣商家Top20
數(shù)據(jù)需要導(dǎo)入數(shù)據(jù)庫
Django編寫rest api接口
項(xiàng)目結(jié)構(gòu)
小編最近整理了一套Python學(xué)習(xí)教程怒炸,有需要的小伙伴带饱,記得來小編的交流群:556370268,即可免費(fèi)領(lǐng)取一套Python學(xué)習(xí)教程哦
settings.py.
// 安裝的app如下
INSTALLED_APPS = [
#...
'rest_framework',
'django_filters',
'api.apps.ApiConfig',
'front.apps.FrontConfig',
]
//restframework 配置如下
REST_FRAMEWORK = {
//這里配置了分頁處理阅羹,每頁最多20個(gè)項(xiàng)目
'DEFAULT_PAGINATION_CLASS':'api.custompagination.LimitOffsetPaginationWithUpperBound',
'PAGE_SIZE': 20,
'DEFAULT_FILTER_BACKENDS': (
//這里配置了排序勺疼、過濾、搜索器
'django_filters.rest_framework.DjangoFilterBackend',
'rest_framework.filters.OrderingFilter',
'rest_framework.filters.SearchFilter',
),
//這里配置了用戶認(rèn)證捏鱼,管理員才可以更改內(nèi)容执庐,未登錄不能更改
'DEFAULT_AUTHENTICATION_CLASSES':(
'rest_framework.authentication.BasicAuthentication',
'rest_framework.authentication.SessionAuthentication',
),
//這里配置了訪問次數(shù)限制,過多會(huì)返回429錯(cuò)誤 too many requests
'DEFAULT_THROTTLE_CLASSES': (
'rest_framework.throttling.AnonRateThrottle',
'rest_framework.throttling.UserRateThrottle',
),
//這里配置了訪問次數(shù)导梆,anon代表匿名用戶轨淌,user代表已登錄用戶,entries是我自己設(shè)置的作用域看尼,300/hour代表最多300次每小時(shí)
'DEFAULT_THROTTLE_RATES': {
'anon': '300/hour',
'user': '100/hour',
'entries': '200/hour',
},
'DEFAULT_VERSIONING_CLASS':'rest_framework.versioning.NamespaceVersioning',
}
models.py.
from django.db import models
class Entry(models.Model):
city = models.CharField(max_length=50)
school = models.CharField(max_length=100)
link = models.CharField(max_length=100,null=True,default='null')
name = models.CharField(max_length=200)
lat = models.CharField(max_length=20,null=True,default='0.0')
lng = models.CharField(max_length=20,null=True,default='0.0')
address = models.CharField(max_length=200,null=True,default='null')
distance = models.CharField(max_length=20,null=True,default='0')
time = models.CharField(max_length=20,null=True,default='0:00')
contact = models.CharField(max_length=200,null=True,default='null')
score = models.CharField(max_length=10,null=True,default='0')
comments = models.CharField(max_length=20,null=True,default='0')
sell = models.CharField(max_length=20,null=True,default='0')
image = models.CharField(max_length=200,null=True,default='null')
owner = models.ForeignKey('auth.User',related_name='entries',on_delete=models.CASCADE)
# class Meta:
# ordering = ('name',)
def __str__(self):
return self.name
serializers.py.
from rest_framework import serializers
from api.models import Entry
//這里繼承自超鏈接模型序列器递鹉,用于把數(shù)據(jù)轉(zhuǎn)換為json格式,并且顯示鏈接
class EntrySerializer(serializers.HyperlinkedModelSerializer):
owner = serializers.ReadOnlyField(source='owner.username')
class Meta:
model = Entry
fields = ('url','pk','name','city','school','link','lat','lng','address','distance','time','contact',
'score','comments','sell','image','owner')
views.py.
from rest_framework import generics
from rest_framework.response import Response
from rest_framework.reverse import reverse
from api.models import Entry
from api.serializers import EntrySerializer
from rest_framework import permissions
from rest_framework.permissions import IsAuthenticated
from rest_framework.throttling import ScopedRateThrottle
from api import custompermission
//這里是獲取所有數(shù)據(jù)藏斩,可實(shí)現(xiàn)HTTP get躏结、Post、Option操作
class EntryList(generics.ListCreateAPIView):
//限流自定義作用域
throttle_scope = 'entries'
throttle_classes = (ScopedRateThrottle,)
queryset = Entry.objects.all()
serializer_class = EntrySerializer
name = 'entry-list'
filter_fields = ('city','school','name')
search_fields = ('school','city')
ordering_fields = ('city')
//管理員才能post操作創(chuàng)建新的數(shù)據(jù)
permission_classes = (
permissions.IsAuthenticatedOrReadOnly,
custompermission.IsCurrentUserOwnerOrReadOnly,
)
def perform_create(self, serializer):
serializer.save(owner=self.request.user)
//這里是獲取具體某一項(xiàng)的數(shù)據(jù)灾茁,可實(shí)現(xiàn)HTTP GET窜觉、PUT谷炸、PATCH、Option操作
class EntryDetail(generics.RetrieveUpdateDestroyAPIView):
throttle_scope = 'entries'
throttle_classes = (ScopedRateThrottle,)
queryset = Entry.objects.all()
serializer_class = EntrySerializer
name = 'entry-detail'
permission_classes = (
permissions.IsAuthenticatedOrReadOnly,
custompermission.IsCurrentUserOwnerOrReadOnly,
)
//api根目錄
class ApiRoot(generics.GenericAPIView):
name = 'api-root'
def get(self, request, *args, **kwargs):
return Response({
'entries': reverse(EntryList.name, request=request),
})
urls.py.
from django.urls import path
from api import views
urlpatterns = [
path('entries/', views.EntryList.as_view(), name=views.EntryList.name),
path('entry-detail/<int:pk>', views.EntryDetail.as_view(), name=views.EntryDetail.name),
path('', views.ApiRoot.as_view(), name=views.ApiRoot.name)
]
ele/urls.py.
from django.urls import path,include
urlpatterns = [
path('v1/',include('api.urls')),
path('v1/api-auth/',include('rest_framework.urls')),
path('',include('front.urls'))
]
以下為啟動(dòng)界面
到此為止非常簡(jiǎn)單的api就寫完了禀挫,接下來就是自動(dòng)化測(cè)試是否達(dá)到預(yù)期效果旬陡。
如圖,測(cè)試通過语婴!
在程序中調(diào)用剛剛寫好的api
創(chuàng)建一個(gè)新的app并且添加到settings.py里面
(venv)$ python manage.py startapp front
做好的效果如下:點(diǎn)擊加載更多會(huì)觸發(fā)ajax
由于篇幅有限描孟,這里貼出js代碼
使用ajax get請(qǐng)求剛剛寫好的api接口并且添加到表格中
myjs.js.
$('#load-more').click(function () {
$.ajax({
method:'GET',
url:api_url,
dataType:'json',
success:function (data) {
api_url = data['next'];
if (api_url == null){
$('#load-more').val('已加載全部');
$('#load-more').attr('disabled',true);
//api_url這里就是剛剛寫好的api接口
api_url = 'v1/entries/';
}
var results = data['results'];
for (i=0;i<results.length;i++){
$('#ele-table-body').append(
' <tr>\n' +
' <th scope="col">'+results[i]['pk']+'</th>\n' +
' <th scope="col">'+results[i]['city']+'</th>\n' +
' <th scope="col"><a href="/detail/' + results[i]['pk'] +'">' + results[i]['name'] + '</a></th>\n' +
' <th scope="col">'+results[i]['school']+'</th>\n' +
' <th scope="col">'+results[i]['score']+'</th>\n' +
' </tr>'
)
}
}
})
});
可以修改具體的一條數(shù)據(jù),使用ajax patch方法提交數(shù)據(jù)砰左。
注:PUT方法是修改所有數(shù)據(jù)匿醒,而PATCH方法是修改局部數(shù)據(jù)
myjs.js.
$('#edit-confirm-btn').click(function () {
var name = $('#name').val();
var distance = $('#distance').val();
var adderss = $('#address').val();
var time = $('#time').val();
var score = $('#score').val();
var comments = $('#comments').val();
var sell = $('#sell').val();
var pk = $('#pk').val();
$.ajax({
type:'PATCH',
url:'/detail/' + pk,
data:{
"name": name,
"distance": distance,
"address": adderss,
"time": time,
"score": score,
"comments": comments,
"sell": sell,
},
success:function (data) {
if (data.status == 'ok'){
console.log('success');
location.reload();
}
}
})
})
本文通過一個(gè)小例子介紹了如何使用Django調(diào)用自己寫的api