一、普通方式实现商品列表页
先了解Django中实现Json数据传递的基本方法,可以查看中文文档https://www.cntofu.com/book/35/index.html,并结合英文文档了解其用法。
1.使用Django View实现商品列表
下面实现通过View类直接将商品信息显示到前端。
为了区别于views.py,在apps/goods下新建views_base.py如下:
import json from django.views.generic.base import View from django.http import HttpResponse from goods.models import Goods class MyEncoder(json.JSONEncoder): def default(self, obj): if isinstance(obj, bytes): return str(obj, encoding='utf-8') return json.JSONEncoder.default(self, obj) class GoodsListView(View): def get(self, request): '''通过View实现商品列表页''' json_list = [] goods = Goods.objects.all()[:10] for good in goods: json_dict = {} json_dict["name"] = good.name json_dict["category"] = good.category.name json_dict["market_price"] = good.market_price json_list.append(json_dict) return HttpResponse(json.dumps(json_list, ensure_ascii=False), content_type='application/json')
urls.py中加入路由如下:
urlpatterns = [ url(r'^xadmin/', xadmin.site.urls), url(r'^media/(?P<path>.*)$', serve, {'document_root':MEDIA_ROOT}), # 商品列表页 url(r'goods/$', GoodsListView.as_view(), name='goods-list') ]
显示:
显然,数据以json的形式返回前端。
但是从代码中可以看到:
通过在新建列表、其元素为单个商品信息组成的字典,一个一个地添加,显得很麻烦,可进行改进;
有些字段不能直接用json.dumps()
方法序列化,如datetime,会报错,如商品列表视图修改为如下时:
class GoodsListView(View): def get(self, request): '''通过View实现商品列表页''' json_list = [] goods = Goods.objects.all()[:10] for good in goods: json_dict = {} json_dict["name"] = good.name json_dict["category"] = good.category.name json_dict["market_price"] = good.market_price json_dict["add_time"] = good.add_time json_list.append(json_dict) return HttpResponse(json.dumps(json_list, ensure_ascii=False))
会报错:
raise TypeError(f'Object of type {o.__class__.__name__} ' TypeError: Object of type date is not JSON serializable
显然可以进行改进。
2.serializer序列化model
使用Django自带的model_to_dict()
方法可以实现直接将模型数据转化为字典形式,但是对于DateTimeField、ImageField等字段时还是无法序列化,因此需要使用serializer进行序列化,views_base.py如下:
import json from django.views.generic.base import View from django.http import HttpResponse, JsonResponse from django.forms.models import model_to_dict from django.core import serializers from goods.models import Goods class MyEncoder(json.JSONEncoder): def default(self, obj): if isinstance(obj, bytes): return str(obj, encoding='utf-8') return json.JSONEncoder.default(self, obj) class GoodsListView(View): def get(self, request): '''通过serializers实现商品列表页''' goods = Goods.objects.all()[:10] json_data = serializers.serialize('json', goods) json_data = json.loads(json_data) return HttpResponse(json.dumps(json_data), content_type='application/json')
显示:
显然,此时所有字段都可以显示到前端,还可以简化如下:
class GoodsListView(View): def get(self, request): '''通过serializers实现商品列表页''' goods = Goods.objects.all()[:10] json_data = serializers.serialize('json', goods) return HttpResponse(json_data, content_type='application/json')
还可以直接使用JsonResponse对象,如下:
class GoodsListView(View): def get(self, request): '''通过serializers实现商品列表页''' goods = Goods.objects.all()[:10] json_data = serializers.serialize('json', goods) return JsonResponse(json.loads(json_data), safe=False)
效果与之前一样。
虽然Django已经可以实现Json数据传递,但是我们还是采用Restful framework,因为其对Django自带功能实现了进一步优化,更方便使用。
二、DRF实现商品列表页
Django Restful framework简称DRF,可以查看官方文档https://www.django-rest-framework.org/,从官方文档可以看到,Django REST框架是用于构建Web API的功能强大且灵活的工具包。
使用REST框架的一些原因:
该网站可浏览API是你的开发人员一个巨大的可用性胜利;
身份验证策略,包括OAuth1a和OAuth2的软件包;
支持ORM和非ORM数据源的序列化;
完全可自定义;
广泛的文档资料以及强大的社区支持。
要使用DRF,还需要DRF所依赖的第三方库django-guardian、coreapi,直接通过命令添加即可,还需要在settings.py中进行配置:
INSTALLED_APPS = [ 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'apps.users.apps.UsersConfig', 'goods.apps.GoodsConfig', 'trade.apps.TradeConfig', 'user_operation.apps.UserOperationConfig', 'DjangoUeditor', 'xadmin', 'crispy_forms', 'django.contrib.admin', 'rest_framework', ]
1.使用serializer实现基本序列化
通过DRF实现商品列表页的原理是:
通过DRF返回数据,基于CBV(Class-based Views, 即基于类的视图)方式编码。
urls.py中配置路径:
from django.conf.urls import url, include from django.views.static import serve from rest_framework.documentation import include_docs_urls import xadmin from .settings import MEDIA_ROOT from goods.views_base import GoodsListView urlpatterns = [ url(r'^xadmin/', xadmin.site.urls), url(r'^media/(?P<path>.*)$', serve, {'document_root':MEDIA_ROOT}), url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')), # 商品列表页 url(r'goods/$', GoodsListView.as_view(), name='goods-list'), # 文档路由 url(r'docs/', include_docs_urls(title='生鲜电商')) ]
apps/goods下新建serializers.py如下:
from rest_framework import serializers class GoodsSerializer(serializers.Serializer): name = serializers.CharField(required=True, max_length=300) click_num = serializers.IntegerField(default=0)
现在建立基于类的视图CBV,apps/goods/views.py如下:
from rest_framework.views import APIView from rest_framework.response import Response from .models import Goods from .serializers import GoodsSerializer # Create your views here. class GoodsListView(APIView): '''商品序列化''' def get(self, request, format=None): goods = Goods.objects.all()[:10] goods_serializer = GoodsSerializer(goods, many=True) return Response(goods_serializer.data)
urls.py修改如下:
from django.conf.urls import url, include from django.views.static import serve from rest_framework.documentation import include_docs_urls import xadmin from .settings import MEDIA_ROOT from goods.views import GoodsListView urlpatterns = [ url(r'^xadmin/', xadmin.site.urls), url(r'^media/(?P<path>.*)$', serve, {'document_root':MEDIA_ROOT}), url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')), # 商品列表页 url(r'goods/$', GoodsListView.as_view(), name='goods-list'), # 文档路由 url(r'docs/', include_docs_urls(title='生鲜电商')) ]
此时再访问http://127.0.0.1:8000/goods/,显示:
显然,此时还是显示出了数据,并且经过restful_framework优化,不是单纯地显示json数据,而且可以通过json和API两种方式查看,还能查看OPTIONS数据。
如果报错__str__ returned non-string (type NoneType),可以通过退出登录后台管理或者修改自定义的用户模型的__str__()方法解决,具体可参考https://blog.csdn.net/CUFEECR/article/details/107469168。