文章目录
- 接口开发
- django原生CBV开发==商品分类菜单==接口
- 继承APIView开发==商品类型分类==接口
- 通过序列化器开发==商品详情==接口
接口开发
django原生CBV开发商品分类菜单接口
先直接给出最终的views类,先简单的解释一下:
在基于CBV(基于类视图的)的接口时,直接在类中定义名字于请求名相等的方法即可
get请求中需要先获取符合条件的数据库中的数据
result_json = {‘status’: 1000, ‘data’: []} 是先定义一个返回的格式,‘status’: 1000是这个接口的响应码,通过循环将数据库中的数据会放在data中
最后返回一个HttpResponse响应,一定要清楚接口最后返回的是JSON数据,所以在返回Http响应响应时一定要用json.dumps函数将数据转化成JSON。
在代码中的for循环中,我一共打印了三组数据,反别是item,item.to_dict,result_json。他们的类型分别是对象,字典,字典。那么to_dict函数的意义又是什么呢?因为json.dumps函数不可以直接将自定义对象转换为JSON数据,所以需要在每一个model中定义一个方法(to_dict方法)将对象先转化为字典的形式。再通过json.dumps再返回时转化为JSON。
一级菜单接口和二级菜单接口:
menu/views.py
import json
from django.http import HttpResponse
from django.views import View
from apps.menu.models import MainMenu, SubMenu
from utils import ResponseMessageclass MainMenuView(View):def get(self, request):main_menu = MainMenu.objects.all()result_json = {'status': 1000, 'data': []}for item in main_menu:# print(item) # item是对象 MainMenu object (1) MainMenu object (2) MainMenu object (3) MainMenu object (4)........# print(item.to_dict()) # {'main_menu_id': 1, 'main_menu_name': '家用电器'}{'main_menu_id': 2, 'main_menu_name': '手机'}{'main_menu_id': 2, 'main_menu_name': '运营商'}result_json['data'].append(item.to_dict()) #要通过每个item对象里的to_dict方法序列化对象# print(result_json) # 字典,并不是JSON格式的数据return HttpResponse(json.dumps(result_json), content_type='application/json')# json.drup()将字典转化为JSON,content_type='application/json'告诉客户端这个响应是JSON格式的数据,客户端应该相应地处理它。class SubMenuView(View):def get(self, request):# 获取请求的参数param_id = request.GET['main_menu_id']sub_menu = SubMenu.objects.filter(main_menu_id=param_id)# 封装一个同意接受数据返回请求的方法return ResponseMessage.MenuResponse.success(sub_menu)
在模型类中添加to_dict方法:
menu/models.py
import jsonfrom django.db import modelsclass MainMenu(models.Model):main_menu_id = models.IntegerField(verbose_name='菜单ID')main_menu_name = models.CharField(max_length=255, verbose_name='菜单名称', null=False)main_menu_url = models.CharField(max_length=255, null=True, blank=True, verbose_name='菜单地址')# 手动序列化def to_dict(self):return {'main_menu_id': self.main_menu_id,'main_menu_name': self.main_menu_name,}class Meta:db_table = 'main_menu'class SubMenu(models.Model):main_menu_id = models.IntegerField( null=True, blank=True, verbose_name='一级菜单ID')submenu_id = models.IntegerField( null=True, blank=True, verbose_name='二级菜单ID')submenu_name = models.CharField(max_length=255, verbose_name='二级菜单名称', null=False)submenu_type = models.CharField(max_length=255, null=True, blank=True, verbose_name='二级菜单类型')submenu_url = models.CharField(max_length=255, null=True, blank=True, verbose_name='二级菜单地址')def to_dict(self):return{'main_menu_id': self.main_menu_id,'submenu_id': self.submenu_id,'submenu_name': self.submenu_name,'submenu_type': self.submenu_type,'submenu_url': self.submenu_url,}class Meta:db_table = 'sub_menu'
因为在写每一个接口时,数据返回逻辑就是每一个接口都要序列化然后转化为JSON,所以干脆创建一个工具类,用来让每一个接口直接调用这个工具类。
utils/ResponseMessage.py
from django.http import HttpResponse#分类菜单
class MenuResponse():@staticmethoddef success(data):result_json = {'status': '1000', 'data': []}for item in data:result_json['data'].append(item.to_dict())return HttpResponse(json.dumps(result_json), content_type='application/json')@staticmethoddef failed(data):result_json = {'status': '1001', 'data': []}for item in data:result_json['data'].append(item.to_dict())return HttpResponse(json.dumps(result_json), content_type='application/json')@staticmethoddef other(data):result_json = {'status': '1002', 'data': []}for item in data:result_json['data'].append(item.to_dict())return HttpResponse(json.dumps(result_json), content_type='application/json')
继承APIView开发商品类型分类接口
这个接口中基于APIView的接口开发和基于View的开发没有任何区别,因为在面向对象中APIView本身就是继承于View的,所以继承APIView会先在APIView找,如果APIView没有封装该方法,那么才会执行View中的方法
from rest_framework.views import APIView
from apps.goods.models import Goods
from utils import ResponseMessage# http://localhost:8000/goods/category_id/page
class GoodsCategoryAPIView(APIView):def get(self, request, category_id, page):current_page = (page - 1) * 20 #当前页的起始位置end_page = page * 20 #当前页的结束位置category_data = Goods.objects.filter(type_id=category_id)[current_page:end_page]return ResponseMessage.GoodsResponse.success(category_data)
这个时候要在ResponseMessage.py中加入商品分类的工具类,当然不能忘记在goods/models类中加入to_dict进行手动系列化:
import decimal
import json
from django.http import HttpResponse# 商品分类
class GoodsResponse():@staticmethoddef success(data):result_json = {'status': '2000', 'data': []}for item in data:result_json['data'].append(item.to_dict())return HttpResponse(json.dumps(result_json, cls=DecimalEncoder), content_type='application/json')@staticmethoddef failed(data):result_json = {'status': '2001', 'data': []}for item in data:result_json['data'].append(item.to_dict())return HttpResponse(json.dumps(result_json, cls=DecimalEncoder), content_type='application/json')@staticmethoddef other(data):result_json = {'status': '2002', 'data': []}for item in data:result_json['data'].append(item.to_dict())return HttpResponse(json.dumps(result_json, cls=DecimalEncoder), content_type='application/json')class DecimalEncoder(json.JSONEncoder):def default(self, obj):if isinstance(obj, decimal.Decimal):return float(obj)
这个编码器类用于处理 JSON 序列化过程中的
Decimal
类型,json模块不能处理这种类型。通过指定cls
参数,你可以确保所有的Decimal
对象都被正确地转换为 JSON 字符串
通过序列化器开发商品详情接口
在使用序列化器之前,我们先用手动序列化的方式来实现商品详情接口:
goods/views
# http://localhost:8000/goods/sku_id
class GoodsDetailAPIView(APIView):def get(self, request, sku_id):good = Goods.objects.filter(sku_id=sku_id)return ResponseMessage.GoodsResponse.success(good)
因为商品详情是根据商品属性中的sku_id查找的,再此前的数据库设计的时候我没有添加这个属性,所以现在要添加这个属性
sku_id = models.IntegerField(unique=True,null=False, verbose_name="sku_id")
python manage.py makemigrations python manage.py migrate
使用序列化器:
使用序列化器要现创建一个继承自 serializers.ModelSerializer 的类,一般在app下创建一个serializers.py。
# goods/serializers.py
from rest_framework import serializers
from apps.goods.models import Goods
from jingxi_shop_project.settings import IMAGE_URLclass GoodsSerializer(serializers.ModelSerializer):# SerializerMethodField方法允许你为序列化器定义一个名为 get_属性 的方法,这个方法返回的值将作为该字段的值在序列化时输出photo_URL = serializers.SerializerMethodField()def get_photo_URL(self, obj):return IMAGE_URL + obj.photo_URLclass Meta:model = Goods # 指定了序列化器将要序列化的模型类是Goodsfields = "__all__" # 序列化器将包含模型定义的所有字段
# goods/views.py
# http://localhost:8000/goods/sku_id
class GoodsDetailAPIView(APIView):def get(self, request, sku_id):# good_data = Goods.objects.filter(sku_id=sku_id) # 返回的是一个QuerySet查询集,并不是一个对象,哪怕符合条件的只有一个对象。good_data = Goods.objects.filter(sku_id=sku_id).first() # 获取 QuerySet 中的第一个模型实例,是一个对象# 序列化的参数是instance,反序列化的参数是dataresult = GoodsSerializer(instance=good_data)result_json = {'status': '2000', 'data': result.data}return HttpResponse(json.dumps(result_json), content_type='application/json')
此时我们就可以通过sku_id来获取JSON格式的数据了:
特殊处理的字段会在最前面。
在上面我们用first()函数拿到了QuerySet查询集中的第一个实例,实际上还有另一种写法
def get(self, request, sku_id):good_data = Goods.objects.filter(sku_id=sku_id)print(type(good_data))# 设置 many=True 表示告诉序列化器要处理多个对象也就是传入的instance是一个包含多个对象的查询集,通常用于处理查询集(QuerySet)返回的结果result = GoodsSerializer(instance=good_data, many=True)result_json = {'status': '2000', 'data': result.data}return HttpResponse(json.dumps(result_json), content_type='application/json')
直接用many=True告诉序列化器你要处理一个包含多个对象的查询集,他就会自己遍历并序列化了。
如果不特殊处理photo_URL这个字段,就会输出数据库中最原始的数据:
# goods/serializers.py
from rest_framework import serializers
from apps.goods.models import Goods
from jingxi_shop_project.settings import IMAGE_URLclass GoodsSerializer(serializers.ModelSerializer):class Meta:model = Goodsfields = "__all__"
# goods/views.py
class GoodsDetailAPIView(APIView):def get(self, request, sku_id):good_data = Goods.objects.filter(sku_id=sku_id)result = GoodsSerializer(instance=good_data)result_json = {'status': '2000', 'data': result.data}return HttpResponse(json.dumps(result_json), content_type='application/json')
若有错误与不足请指出,关注DPT一起进步吧!!!