python restful api_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(

idint primary key auto_increment,

mid varchar(10) notnull,

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 pagein 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, ain enumerate(all_a):

title = a.get_text()

href = a['href']

lists = self.html(href, title)

for iin 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工程

运行我们的爬虫,很快数据库表里就有数据了。

827512-20180605104705648-902001749.png

然后开始写接口。我是通过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 viewsas 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

可以看到下图

827512-20180605103809526-1776036142.png

取我们表的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数据了。

9931795.html

9931795.html

827512-20180605105201595-1309487419.png

827512-20180605105225823-1754220282.png

当然app也是可以调用我们的接口的

827512-20180605105403515-217219056.png

827512-20180605105445911-2109047059.jpg

还有个问题

我们的数据有好几千条,一块返回来很不合理,所以需要分页,当然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 midis 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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值