Python用Django寫restful api接口


https://www.cnblogs.com/sixrain/p/9138442.html

用Python如何寫一個接口呢,首先得要有數據,可以用我們在網站上爬的數據,在上一篇文章中寫了如何用Python爬蟲,有興趣的可以看看:

 
大量的數據保存到數據庫比較方便。我用的pymsql,pymsql是Python中操作MySQL的模塊,其使用方法和MySQLdb幾乎相同。但目前在python3.x中,PyMySQL取代了MySQLdb。
 

1.連接數據庫

1
2
3
# 連接數據庫,需指定charset否則可能會報錯
db = pymysql.connect(host= "localhost" , user= "root" , password= "123" , db= "mysql" , charset= "utf8mb4" )
cursor = db.cursor()  # 創建一個游標對象

  

2.創建數據庫

1
2
3
4
5
6
7
8
9
10
11
cursor.execute( "DROP TABLE IF EXISTS meizi_meizis" )  # 如果表存在則刪除
       # 創建表sql語句
       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)  # 執行創建數據表操作

  

3.爬取數據

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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)  # 保存到返回數組中
        return  lists

  

4.保存到數據庫

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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  in  lists:
                # print(i['meiziid'], i['title'], i['picname'], i['page_url'], i['img_url'])
                # 插入數據到數據庫sql語句,%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()  # 關閉數據庫

  

5.創建Web工程

運行我們的爬蟲,很快數據庫表里就有數據了。

然后開始寫接口。我是通過Django+rest_framework來寫的。

Django 是用 Python開發的一個免費開源的Web框架,可以用於快速搭建高性能,優雅的網站。Django 中提供了開發網站經常用到的模塊,常見的代碼都為你寫好了,減少重復的代碼。
 

Django 目錄結構

網址入口,關聯到對應的views.py中的一個函數(或者generic類),訪問網址就對應一個函數。
處理用戶發出的請求,從urls.py中對應過來, 通過渲染templates中的網頁可以將顯示內容,比如登陸后的用戶名,用戶請求的數據,輸出到網頁。
與數據庫操作相關,存入或讀取數據時用到這個,當然用不到數據庫的時候 你可以不使用。
表單,用戶在瀏覽器上輸入數據提交,對數據的驗證工作以及輸入框的生成等工作,當然你也可以不使用。
templates 文件夾
views.py 中的函數渲染templates中的Html模板,得到動態內容的網頁,當然可以用緩存來提高速度。
后台,可以用很少量的代碼就擁有一個強大的后台。
Django 的設置,配置文件,比如 DEBUG 的開關,靜態文件的位置等。
 
 

Django 常用操作

1)新建一個 django project
django-admin.py startproject project_name
 
2)新建 app
python manage.py startapp app_name
一般一個項目有多個app, 當然通用的app也可以在多個項目中使用。
還得在工程目錄的settings.py文件在配置
 
1
2
3
4
5
6
7
8
9
10
11
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下編寫代碼
1
2
def index(request):
     return  HttpResponse(u "你好" )

  

在工程目錄urls.py配置

1
2
3
4
from  learn import views  as  learn_views
urlpatterns = [
     url(r '^$' , learn_views.index), 
]

通過python manage.py runserver啟動,就會看到我們輸出的“你好”了

 
3)創建數據庫表 或 更改數據庫表或字段
在app下的models.py創建表
 
1
2
3
4
5
6
7
class  Person(models.Model):
     name = models.CharField(max_length=30)
     age = models.IntegerField()
 
     def __unicode__(self):
         # 在Python3中使用 def __str__(self):
         return  self.name

 

運行命令,就可以生成對應的表

1
2
3
4
5
Django 1.7.1及以上 用以下命令
# 1. 創建更改的文件
python manage.py makemigrations
# 2. 將生成的py文件應用到數據庫
python manage.py migrate

 

在views.py文件里就可以獲取數據庫的數據

1
2
3
4
5
6
7
8
9
10
11
12
def create(request):
     # 新建一個對象的方法有以下幾種:
     Person.objects.create(name= 'xiaoli' , age=18)
     # p = Person(name="WZ", age=23)
     # p = Person(name="TWZ")
     # p.age = 23
     # p.save()
     # 這種方法是防止重復很好的方法,但是速度要相對慢些,返回一個元組,第一個為Person對象,
     # 第二個為True或False, 新建時返回的是True, 已經存在時返回False
     # Person.objects.get_or_create(name="WZT", age=23)
     s = Person.objects. get (name= 'xiaoli' )
     return  HttpResponse(str(s))

  

6.寫接口

接口使用rest_framework,rest_framework是一套基於Django 的 REST 框架,是一個強大靈活的構建 Web API 的工具包。

寫接口三步完成:連接數據庫、取數據、數據輸出
 

1)連接數據庫

在工程目錄下的settings.py文件下配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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)取數據

既然要取數據,那model肯定得和數據庫的一致,我發現一個快捷的方式可以把數據庫中的表生成對應的model,在項目目錄下執行命令
1
python manage.py inspectdb

 

可以看到下圖

 

取我們表的model拷貝到app下的models.py里

1
2
3
4
5
6
7
8
9
10
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'

 

創建一個序列化Serializer類

提供序列化和反序列化的途徑,使之可以轉化為,某種表現形式如json。我們可以借助serializer來實現,類似於Django表單(form)的運作方式。在app目錄下,創建文件serializers.py。
1
2
3
4
5
6
7
class  MeiziSerializer(serializers.ModelSerializer):
     # ModelSerializer和Django中ModelForm功能相似
     # Serializer和Django中Form功能相似
     class  Meta:
         model = Meizis
         # 和"__all__"等價
         fields = ( 'mid' 'title' 'picname' 'page_url' 'img_url' )

 

這樣在views.py就可以來獲取數據庫的數據了

1
2
3
meizis = Meizis.objects.all()
serializer = MeiziSerializer(meizis, many=True)
return  Response(serializer.data)

  


3) 數據輸出客戶端或前端

 REST框架提供了兩種編寫API視圖的封裝。
  • @api_view裝飾器,基於方法的視圖。
  • 繼承APIView類,基於類的視圖。
 
request.data會自行處理輸入的json請求
使用格式后綴明確的指向指定的格式,需要添加一個format關鍵字參數
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
1
2
3
4
5
6
7
8
9
10
11
12
13
@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)分頁

最后別忘了在urls.py配置URL,通過瀏覽器就可以看到json數據了。

 

 當然app也是可以調用我們的接口的


還有個問題

我們的數據有好幾千條,一塊返回來很不合理,所以需要分頁,當然rest_framework框架提供了這個功能,post請求不支持,需要自己查數據庫或者切片來進行返回。來看看rest_framework是如何來分頁的。在models.py里創建一個類
 
1
2
3
4
5
6
7
8
9
class  StandardResultSetPagination(LimitOffsetPagination):
     # 默認每頁顯示的條數
     default_limit = 20
     # url 中傳入的顯示數據條數的參數
     limit_query_param =  'limit'
     # url中傳入的數據位置的參數
     offset_query_param =  'offset'
     # 最大每頁顯示條數
     max_limit = None

  

在serializers.py創建倆個類,為什么是倆個?因為我們有倆個接口,一個明細,一個列表,而列表是不需要把字段的所有數據都返回的

1
2
3
4
5
6
7
8
9
10
class  ListSerialize(serializers.ModelSerializer):
     class  Meta:
         model = Meizis
         fields = ( 'mid' 'title' )
 
 
class  ListPicSerialize(serializers.ModelSerializer):
     class  Meta:
         model = Meizis
         fields =  "__all__"

  

在views.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
28
29
30
@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
         # 根據url參數 獲取分頁數據
         obj = StandardResultSetPagination()
         page_list = obj.paginate_queryset(meizis, request)
         # 對數據序列化 普通序列化 顯示的只是數據
         ser = ListSerialize(instance=page_list, many=True)  # 多個many=True # instance:把對象序列化
         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是用來獲取一個對象的,如果需要獲取滿足條件的一些數據,就要用到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( '請傳mid' ))

  

到這里就完成了接口的編寫,都是對框架的簡單使用,希望對大家有幫助。
 
 
GitHub地址,歡迎star
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM