Python用Django寫restful api接口

用Python如何寫一個接口呢,首先得要有數據,能夠用咱們在網站上爬的數據,在上一篇文章中寫了如何用Python爬蟲,有興趣的能夠看看:
 
大量的數據保存到數據庫比較方便。我用的pymsql,pymsql是Python中操做MySQL的模塊,其使用方法和MySQLdb幾乎相同。但目前在python3.x中,PyMySQL取代了MySQLdb。
 

1.鏈接數據庫

# 鏈接數據庫,需指定charset不然可能會報錯
db = pymysql.connect(host="localhost", user="root", password="123", db="mysql", charset="utf8mb4")
cursor = db.cursor()  # 建立一個遊標對象

  

2.建立數據庫

  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.爬取數據

 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.保存到數據庫

 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'])
                # 插入數據到數據庫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來寫的。html

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文件在配置
 
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下編寫代碼
def index(request):
    return HttpResponse(u"你好")

  

在工程目錄urls.py配置前端

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

經過python manage.py runserver啓動,就會看到咱們輸出的「你好」了python

 
3)建立數據庫表 或 更改數據庫表或字段
在app下的models.py建立表
 
class Person(models.Model):
    name = models.CharField(max_length=30)
    age = models.IntegerField()

    def __unicode__(self):
        # 在Python3中使用 def __str__(self):
        return self.name

 

運行命令,就能夠生成對應的表mysql

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

 

在views.py文件裏就能夠獲取數據庫的數據git

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 的工具包。github

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

1)鏈接數據庫

在工程目錄下的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)取數據

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

 

能夠看到下圖sql

 

取咱們表的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'

 

建立一個序列化Serializer類django

提供序列化和反序列化的途徑,使之能夠轉化爲,某種表現形式如json。咱們能夠藉助serializer來實現,相似於Django表單(form)的運做方式。在app目錄下,建立文件serializers.py。
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就能夠來獲取數據庫的數據了json

        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
@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裏建立一個類
 
class StandardResultSetPagination(LimitOffsetPagination):
    # 默認每頁顯示的條數
    default_limit = 20
    # url 中傳入的顯示數據條數的參數
    limit_query_param = 'limit'
    # url中傳入的數據位置的參數
    offset_query_param = 'offset'
    # 最大每頁顯示條數
    max_limit = None

  

在serializers.py建立倆個類,爲何是倆個?由於咱們有倆個接口,一個明細,一個列表,而列表是不須要把字段的全部數據都返回的

class ListSerialize(serializers.ModelSerializer):
    class Meta:
        model = Meizis
        fields = ('mid', 'title')


class ListPicSerialize(serializers.ModelSerializer):
    class Meta:
        model = Meizis
        fields = "__all__"

  

在views.py裏編寫
@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
相關文章
相關標籤/搜索