Vue+Django REST framework打造生鲜电商项目

来源:互联网 发布:淘宝运费险赔付多少钱 编辑:程序博客网 时间:2024/06/11 01:02

掌握的技术

1.Vue+Django REST Framework前后端分离技术

2.彻底玩转restful api开发流程

3.Django REST Framework的功能实现和核心源码分析

4.Sentry完成线上系统的错误日志的监控和告警

5.第三方登录和支付宝支付的集成

6.本地调试远程服务器代码技巧

课程系统构成

1.vue前端项目

2.django rest framework系统实现前台功能

3.xadmin后台管理系统

Django REST Framework技能

通用view实现rest api接口

1.ApiView方式实现api

2.GenericView方式实现api接口

3.Viewset和router方式实现api接口和url配置

4.django_filter,SearchFilter,OrderFilter,分页

5.通用mixins

权限和认证

1.Authentication用户认证设置

2.动态设置permission,Authentication

3.Validators实现字段验证

序列化和表单验证

1.Serializer

2.ModelSerializer

3.动态设置serializer

支付,登录和注册

1.json web token实现登录

2.手机注册

3.支付宝支付

4.第三方登录

进阶开发

1.django rest framework部分核心源码解读

2.文档自动化管理

3,django rest framework的缓存

4,Throttling对用户和ip进行限速

开发中常见的问题

1.本地系统不能重现的bug

2.api接口出错不能及时的发现或难找到错误栈

3.api文档管理问题

4.大量的url配置造成url配置越来越多难以维护

5.接口不及时去更新文档对方不知道如何去测试接口,但写文档会花费大量的时间去维护

6.为了防止爬虫,我们需要对api的访问频率进行限制,比如一分钟,一小时或者一天用户的访问频率限制问题

7.某些页面将数据放入缓存,加速某些api的访问速度

开发中常见的问题解决方案

1.通过介绍Pycharm的远程服务器代码调试技巧让大家不仅可以调试支付,第三方登录还可以调试远程服务器的代码来重现服务器上的bug

2.通过docker搭建sentry来体验错误日志监控系统,让我们不仅可以得到线上的错误还能及时在发生系统错误时收到邮件通知

3.django rest framework的文档自动化管理以及url的注册管理功能会让我们省去写文档的时间

4.django rest framework的文档管理功能不仅可以让我们省去写文档的时间还能直接在文档里面测试接口,自动生成的js接口代码,shell测试代码和python测试代码

5.django rest framework提供的throttle来对api进行访问频率限制

6.引入第三方框架来设置某些api的缓存

Django进阶知识点

1.Django mirgrations原理

2.Django信号量

3.Django从请求到响应的完整过程

4.独立使用django的Model

Vue知识点

1.Vue技术选型分析

2.API后端接口数据填充到Vue组件模板

3.Vue代码结构分析

搭建开发环境

1.pycharm

2.mysql,navicat

3.virtualenv和virtualenvwrapper

4.vue项目环境搭建

项目初始化

创建虚拟环境

mkvirtualenv -p /usr/bin/python3 VueShop

http://www.django-rest-framework.org/ 【django rest framework官网】

安装django

pip install -i https://pypi.douban.com/simple django

安装django rest framework等

pip install djangorestframework

pip install markdown

pip install django-filter

运行:

配置数据库

DATABASES = {    'default': {        'ENGINE': 'django.db.backends.mysql',        'NAME': "mxshop",        'USER': 'root',        'PASSWORD': "123456",        'HOST': "127.0.0.1",        'OPTIONS': { 'init_command': 'SET storage_engine=INNODB;' }    }}
创建数据库:

create database mxshop default character set utf8 collate utf8_general_ci;安装依赖包
apt-get install python3-dev
pip install -i https://pypi.douban.com/simple mysqlclientpip install -i https://pypi.douban.com/simple pillow
python中安装时的第三方包

https://www.lfd.uci.edu/~gohlke/pythonlibs/
新建python package apps放置所有的app

新建包extra_apps放置第三方包

新建media,db_tools

鼠标右击(apps,extra_apps)-->Mark Directory as-->Sources Root


django-admin startapp trade,goods,user_operation

分别建立各个app

user models设计

# _*_coding:utf-8_*_from datetime import datetimefrom django.db import modelsfrom django.contrib.auth.models import AbstractUserclass UserProfile(AbstractUser):    """    用户    """    name = models.CharField(max_length=30, null=True, blank=True, verbose_name="姓名")    birthday = models.DateField(null=True, blank=True, verbose_name="出生年月")    gender = models.CharField(max_length=6, choices=(("male", u"男"), ("female", "女")), default="female",                              verbose_name="性别")    mobile = models.CharField(null=True, blank=True, max_length=11, verbose_name="电话")    email = models.EmailField(max_length=100, null=True, blank=True, verbose_name="邮箱")    class Meta:        verbose_name = "用户"        verbose_name_plural = "用户"    def __str__(self):        return self.nameclass VerifyCode(models.Model):    """    短信验证码    """    code = models.CharField(max_length=10, verbose_name="验证码")    mobile = models.CharField(max_length=11, verbose_name="电话")    add_time = models.DateTimeField(default=datetime.now, verbose_name="添加时间")    class Meta:        verbose_name = "短信验证码"        verbose_name_plural = verbose_name    def __str__(self):        return self.code
让UserProfile替换系统用户,修改settings.py:

DEBUG = TrueALLOWED_HOSTS = []AUTH_USER_MODEL='users.UserProfile'

goods model设计

引入第三方包DjangoUeditor

# _*_coding:utf-8_*_from DjangoUeditor.models import UEditorFieldfrom datetime import datetimefrom django.db import modelsclass GoodsCategory(models.Model):    """    商品类别    """    CATEGORY_TYPE = (        (1, "一级类目"),        (2, "二级类目"),        (3, "三级类目"),    )    name = models.CharField(default="", max_length=30, verbose_name="类别名", help_text="类别名")    code = models.CharField(default="", max_length=30, verbose_name="类别code", help_text="类别code")    desc = models.TextField(default="", verbose_name="类别描述", help_text="类别描述")    category_type = models.IntegerField(choices=CATEGORY_TYPE, verbose_name="类别级目", help_text="类别级目")    parent_category = models.ForeignKey("self", null=True, blank=True, verbose_name="父类目级别", help_text="父目录",                                        related_name="sub_cat")    is_tab = models.BooleanField(default=False, verbose_name="是否导航", help_text="是否导航")    add_time = models.DateTimeField(default=datetime.now, verbose_name="添加时间")    class Meta:        verbose_name = "商品类别"        verbose_name_plural = verbose_name    def __str__(self):        return self.nameclass GoodsCategoryBrand(models.Model):    """    品牌名    """    category = models.ForeignKey(GoodsCategory, related_name='brands', null=True, blank=True, verbose_name="商品类目")    name = models.CharField(default="", max_length=30, verbose_name="品牌名", help_text="品牌名")    desc = models.TextField(default="", max_length=200, verbose_name="品牌描述", help_text="品牌描述")    image = models.ImageField(max_length=200, upload_to="brands/")    add_time = models.DateTimeField(default=datetime.now, verbose_name="添加时间")    class Meta:        verbose_name = "品牌"        verbose_name_plural = verbose_name        db_table = "goods_goodsbrand"    def __str__(self):        return self.nameclass Goods(models.Model):    """    商品    """    category = models.ForeignKey(GoodsCategory, verbose_name="商品类目")    goods_sn = models.CharField(max_length=50, default="", verbose_name="商品唯一货号")    name = models.CharField(max_length=100, verbose_name="商品名")    click_num = models.IntegerField(default=0, verbose_name="点击数")    sold_num = models.IntegerField(default=0, verbose_name="商品销售量")    fav_num = models.IntegerField(default=0, verbose_name="收藏数")    goods_num = models.IntegerField(default=0, verbose_name="库存数")    market_price = models.FloatField(default=0, verbose_name="市场价格")    shop_price = models.FloatField(default=0, verbose_name="本店价格")    goods_brief = models.TextField(max_length=500, verbose_name="商品简短描述")    goods_desc = UEditorField(verbose_name=u"内容", imagePath="goods/images/", width=1000, height=300,                              filePath="goods/files/", default='')    ship_free = models.BooleanField(default=True, verbose_name="是否承担运费")    goods_front_image = models.ImageField(upload_to="goods/images/", null=True, blank=True, verbose_name="封面图")    is_new = models.BooleanField(default=False, verbose_name="是否新品")    is_hot = models.BooleanField(default=False, verbose_name="是否热销")    add_time = models.DateTimeField(default=datetime.now, verbose_name="添加时间")    class Meta:        verbose_name = '商品'        verbose_name_plural = verbose_name    def __str__(self):        return self.nameclass IndexAd(models.Model):    category = models.ForeignKey(GoodsCategory, related_name='category', verbose_name="商品类目")    goods = models.ForeignKey(Goods, related_name='goods')    class Meta:        verbose_name = '首页商品类别广告'        verbose_name_plural = verbose_name    def __str__(self):        return self.goods.nameclass GoodsImage(models.Model):    """    商品轮播图    """    goods = models.ForeignKey(Goods, verbose_name="商品", related_name="images")    image = models.ImageField(upload_to="", verbose_name="图片", null=True, blank=True)    add_time = models.DateTimeField(default=datetime.now, verbose_name="添加时间")    class Meta:        verbose_name = '商品图片'        verbose_name_plural = verbose_name    def __str__(self):        return self.goods.nameclass Banner(models.Model):    """    轮播的商品    """    goods = models.ForeignKey(Goods, verbose_name="商品")    image = models.ImageField(upload_to='banner', verbose_name="轮播图片")    index = models.IntegerField(default=0, verbose_name="轮播顺序")    add_time = models.DateTimeField(default=datetime.now, verbose_name="添加时间")    class Meta:        verbose_name = '轮播商品'        verbose_name_plural = verbose_name    def __str__(self):        return self.goods.nameclass HotSearchWords(models.Model):    """    热搜词    """    keywords = models.CharField(default="", max_length=20, verbose_name="热搜词")    index = models.IntegerField(default=0, verbose_name="排序")    add_time = models.DateTimeField(default=datetime.now, verbose_name="添加时间")    class Meta:        verbose_name = '热搜词'        verbose_name_plural = verbose_name    def __str__(self):        return self.keywords

trade models设计

from datetime import datetimefrom django.db import modelsfrom django.contrib.auth import get_user_modelfrom goods.models import GoodsUser = get_user_model()# Create your models here.class ShoppingCart(models.Model):    """    购物车    """    user = models.ForeignKey(User, verbose_name=u"用户")    goods = models.ForeignKey(Goods, verbose_name=u"商品")    nums = models.IntegerField(default=0, verbose_name="购买数量")    add_time = models.DateTimeField(default=datetime.now, verbose_name=u"添加时间")    class Meta:        verbose_name = '购物车'        verbose_name_plural = verbose_name        unique_together = ("user", "goods")    def __str__(self):        return "%s(%d)".format(self.goods.name, self.nums)class OrderInfo(models.Model):    """    订单    """    ORDER_STATUS = (        ("TRADE_SUCCESS", "成功"),        ("TRADE_CLOSED", "超时关闭"),        ("WAIT_BUYER_PAY", "交易创建"),        ("TRADE_FINISHED", "交易结束"),        ("paying", "待支付"),    )    user = models.ForeignKey(User, verbose_name="用户")    order_sn = models.CharField(max_length=30, null=True, blank=True, unique=True, verbose_name="订单号")    trade_no = models.CharField(max_length=100, unique=True, null=True, blank=True, verbose_name=u"交易号")    pay_status = models.CharField(choices=ORDER_STATUS, default="paying", max_length=30, verbose_name="订单状态")    post_script = models.CharField(max_length=200, verbose_name="订单留言")    order_mount = models.FloatField(default=0.0, verbose_name="订单金额")    pay_time = models.DateTimeField(null=True, blank=True, verbose_name="支付时间")    # 用户信息    address = models.CharField(max_length=100, default="", verbose_name="收货地址")    signer_name = models.CharField(max_length=20, default="", verbose_name="签收人")    singer_mobile = models.CharField(max_length=11, verbose_name="联系电话")    add_time = models.DateTimeField(default=datetime.now, verbose_name="添加时间")    class Meta:        verbose_name = u"订单"        verbose_name_plural = verbose_name    def __str__(self):        return str(self.order_sn)class OrderGoods(models.Model):    """    订单的商品详情    """    order = models.ForeignKey(OrderInfo, verbose_name="订单信息", related_name="goods")    goods = models.ForeignKey(Goods, verbose_name="商品")    goods_num = models.IntegerField(default=0, verbose_name="商品数量")    add_time = models.DateTimeField(default=datetime.now, verbose_name="添加时间")    class Meta:        verbose_name = "订单商品"        verbose_name_plural = verbose_name    def __str__(self):        return str(self.order.order_sn)

user_operation models设计

from datetime import datetimefrom django.db import modelsfrom django.contrib.auth import get_user_modelfrom goods.models import Goods# Create your models here.User = get_user_model()class UserFav(models.Model):    """    用户收藏    """    user = models.ForeignKey(User, verbose_name="用户")    goods = models.ForeignKey(Goods, verbose_name="商品", help_text="商品id")    add_time = models.DateTimeField(default=datetime.now, verbose_name=u"添加时间")    class Meta:        verbose_name = '用户收藏'        verbose_name_plural = verbose_name        unique_together = ("user", "goods")    def __str__(self):        return self.user.usernameclass UserLeavingMessage(models.Model):    """    用户留言    """    MESSAGE_CHOICES = (        (1, "留言"),        (2, "投诉"),        (3, "询问"),        (4, "售后"),        (5, "求购")    )    user = models.ForeignKey(User, verbose_name="用户")    message_type = models.IntegerField(default=1, choices=MESSAGE_CHOICES, verbose_name="留言类型",                                       help_text=u"留言类型: 1(留言),2(投诉),3(询问),4(售后),5(求购)")    subject = models.CharField(max_length=100, default="", verbose_name="主题")    message = models.TextField(default="", verbose_name="留言内容", help_text="留言内容")    file = models.FileField(upload_to="message/images/", verbose_name="上传的文件", help_text="上传的文件")    add_time = models.DateTimeField(default=datetime.now, verbose_name="添加时间")    class Meta:        verbose_name = "用户留言"        verbose_name_plural = verbose_name    def __str__(self):        return self.subjectclass UserAddress(models.Model):    """    用户收货地址    """    user = models.ForeignKey(User, verbose_name="用户")    province = models.CharField(max_length=100, default="", verbose_name="省份")    city = models.CharField(max_length=100, default="", verbose_name="城市")    district = models.CharField(max_length=100, default="", verbose_name="区域")    address = models.CharField(max_length=100, default="", verbose_name="详细地址")    signer_name = models.CharField(max_length=100, default="", verbose_name="签收人")    signer_mobile = models.CharField(max_length=11, default="", verbose_name="电话")    add_time = models.DateTimeField(default=datetime.now, verbose_name="添加时间")    class Meta:        verbose_name = "收货地址"        verbose_name_plural = verbose_name    def __str__(self):        return self.address
setting配置:

INSTALLED_APPS = [    'django.contrib.auth',    'django.contrib.contenttypes',    'django.contrib.sessions',    'django.contrib.messages',    'django.contrib.staticfiles',    'users.apps.UsersConfig',    'DjangoUeditor',    'goods.apps.GoodsConfig',    'trade.apps.TradeConfig',    'user_operation.apps.UserOperationConfig',]

python3 manage.py makemigrations生成表

xadmin后台管理系统的配置

拷贝xadmin源码到extra_apps下,xadmin可到GitHub上找到,在各个app下建立adminx.py文件

users adminx.py:

#!/usr/bin/env python# encoding: utf-8import xadminfrom xadmin import viewsfrom .models import VerifyCodeclass BaseSetting(object):    enable_themes = True    use_bootswatch = Trueclass GlobalSettings(object):    site_title = "慕学生鲜后台"    site_footer = "mxshop"    # menu_style = "accordion"class VerifyCodeAdmin(object):    list_display = ['code', 'mobile', "add_time"]xadmin.site.register(VerifyCode, VerifyCodeAdmin)xadmin.site.register(views.BaseAdminView, BaseSetting)xadmin.site.register(views.CommAdminView, GlobalSettings)
goods adminx.py:

#!/usr/bin/env python# encoding: utf-8import xadminfrom .models import Goods, GoodsCategory, GoodsImage, GoodsCategoryBrand, Banner, HotSearchWordsfrom .models import IndexAdclass GoodsAdmin(object):    list_display = ["name", "click_num", "sold_num", "fav_num", "goods_num", "market_price",                    "shop_price", "goods_brief", "goods_desc", "is_new", "is_hot", "add_time"]    search_fields = ['name', ]    list_editable = ["is_hot", ]    list_filter = ["name", "click_num", "sold_num", "fav_num", "goods_num", "market_price",                   "shop_price", "is_new", "is_hot", "add_time", "category__name"]    style_fields = {"goods_desc": "ueditor"}    class GoodsImagesInline(object):        model = GoodsImage        exclude = ["add_time"]        extra = 1        style = 'tab'    inlines = [GoodsImagesInline]class GoodsCategoryAdmin(object):    list_display = ["name", "category_type", "parent_category", "add_time"]    list_filter = ["category_type", "parent_category", "name"]    search_fields = ['name', ]class GoodsBrandAdmin(object):    list_display = ["category", "image", "name", "desc"]    def get_context(self):        context = super(GoodsBrandAdmin, self).get_context()        if 'form' in context:            context['form'].fields['category'].queryset = GoodsCategory.objects.filter(category_type=1)        return contextclass BannerGoodsAdmin(object):    list_display = ["goods", "image", "index"]class HotSearchAdmin(object):    list_display = ["keywords", "index", "add_time"]class IndexAdAdmin(object):    list_display = ["category", "goods"]xadmin.site.register(Goods, GoodsAdmin)xadmin.site.register(GoodsCategory, GoodsCategoryAdmin)xadmin.site.register(Banner, BannerGoodsAdmin)xadmin.site.register(GoodsCategoryBrand, GoodsBrandAdmin)xadmin.site.register(HotSearchWords, HotSearchAdmin)xadmin.site.register(IndexAd, IndexAdAdmin)
trade adminx.py:

# -*- coding: utf-8 -*-import xadminfrom .models import ShoppingCart, OrderInfo, OrderGoodsclass ShoppingCartAdmin(object):    list_display = ["user", "goods", "nums", ]class OrderInfoAdmin(object):    list_display = ["user", "order_sn",  "trade_no", "pay_status", "post_script", "order_mount",                    "order_mount", "pay_time", "add_time"]    class OrderGoodsInline(object):        model = OrderGoods        exclude = ['add_time', ]        extra = 1        style = 'tab'    inlines = [OrderGoodsInline, ]xadmin.site.register(ShoppingCart, ShoppingCartAdmin)xadmin.site.register(OrderInfo, OrderInfoAdmin)
user_operation adminx.py:

#!/usr/bin/env python# encoding: utf-8import xadminfrom .models import UserFav, UserLeavingMessage, UserAddressclass UserFavAdmin(object):    list_display = ['user', 'goods', "add_time"]class UserLeavingMessageAdmin(object):    list_display = ['user', 'message_type', "message", "add_time"]class UserAddressAdmin(object):    list_display = ["signer_name", "signer_mobile", "district", "address"]xadmin.site.register(UserFav, UserFavAdmin)xadmin.site.register(UserAddress, UserAddressAdmin)xadmin.site.register(UserLeavingMessage, UserLeavingMessageAdmin)
安装xadmin依赖包,可参照:https://github.com/sshwsfc/xadmin/blob/master/requirements.txt
INSTALLED_APPS = [    'django.contrib.auth',    'django.contrib.contenttypes',    'django.contrib.sessions',    'django.contrib.messages',    'django.contrib.staticfiles',    'users.apps.UsersConfig',    'DjangoUeditor',    'goods.apps.GoodsConfig',    'trade.apps.TradeConfig',    'user_operation.apps.UserOperationConfig',    'crispy_forms',    'xadmin',]
pip install django-crispy-forms django-reversion django-formtools future httplib2 sixexcel表格:pip install xlwt xlsxwriter
python3 manage.py migrate

创建超级管理员:

python3 manage.py runserver

浏览器访问:127.0.0.1:8000/xadmin

setting.py中修改时区,中文:

#设置时区LANGUAGE_CODE = 'zh-hans'  #中文支持,django1.8以后支持;1.8以前是zh-cnTIME_ZONE = 'Asia/Shanghai'USE_I18N = TrueUSE_L10N = TrueUSE_TZ = False   #默认是Ture,时间是utc时间,由于我们要用本地时间,所用手动修改为false!!!!
修改goods为中文名,其他app分别做对应修改:

from django.apps import AppConfigclass GoodsConfig(AppConfig):    name = 'goods'    verbose_name="商品"

在db_tools和media引入相关数据文件和静态文件:


import_category_data.py

# -*- coding: utf-8 -*-__author__ = 'bobby'#独立使用django的modelimport sysimport ospwd = os.path.dirname(os.path.realpath(__file__))sys.path.append(pwd+"../")os.environ.setdefault("DJANGO_SETTINGS_MODULE", "MxShop.settings")import djangodjango.setup()from goods.models import GoodsCategoryfrom db_tools.data.category_data import row_datafor lev1_cat in row_data:    lev1_intance = GoodsCategory()    lev1_intance.code = lev1_cat["code"]    lev1_intance.name = lev1_cat["name"]    lev1_intance.category_type = 1    lev1_intance.save()    for lev2_cat in lev1_cat["sub_categorys"]:        lev2_intance = GoodsCategory()        lev2_intance.code = lev2_cat["code"]        lev2_intance.name = lev2_cat["name"]        lev2_intance.category_type = 2        lev2_intance.parent_category = lev1_intance        lev2_intance.save()        for lev3_cat in lev2_cat["sub_categorys"]:            lev3_intance = GoodsCategory()            lev3_intance.code = lev3_cat["code"]            lev3_intance.name = lev3_cat["name"]            lev3_intance.category_type = 3            lev3_intance.parent_category = lev2_intance            lev3_intance.save()
import_goods_data.py:

# -*- coding: utf-8 -*-__author__ = 'bobby'import sysimport ospwd = os.path.dirname(os.path.realpath(__file__))sys.path.append(pwd+"../")os.environ.setdefault("DJANGO_SETTINGS_MODULE", "MxShop.settings")import djangodjango.setup()from goods.models import Goods, GoodsCategory, GoodsImagefrom db_tools.data.product_data import row_datafor goods_detail in row_data:    goods = Goods()    goods.name = goods_detail["name"]    goods.market_price = float(int(goods_detail["market_price"].replace("¥", "").replace("元", "")))    goods.shop_price = float(int(goods_detail["sale_price"].replace("¥", "").replace("元", "")))    goods.goods_brief = goods_detail["desc"] if goods_detail["desc"] is not None else ""    goods.goods_desc = goods_detail["goods_desc"] if goods_detail["goods_desc"] is not None else ""    goods.goods_front_image = goods_detail["images"][0] if goods_detail["images"] else ""    category_name = goods_detail["categorys"][-1]    category = GoodsCategory.objects.filter(name=category_name)    if category:        goods.category = category[0]    goods.save()    for goods_image in goods_detail["images"]:        goods_image_instance = GoodsImage()        goods_image_instance.image = goods_image        goods_image_instance.goods = goods        goods_image_instance.save()

settings.py中配置静态资源路径:

STATIC_URL = '/static/'MEDIA_URL = "/media/"STATICFILES_DIRS = (    os.path.join(BASE_DIR, "static"),)MEDIA_ROOT = os.path.join(BASE_DIR, "media")
urls.py中配置:

from django.conf.urls import url# from django.contrib import adminimport xadminfrom MxShop.settings import MEDIA_ROOTfrom django.views.static import serveurlpatterns = [    # url(r'^admin/', admin.site.urls),    url(r'^xadmin/',xadmin.site.urls),    url(r'^media/(?P<path>.*)$', serve, {"document_root": MEDIA_ROOT}),]
运行import_goods_data.py,import_catetory_data.py生成数据

运行项目:


前后端分离优缺点

为什么要前后端分离

1.pc,app,pad多端适应

2.SPA开发模式开始流行

3.前后端开发职责不清

4.开发效率问题,前后端互相等待

5.前端一直配合着后端,能力受限

6.后台开发语言和模板高度耦合,导致开发语言依赖严重

前后端分离缺点

1.前后端学习门槛增加

2.数据依赖 导致文档重要性增加

3.前端工作量加大

4.SEO的难度增加

5.后端开发模式迁移增加成本

restful api

restful api目前是前后端分离最佳实践

1.轻量,直接通过http,不需要额外的协议,post/get/put/delete操作

2.面向资源,一目了然,具有自解释性

3.数据描述简单,一般通过json或者xml做数据通信

restful API重要概念

理解RESTful架构

RESTful API设计指南

几个概念

1.前端工程化

2.数据双向绑定

3.组件化开发

vue开发的几个概念

1.webpack

2.vue,vuex,vue-router,axios

3.ES6,babel

django的view实现商品列表页

urls.py

from django.conf.urls import url# from django.contrib import adminimport xadminfrom MxShop.settings import MEDIA_ROOTfrom django.views.static import servefrom goods.views_base import GoodsListViewurlpatterns = [    # url(r'^admin/', admin.site.urls),    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")]
goods views_base.py

# -*-coding:utf-8 -*-from django.views.generic.base import Viewfrom django.http import HttpResponseimport jsonfrom goods.models import Goodsfrom django.views.generic import ListViewclass GoodsListView(View):    def get(self, request):        """            通过django的view实现商品列表页            :param request:            :return:            """        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), content_type="application/json")

django的serializer序列化model

views_base.py

# -*-coding:utf-8 -*-from django.views.generic.base import Viewfrom django.http import HttpResponse, JsonResponseimport jsonfrom goods.models import Goodsfrom django.views.generic import ListViewclass GoodsListView(View):    def get(self, request):        """            通过django的view实现商品列表页            :param request:            :return:            """        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)'''        '''不能序列化日期图片类型        from django.forms.models import model_to_dict        for good in goods:            json_dict=model_to_dict(good)            json_list.append(json_dict)        '''        from django.core import serializers        json_data = serializers.serialize('json', goods)        json_data = json.loads(json_data)        # return HttpResponse(json.dumps(json_data), content_type="application/json")        # return HttpResponse(json_data, content_type="application/json")        return JsonResponse(json_data, safe=False)

apiview方式实现商品列表页

django中文文档1.8.2

django rest framewrok官网

pip install coreapipip install django-guardian
urls.py:

from django.conf.urls import url,include# from django.contrib import adminimport xadminfrom MxShop.settings import MEDIA_ROOTfrom django.views.static import servefrom rest_framework.documentation import include_docs_urlsfrom goods.views_base import GoodsListViewurlpatterns = [    # url(r'^admin/', admin.site.urls),    url(r'^xadmin/',xadmin.site.urls),    url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),    url(r'^media/(?P<path>.*)$', serve, {"document_root": MEDIA_ROOT}),    #商品列表页    url(r'goods/$',GoodsListView.as_view(),name="goods-list"),    url(r'docs/',include_docs_urls(title="慕学生鲜"))]

INSTALLED_APPS中添加:
rest_framework

INSTALLED_APPS = [    'django.contrib.auth',    'django.contrib.contenttypes',    'django.contrib.sessions',    'django.contrib.messages',    'django.contrib.staticfiles',    'users.apps.UsersConfig',    'DjangoUeditor',    'goods.apps.GoodsConfig',    'trade.apps.TradeConfig',    'user_operation.apps.UserOperationConfig',    'crispy_forms',    'xadmin',    'rest_framework',]
goods views.py:

from .serializers import GoodsSerializerfrom rest_framework.views import APIViewfrom rest_framework.response import Responsefrom .models import Goodsclass GoodsListView(APIView):    """    List all snippets, or create a new snippet.    """    def get(self, request, format=None):        goods = Goods.objects.all()[:10]        goods_serializer = GoodsSerializer(goods, many=True)        return Response(goods_serializer.data)
goods下新建serializers.py

# -*-coding:utf-8-*-from rest_framework import serializersclass GoodsSerializer(serializers.Serializer):    name=serializers.CharField(required=True,max_length=100)    click_num=serializers.IntegerField(default=0)
urls.py:

from django.conf.urls import url,include# from django.contrib import adminimport xadminfrom MxShop.settings import MEDIA_ROOTfrom django.views.static import servefrom rest_framework.documentation import include_docs_urls#from goods.views_base import GoodsListViewfrom goods.views import GoodsListViewurlpatterns = [    # url(r'^admin/', admin.site.urls),    url(r'^xadmin/',xadmin.site.urls),    url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),    url(r'^media/(?P<path>.*)$', serve, {"document_root": MEDIA_ROOT}),    #商品列表页    url(r'goods/$',GoodsListView.as_view(),name="goods-list"),    url(r'docs/',include_docs_urls(title="慕学生鲜"))]

如果出现__str__ returned non-string (type NoneType)错误,将users model中self.name改为self.username

drf的modelserializer实现商品列表页功能

继续添加:

serializer.py:

# -*-coding:utf-8-*-from rest_framework import serializersfrom goods.models import Goodsclass GoodsSerializer(serializers.Serializer):    name = serializers.CharField(required=True, max_length=100)    click_num = serializers.IntegerField(default=0)    goods_front_image = serializers.ImageField()        def create(self, validated_data):        return Goods.objects.create(**validated_data)
views.py:

from .serializers import GoodsSerializerfrom rest_framework.views import APIViewfrom rest_framework.response import Responsefrom rest_framework import statusfrom .models import Goodsclass GoodsListView(APIView):    """    List all snippets, or create a new snippet.    """    def get(self, request, format=None):        goods = Goods.objects.all()[:10]        goods_serializer = GoodsSerializer(goods, many=True)        return Response(goods_serializer.data)    def post(self, request, format=None):        serializer = GoodsSerializer(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)
使用ModelSerializer:

serializer.py:

# -*-coding:utf-8-*-from rest_framework import serializersfrom goods.models import Goodsclass GoodsSerializer(serializers.ModelSerializer):    class Meta:        model = Goods        fields = ('name', 'click_num', 'market_price', 'add_time')
views.py:

from .serializers import GoodsSerializerfrom rest_framework.views import APIViewfrom rest_framework.response import Responsefrom rest_framework import statusfrom .models import Goodsclass GoodsListView(APIView):    """    List all snippets, or create a new snippet.    """    def get(self, request, format=None):        goods = Goods.objects.all()[:10]        goods_serializer = GoodsSerializer(goods, many=True)        return Response(goods_serializer.data)

fields="__all__",可以返回全部
修改一下serializer.py:

# -*-coding:utf-8-*-from rest_framework import serializersfrom goods.models import Goods, GoodsCategoryclass CategorySerializer(serializers.ModelSerializer):    class Meta:        model = GoodsCategory        fields = "__all__"class GoodsSerializer(serializers.ModelSerializer):    category = CategorySerializer()    class Meta:        model = Goods        # fields = ('name', 'click_num', 'market_price', 'add_time')        fields = "__all__"

GenericView方式实现商品列表页和分页功能详解

goods views.py:

from .serializers import GoodsSerializerfrom rest_framework.views import APIViewfrom rest_framework.response import Responsefrom rest_framework import mixinsfrom rest_framework import genericsfrom rest_framework import statusfrom .models import Goodsclass GoodsListView(mixins.ListModelMixin,generics.GenericAPIView):    """商品列表页"""    queryset=Goods.objects.all()[:10]    serializer_class=GoodsSerializer    def get(self,request,*args,**kwargs):        return self.list(request,*args,**kwargs)


也可以继承ListAPIView实现同样功能:

from .serializers import GoodsSerializerfrom rest_framework.views import APIViewfrom rest_framework.response import Responsefrom rest_framework import mixinsfrom rest_framework import genericsfrom rest_framework import statusfrom .models import Goodsclass GoodsListView(generics.ListAPIView):    """商品列表页"""    queryset=Goods.objects.all()[:10]    serializer_class=GoodsSerializer
在setting中配置实现分页:

MEDIA_ROOT = os.path.join(BASE_DIR, "media")REST_FRAMEWORK = {    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',    'PAGE_SIZE': 10,}

返回数据:

HTTP 200 OKAllow: GET, HEAD, OPTIONSContent-Type: application/jsonVary: Accept{    "count": 52,    "next": "http://127.0.0.1:8000/goods/?page=2",    "previous": null,    "results": [        {            "id": 1,            "category": {                "id": 20,                "name": "根茎类",                "code": "gjl",                "desc": "",                "category_type": 2,                "is_tab": false,                "add_time": "2017-12-02T11:48:50",                "parent_category": 1            },            "goods_sn": "",            "name": "新鲜水果甜蜜香脆单果约800克",            "click_num": 0,            "sold_num": 0,            "fav_num": 0,            "goods_num": 0,            "market_price": 232.0,            "shop_price": 156.0,            "goods_brief": "食用百香果可以增加胃部饱腹感,减少余热量的摄入,还可以吸附胆固醇和胆汁之类有机分子,抑制人体对脂肪的吸收。因此,长期食用有利于改善人体营养吸收结构,降低体内脂肪,塑造健康优美体态。",            "goods_desc": "<p><img src=\"/media/goods/images/2_20170719161405_249.jpg\" title=\"\" alt=\"2.jpg\"/></p><p><img src=\"/media/goods/images/2_20170719161414_628.jpg\" title=\"\" alt=\"2.jpg\"/></p><p><img src=\"/media/goods/images/2_20170719161435_381.jpg\" title=\"\" alt=\"2.jpg\"/></p>",            "ship_free": true,            "goods_front_image": "http://127.0.0.1:8000/media/goods/images/1_P_1449024889889.jpg",            "is_new": false,            "is_hot": false,            "add_time": "2017-12-02T12:34:30"        },
另一种方式分页,注释之前的REST_FRAMEWORK配置,在view中写入

from .serializers import GoodsSerializerfrom rest_framework.views import APIViewfrom rest_framework.response import Responsefrom rest_framework import mixinsfrom rest_framework import genericsfrom rest_framework.pagination import PageNumberPaginationfrom rest_framework import statusfrom .models import Goodsclass GoodsPagination(PageNumberPagination):    page_size = 10    page_size_query_param = 'page_size'    page_query_param = "p"    max_page_size = 100class GoodsListView(generics.ListAPIView):    """商品列表页"""    queryset = Goods.objects.all()    serializer_class = GoodsSerializer    pagination_class = GoodsPagination
返回:

{    "count": 52,    "next": "http://127.0.0.1:8000/goods/?p=2",    "previous": null,    "results": [
动态分页:在浏览器输入:http://127.0.0.1:8000/goods/?p=2&page_size=20

返回:

"count": 52,    "next": "http://127.0.0.1:8000/goods/?p=3&page_size=20",    "previous": "http://127.0.0.1:8000/goods/?page_size=20",    "results": [

viewsets和router完成商品列表页

goods views.py:

from .serializers import GoodsSerializerfrom rest_framework.views import APIViewfrom rest_framework.response import Responsefrom rest_framework import mixinsfrom rest_framework import genericsfrom rest_framework.pagination import PageNumberPaginationfrom rest_framework import viewsetsfrom rest_framework import statusfrom .models import Goodsclass GoodsPagination(PageNumberPagination):    page_size = 10    page_size_query_param = 'page_size'    page_query_param = "p"    max_page_size = 100class GoodsListViewSet(mixins.ListModelMixin,viewsets.GenericViewSet):    """商品列表页"""    queryset = Goods.objects.all()    serializer_class = GoodsSerializer    pagination_class = GoodsPagination
urls.py:

from django.conf.urls import url, include# from django.contrib import adminimport xadminfrom MxShop.settings import MEDIA_ROOTfrom django.views.static import servefrom rest_framework.documentation import include_docs_urls# from goods.views_base import GoodsListViewfrom goods.views import GoodsListViewSetgoods_list = GoodsListViewSet.as_view({    'get': 'list',})urlpatterns = [    # url(r'^admin/', admin.site.urls),    url(r'^xadmin/', xadmin.site.urls),    url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),    url(r'^media/(?P<path>.*)$', serve, {"document_root": MEDIA_ROOT}),    # 商品列表页    url(r'goods/$', goods_list, name="goods-list"),    url(r'docs/', include_docs_urls(title="慕学生鲜"))]
同样返回相同的结果

使用router

from django.conf.urls import url, include# from django.contrib import adminimport xadminfrom MxShop.settings import MEDIA_ROOTfrom django.views.static import servefrom rest_framework.documentation import include_docs_urlsfrom rest_framework.routers import DefaultRouter# from goods.views_base import GoodsListViewfrom goods.views import GoodsListViewSetrouter=DefaultRouter()#配置goods的urlrouter.register(r'goods',GoodsListViewSet)urlpatterns = [    # url(r'^admin/', admin.site.urls),    url(r'^xadmin/', xadmin.site.urls),    url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),    url(r'^media/(?P<path>.*)$', serve, {"document_root": MEDIA_ROOT}),    url(r'^',include(router.urls)),    url(r'docs/', include_docs_urls(title="慕学生鲜"))]
也返回同样结果

GenericViewSet(Viewset)     -drf

        GenericAPIView              -drf

              APIView                      -drf

                   View                       -drf

mixin

    CreateModelMixin

    ListModelMixin

    UpdateModelMixin

    RetrieveModelMixin

    DestoryModelMixin

drf的过滤

在settings中添加django-filter

django-filter官网:https://django-filter.readthedocs.io/en/master/

from .serializers import GoodsSerializerfrom rest_framework.views import APIViewfrom rest_framework.response import Responsefrom rest_framework import mixinsfrom rest_framework import genericsfrom rest_framework.pagination import PageNumberPaginationfrom django_filters.rest_framework import DjangoFilterBackendfrom rest_framework import viewsetsfrom rest_framework import statusfrom .models import Goodsclass GoodsPagination(PageNumberPagination):    page_size = 10    page_size_query_param = 'page_size'    page_query_param = "p"    max_page_size = 100class GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):    """商品列表页"""    queryset = Goods.objects.all()    serializer_class = GoodsSerializer    pagination_class = GoodsPagination    filter_backends = (DjangoFilterBackend,)    filter_fields = ('name', 'shop_price')    '''    def get_queryset(self):        queryset=Goods.objects.all()        price_min=self.request.query_params.get("price_min",0)        if price_min:            queryset=queryset.filter(shop_price__gt=int(price_min))        return queryset    '''

浏览器访问出现,过滤器图标

也可以新建filters.py:

# -*-coding:utf-8-*-import django_filtersfrom .models import Goodsclass GoodsFilter(django_filters.rest_framework.FilterSet):    """    商品的过滤类    """    price_min = django_filters.NumberFilter(name='shop_price', lookup_expr='gte')    price_max = django_filters.NumberFilter(name='shop_price', lookup_expr='lte')    class Meta:        model = Goods        fields = ['price_min', 'price_max']

views.py:

class GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):    """商品列表页"""    queryset = Goods.objects.all()    serializer_class = GoodsSerializer    pagination_class = GoodsPagination    filter_backends = (DjangoFilterBackend,)    filter_class = GoodsFilter


drf的搜索和排序

from .serializers import GoodsSerializerfrom rest_framework.views import APIViewfrom rest_framework.response import Responsefrom rest_framework import mixinsfrom rest_framework import genericsfrom rest_framework.pagination import PageNumberPaginationfrom django_filters.rest_framework import DjangoFilterBackendfrom rest_framework import viewsetsfrom rest_framework import statusfrom rest_framework import filtersfrom .models import Goodsfrom .filters import GoodsFilterclass GoodsPagination(PageNumberPagination):    page_size = 10    page_size_query_param = 'page_size'    page_query_param = "p"    max_page_size = 100class GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):    """商品列表页,分页,搜索,过滤,排序"""    queryset = Goods.objects.all()    serializer_class = GoodsSerializer    pagination_class = GoodsPagination    filter_backends = (DjangoFilterBackend,filters.SearchFilter,filters.OrderingFilter)    filter_class = GoodsFilter    search_fields = ('name', 'goods_brief', 'goods_desc')    ordering_fields=('sold_num','add_time')


商品类别数据接口

views.py:

class CategoryViewset(mixins.ListModelMixin,viewsets.GenericViewSet):    """    list:        商品分类列表数据    """    queryset = GoodsCategory.objects.all()    serializer_class = CategorySerializer
serializer.py:

# -*-coding:utf-8-*-from rest_framework import serializersfrom goods.models import Goods, GoodsCategoryclass CategorySerializer(serializers.ModelSerializer):    class Meta:        model = GoodsCategory        fields = "__all__"class GoodsSerializer(serializers.ModelSerializer):    category = CategorySerializer()    class Meta:        model = Goods        # fields = ('name', 'click_num', 'market_price', 'add_time')        fields = "__all__"
urls.py:

# _*_coding:utf-8_*_from django.conf.urls import url, include# from django.contrib import adminimport xadminfrom MxShop.settings import MEDIA_ROOTfrom django.views.static import servefrom rest_framework.documentation import include_docs_urlsfrom rest_framework.routers import DefaultRouter# from goods.views_base import GoodsListViewfrom goods.views import GoodsListViewSet, CategoryViewsetrouter = DefaultRouter()# 配置goods的urlrouter.register(r'goods', GoodsListViewSet, base_name="goods")# 配置category的urlrouter.register(r'categorys', CategoryViewset, base_name="categorys")urlpatterns = [    # url(r'^admin/', admin.site.urls),    url(r'^xadmin/', xadmin.site.urls),    url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),    url(r'^media/(?P<path>.*)$', serve, {"document_root": MEDIA_ROOT}),    url(r'^', include(router.urls)),    url(r'docs/', include_docs_urls(title="慕学生鲜"))]
浏览器访问:http://127.0.0.1:8000/categorys/

返回数据:

GET /categorys/HTTP 200 OKAllow: GET, HEAD, OPTIONSContent-Type: application/jsonVary: Accept[    {        "id": 1,        "name": "生鲜食品",        "code": "sxsp",        "desc": "",        "category_type": 1,        "is_tab": false,        "add_time": "2017-12-02T11:48:50",        "parent_category": null    },    {        "id": 2,        "name": "精品肉类",        "code": "jprl",        "desc": "",        "category_type": 2,        "is_tab": false,        "add_time": "2017-12-02T11:48:50",        "parent_category": 1    },
修改serilizer.py,呈现三级列表:

class CategorySerializer3(serializers.ModelSerializer):    class Meta:        model = GoodsCategory        fields = "__all__"class CategorySerializer2(serializers.ModelSerializer):    sub_cat = CategorySerializer3(many=True)    class Meta:        model = GoodsCategory        fields = "__all__"class CategorySerializer(serializers.ModelSerializer):    sub_cat = CategorySerializer2(many=True)    class Meta:        model = GoodsCategory        fields = "__all__"
浏览器返回数据:

GET /categorys/HTTP 200 OKAllow: GET, HEAD, OPTIONSContent-Type: application/jsonVary: Accept[    {        "id": 1,        "sub_cat": [            {                "id": 2,                "sub_cat": [                    {                        "id": 3,                        "name": "羊肉",                        "code": "yr",                        "desc": "",                        "category_type": 3,                        "is_tab": false,                        "add_time": "2017-12-02T11:48:50",                        "parent_category": 2                    },                    {                        "id": 4,                        "name": "禽类",                        "code": "ql",                        "desc": "",                        "category_type": 3,                        "is_tab": false,                        "add_time": "2017-12-02T11:48:50",                        "parent_category": 2                    },                    {                        "id": 5,                        "name": "猪肉",                        "code": "zr",                        "desc": "",                        "category_type": 3,                        "is_tab": false,                        "add_time": "2017-12-02T11:48:50",                        "parent_category": 2                    },                    {                        "id": 6,                        "name": "牛肉",                        "code": "nr",                        "desc": "",                        "category_type": 3,                        "is_tab": false,                        "add_time": "2017-12-02T11:48:50",                        "parent_category": 2                    }                ],                "name": "精品肉类",                "code": "jprl",                "desc": "",                "category_type": 2,                "is_tab": false,                "add_time": "2017-12-02T11:48:50",                "parent_category": 1            },

继承mixins.RetrieveModelMixin,可以返回商品详情页

class CategoryViewset(mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet):    """    list:        商品分类列表数据    """    queryset = GoodsCategory.objects.all()    serializer_class = CategorySerializer
浏览器访问:http://127.0.0.1:8000/categorys/12/

返回:

GET /categorys/12/HTTP 200 OKAllow: GET, HEAD, OPTIONSContent-Type: application/jsonVary: Accept{    "id": 12,    "sub_cat": [        {            "id": 13,            "sub_cat": [],            "name": "松花蛋/咸鸭蛋",            "code": "xhd_xyd",            "desc": "",            "category_type": 3,            "is_tab": false,            "add_time": "2017-12-02T11:48:50",            "parent_category": 12        },        {            "id": 14,            "sub_cat": [],            "name": "鸡蛋",            "code": "jd",            "desc": "",            "category_type": 3,            "is_tab": false,            "add_time": "2017-12-02T11:48:50",            "parent_category": 12        }    ],    "name": "蛋制品",    "code": "dzp",    "desc": "",    "category_type": 2,    "is_tab": false,    "add_time": "2017-12-02T11:48:50",    "parent_category": 1}

vue展示商品分类数据

跨域问题:https://github.com/ottoyiu/django-cors-headers

安装:pip install django-cors-headers

添加到install_apps中

'django_filters',    'corsheaders',]MIDDLEWARE = [    'corsheaders.middleware.CorsMiddleware',    'django.middleware.security.SecurityMiddleware',    'django.contrib.sessions.middleware.SessionMiddleware',    'django.middleware.common.CommonMiddleware',    'django.middleware.csrf.CsrfViewMiddleware',    'django.contrib.auth.middleware.AuthenticationMiddleware',    'django.contrib.messages.middleware.MessageMiddleware',    'django.middleware.clickjacking.XFrameOptionsMiddleware',]CORS_ORIGIN_ALLOW_ALL = TrueROOT_URLCONF = 'MxShop.urls'






































原创粉丝点击