vue+django2.0.2-rest-framework 生鲜项目
一、项目初始化
1)window下安装虚拟环境
mkvirtualenv -p=C:\Python3.6\python.exe Mxshop
2)进虚拟环境安装:
- django
- djangorestframework和相关依赖mark,filter
- pillow 图片处理
pip install djangorestframework pip install -i https://pypi.douban.com/simple django==2.0.2 pip install markdown pip install django-filter pip install pillow
3)创建项目
- 项目:MxShop
- app:users
4)setting中数据库选择mysql:
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'mxshop', #数据库名字 'USER': 'root', #账号 'PASSWORD': '***', #密码 'HOST': '127.0.0.1', #IP 'PORT': '3306', #端口 #这里引擎用innodb(默认myisam) #因为后面第三方登录时,要求引擎为INNODB # 'OPTIONS':{'init_command': 'SET storage_engine=INNODB'}, #这样设置会报错,改为 "OPTIONS":{"init_command":"SET default_storage_engine=INNODB;"} } }
Navicat连接数据库并创建mxshop数据库
此时,运行项目会出错:需要安装 MySQLclient:
自从开发全面转向python3之后,由于mysqldb不支持python3,所以django连接mysql就不能再使用mysqldb了。故而选择了mysqlclient,然而两者之间并没有太大的使用上的差异
打开终端,到虚拟环境Mxshop中安装MySQLclient
首先到 https://www.lfd.uci.edu/~gohlke/pythonlibs/, 找到 mysqlclient-1.3.13-cp36-cp36m-win_amd64.whl (最新版本)下载下来,
再在终端虚拟环境安装:
pip install mysqlclient-1.3.13-cp36-cp36m-win_amd64.whl
安装成功再运行项目即可以了
4)项目目录结构搭建:
新建两个python package (app):
- extra_apps (扩展的源码包)
- apps (放所有app)
新建两个文件夹:
- media (保存图片)
- db_tools (数据库配置文件等相关)
把extra_apps和apps标记为sources root,
然后settings中也要加路径,后面import时就只需要import users ,不用再from apps import users了 (参考下项目目录图)
#settings.py import sys sys.path.insert(0,BASE_DIR) sys.path.insert(0,os.path.join(BASE_DIR, 'apps')) sys.path.insert(0,os.path.join(BASE_DIR, 'extra_apps'))
现在项目目录情况如下:
二、users models设计
1)创建三个app ,放进apps包里(users app已经在项目创建的时候便创建了)
- goods 商品
- trade 交易
- user_operation 用户操作
python manage.py startapp goods
python manage.py startapp trade
python manage.py startapp user_operation
注意:model设计时,关于add_time 、 update_time字段的添加,应按如下类型添加:
class UserProfile(AbstractUser): """ 用户信息 """ …… add_time = models.DateTimeField(auto_now_add=True) # 创建时间应使用:auto_now_add=True update_time = models.DateTimeField(default=datetime.now) # 需要默认更新时间时,应采用defaultt=datetime.now # 注意点:
# 1. 使用auto_now、auto_now_add类型,不能通过ORM手动修改该字段(除使用update方法不更新时间外,每次修改/添加数据时,都会自动化更新修改/添加时间(不需手段填写));使用default=datetime.now、default=datetime.now() ,可通过ORM手段修改该字段(后端添加/修改数据时,需要我们手动填写添加(有默认值)时间/修改时间) # 2. 使用User.objects.update方法时,设置的default=datetime.now和auto_now=True都不会生效,而default=datetime.now能通过ORM手段修改,因此update_time参数类型要设置成default=datetime.now
# 也就是说,add_time使用auto_now_add=True可以避免人为修改数据;update_time使用default=datetime.now可以避免使用update方法不更新时间的bug(但每次更新需手动填写update_time字段,如不填写会报错)
2.1)users/models.py 设计表信息
# users/models.py from datetime import datetime from django.db import models from django.contrib.auth.models import AbstractUser class UserProfile(AbstractUser): """ 用户信息 """ GENDER_CHOICES = ( ("male", u"男"), ("female", u"女") ) #用户用手机注册,所以姓名,生日和邮箱可以为空 name = models.CharField("姓名",max_length=30, null=True, blank=True) birthday = models.DateField("出生年月",null=True, blank=True) gender = models.CharField("性别",max_length=6, choices=GENDER_CHOICES, default="female") mobile = models.CharField("电话",max_length=11) email = models.EmailField("邮箱",max_length=100, null=True, blank=True) class Meta: verbose_name = "用户信息" verbose_name_plural = verbose_name def __str__(self): return self.name class VerifyCode(models.Model): """ 验证码 """ code = models.CharField("验证码",max_length=10) mobile = models.CharField("电话",max_length=11) add_time = models.DateTimeField("添加时间",default=datetime.now) class Meta: verbose_name = "短信验证" verbose_name_plural = verbose_name def __str__(self): return self.code
UserProfile继承于Django自带AbstractUser,使用UserProfile用户,需要在setting中配置:
#settings.py #重载系统的用户,让UserProfile生效 AUTH_USER_MODEL = 'users.UserProfile' """ users存于apps包中,正常正确引用UserProfile是:apps.users.UserProfile,
但由于setting.py中配置了:sys.path.insert(0,os.path.join(BASE_DIR, 'apps')),
故可以直接通过 users.UserProfile 找到 UserProfile """
2.2)goods/models表设计
1)导入DjangoUeditor 到extra_apps目录下面 ,在models中import进去
2)将四个app(goods、trade、users、user_operation)均注册到setting中的INSTALLED_APPS:
INSTALLED_APPS = [ 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'apps.users.apps.UsersConfig', 'goods', 'trade', 'user_operation', 'users' ]
3)设置media的保存路径:
# setting.py MEDIA_URL = "/media/" MEDIA_ROOT = os.path.join(BASE_DIR, "media")
goods/models下商品分类表:
class GoodsCategory(models.Model): """ 商品分类 """ CATEGORY_TYPE = ( (1, "一级类目"), (2, "二级类目"), (3, "三级类目"), ) name = models.CharField('类别名',default="", max_length=30,help_text="类别名") code = models.CharField("类别code",default="", max_length=30,help_text="类别code") desc = models.TextField("类别描述",default="",help_text="类别描述") #目录树级别 category_type = models.IntegerField("类目级别",choices=CATEGORY_TYPE,help_text="类目级别") # 设置models有一个指向自己的外键 parent_category = models.ForeignKey("self", on_delete=models.CASCADE, null=True, blank=True, verbose_name="父类目级别", help_text="父目录",related_name="sub_cat") is_tab = models.BooleanField("是否导航",default=False,help_text="是否导航") add_time = models.DateTimeField("添加时间",default=datetime.now) class Meta: verbose_name = "商品类别" verbose_name_plural = verbose_name def __str__(self): return self.name
goods/models下商品分类下的宣传图标表:
class GoodsCategoryBrand(models.Model): """ 某一大类下的宣传商标 """ category = models.ForeignKey(GoodsCategory, on_delete=models.CASCADE, 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.name
goods/models下商品表 ,及商品轮播:
class Goods(models.Model): """ 商品 """ category = models.ForeignKey(GoodsCategory, on_delete=models.CASCADE, 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="内容", 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.name
商品轮播:
class GoodsImage(models.Model): """ 商品轮播图 """ goods = models.ForeignKey(Goods, on_delete=models.CASCADE, 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.name
goods/models下首页商品轮播:
class Banner(models.Model): """ 首页轮播的商品图,为适配首页大图 """ goods = models.ForeignKey(Goods, on_delete=models.CASCADE, 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.name
三、trade models设计
trade/models.py
from datetime import datetime from django.db import models from goods.models import Goods # 传统做法,从user.models中引入 #from users.models import UserProfile # 但是当第三方模块根本不知道你的user model在哪里如何导入呢 from django.contrib.auth import get_user_model # 这个方法会去setting中找AUTH_USER_MODEL User = get_user_model() # Create your models here. class ShoppingCart(models.Model): """ 购物车 """ user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name="用户") goods = models.ForeignKey(Goods, on_delete=models.CASCADE, verbose_name="商品") 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", "取消/超时关闭"), ("paying", "待支付"), ) # PAY_TYPE = ( # ("alipay", "支付宝"), # ("wechat", "微信"), # ) user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name="用户") # unique订单号唯一 order_sn = models.CharField(max_length=30, null=True, blank=True, unique=True, verbose_name="订单编号") # 微信支付可能会用到 # nonce_str = models.CharField(max_length=50, null=True, blank=True, unique=True, verbose_name="随机加密串") # 支付宝支付时的交易号与本系统进行关联 trade_no = models.CharField(max_length=100, unique=True, null=True, blank=True, verbose_name="交易号") # 以防用户支付到一半不支付了 pay_status = models.CharField(choices=ORDER_STATUS, default="paying", max_length=30, verbose_name="订单状态") # 订单的支付类型 # pay_type = models.CharField(choices=PAY_TYPE, default="alipay", max_length=10, 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 = "订单信息" verbose_name_plural = verbose_name def __str__(self): return str(self.order_sn) class OrderGoods(models.Model): """ 订单内的商品详情 """ # 一个订单对应多个商品,所以添加外键 order = models.ForeignKey(OrderInfo, on_delete=models.CASCADE, verbose_name="订单信息", related_name="goods") # 两个外键形成一张关联表 goods = models.ForeignKey(Goods, on_delete=models.CASCADE, 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表设计
user_operation/models.py
from datetime import datetime from django.db import models from goods.models import Goods from django.contrib.auth import get_user_model # Create your models here. User = get_user_model() class UserFav(models.Model): """ 用户收藏操作 """ user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name="用户") goods = models.ForeignKey(Goods, on_delete=models.CASCADE, verbose_name="商品", help_text="商品id") add_time = models.DateTimeField(default=datetime.now, verbose_name="添加时间") class Meta: verbose_name = '用户收藏' verbose_name_plural = verbose_name # 多个字段作为一个联合唯一索引 unique_together = ("user", "goods") def __str__(self): return self.user.name class UserAddress(models.Model): """ 用户收货地址 """ user = models.ForeignKey(User, on_delete=models.CASCADE, 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 class UserLeavingMessage(models.Model): """ 用户留言 """ MESSAGE_CHOICES = ( (1, "留言"), (2, "投诉"), (3, "询问"), (4, "售后"), (5, "求购") ) user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name="用户") message_type = models.IntegerField(default=1, choices=MESSAGE_CHOICES, verbose_name="留言类型", help_text="留言类型: 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.subject
五、migrations原理及表生成
1)点击Tools → Run manage.py Task.. → 进入manage.py调试
2)在manage.py调试界面,输入:makemigrations ,生成我们每次数据库变动的py脚本
注:makemigrations 只是用来生成这个的。真正的生成数据表必须运行migrate(作用:执行py脚本去数据库生成数据表)
3)输入:migrate ,执行py脚本去数据库生成数据表 (migrate appname :只生成单个app的数据表)
生成表数据,可以在Navicat中查看。
注:尽量不要Navicat和migrate混用。