三、Model设计
1、项目初始化
该项目使用Django Rest Framework完成后台功能,需要安装djangorestframework包及其相关的依赖包,pillow库是图片处理的库,在虚拟环境中安装如下包:
- pip install djangorestframework
- pip install markdown
- pip install django-filter
- pip install pillow
- pip install pymysql
安装完成之后,在settings.py中进行数据库的配置,在这之前需要在数据库中创建一个mxshop数据库:
1 DATABASES = { 2 'default': { 3 'ENGINE': 'django.db.backends.mysql', 4 'NAME': 'mxshop', 5 'USER': 'root', 6 'PASSWORD': 'python', 7 'HOST': '192.168.161.129', 8 'PORT': 3306, 9 'OPTIONS':{'init_command': 'SET default_storage_engine=INNODB;'} 10 } 11 }
然后安装对应python版本的mysqlclient,下载地址:https://www.lfd.uci.edu/~gohlke/pythonlibs/#mysqlclient,下载好之后放到项目根目录下,直接
pip install mysqlclient-1.3.13-cp36-cp36m-win_amd64.whl
然后在__init__.py文件中添加代码:
1 import pymysql 2 3 pymysql.install_as_MySQLdb()
现在完善项目的目录结构,在项目根目录下新建两个package包:
- extra_apps(扩展的源码包)
- apps(放项目创建的app)
新建两个文件夹:
- media(上传的文件)
- db_tools(数据相关)
将extra_apps和apps两个包标记为sources root,然后在settings.py中添加文件访问路径:
1 import os 2 import sys 3 4 # Build paths inside the project like this: os.path.join(BASE_DIR, ...) 5 BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 6 sys.path.insert(0, BASE_DIR) 7 sys.path.insert(0, os.path.join(BASE_DIR, 'apps')) 8 sys.path.insert(0, os.path.join(BASE_DIR, 'extra_apps'))
现在项目的目录结构如下:
2、model设计
该项目需要创建四个app,之前在创建django项目的时候已经创建了users用户app了,现在创建其余三个:
- startapp goods(商品相关)
- startapp trade(交易相关)
- startapp user_operation(用户操作相关)
将这四个app移动到项目目录的apps包下:
将xadmin的源码包和富文本DjangoUeditor的源码包放到extra_apps包下面,具体的安装方式在我的博客在线教育平台中有详细介绍,这里不再赘述:
然后将四个app和xadmin、DjangoUeditor添加到settings.py的INSTALLED_APPS中:
1 INSTALLED_APPS = [ 2 'django.contrib.auth', 3 'django.contrib.contenttypes', 4 'django.contrib.sessions', 5 'django.contrib.messages', 6 'django.contrib.staticfiles', 7 'django.contrib.admin', 8 'users', 9 'goods', 10 'trade', 11 'user_operation', 12 'xadmin', 13 'crispy_forms', 14 'DjangoUeditor', 15 'rest_framework' 16 ]
然后在settings.py中配置文件media文件上传的路径:
1 # 设置上传文件的路径 2 MEDIA_URL="/media/" 3 MEDIA_ROOT = os.path.join(BASE_DIR, "media")
配置上传文件的url:
1 from django.views.static import serve 2 3 from MxShop.settings import MEDIA_ROOT 4 5 urlpatterns = [ 6 path('media/<path:path>', serve, {'document_root': MEDIA_ROOT}), 7 ]
2.1 users的model设计
1 from datetime import datetime 2 3 from django.db import models 4 from django.contrib.auth.models import AbstractUser 5 6 # Create your models here. 7 8 9 class UserProfile(AbstractUser): 10 """用户信息""" 11 12 GENDER_CHOICES = ( 13 ('male', '男'), 14 ('female', '女') 15 ) 16 17 name = models.CharField('姓名', max_length=30, null=True, blank=True) 18 birthday = models.DateField('出生年月', null=True, blank=True) 19 gender = models.CharField('性别', choices=GENDER_CHOICES, max_length=6, default='male') 20 mobile = models.CharField('电话', max_length=11) 21 email = models.EmailField('邮箱', max_length=100, null=True, blank=True) 22 23 class Meta: 24 verbose_name = '用户信息' 25 verbose_name_plural = verbose_name 26 27 def __str__(self): 28 return self.username 29 30 31 class VerifyCode(models.Model): 32 """短信验证码""" 33 34 code = models.CharField('验证码', max_length=10) 35 mobile = models.CharField('电话', max_length=11) 36 add_time = models.DateTimeField('添加时间', default=datetime.now) 37 38 class Meta: 39 verbose_name = '短信验证码' 40 verbose_name_plural = verbose_name 41 42 def __str__(self): 43 return self.code
UserProfile继承的是django的AbstractUser,需要在settings.py中进行配置:
1 AUTH_USER_MODEL = 'users.UserProfile'
2.2 goods的model设计
依照下面的页面进行商品的model设计:
1 from datetime import datetime 2 3 from django.db import models 4 from DjangoUeditor.models import UEditorField 5 6 7 # Create your models here. 8 9 10 class GoodsCategory(models.Model): 11 """商品分类""" 12 13 CATEGORY_CHOICES = ( 14 (1, '一级类目'), 15 (2, '二级类目'), 16 (3, '三级类目'), 17 ) 18 19 name = models.CharField('类别名', max_length=30, default='', help_text='类别名') 20 code = models.CharField('类别code', max_length=30, default='', help_text='类别code') 21 desc = models.TextField('类别描述', default='', help_text='类别描述') 22 category_type = models.IntegerField('类目级别', choices=CATEGORY_CHOICES, help_text='类目级别') 23 parent_category = models.ForeignKey('self', on_delete=models.CASCADE, null=True, blank=True, verbose_name='父类目级别', 24 help_text='父类目级别', related_name='sub_cat') 25 is_tab = models.BooleanField('是否导航', default=False, help_text='是否导航') 26 add_time = models.DateTimeField('添加时间', default=datetime.now) 27 28 class Meta: 29 verbose_name = '商品类别' 30 verbose_name_plural = verbose_name 31 32 def __str__(self): 33 return self.name 34 35 36 class GoodsCategoryBrand(models.Model): 37 """商品宣传商标""" 38 category = models.ForeignKey(GoodsCategory, on_delete=models.CASCADE, related_name='brands', null=True, blank=True, 39 verbose_name="商品类目") 40 name = models.CharField("品牌名", default="", max_length=30, help_text="品牌名") 41 desc = models.TextField("品牌描述", default="", max_length=200, help_text="品牌描述") 42 image = models.ImageField(max_length=200, upload_to="brands/images/") 43 add_time = models.DateTimeField("添加时间", default=datetime.now) 44 45 class Meta: 46 verbose_name = "宣传品牌" 47 verbose_name_plural = verbose_name 48 db_table = "goods_goodsbrand" 49 50 def __str__(self): 51 return self.name 52 53 54 class Goods(models.Model): 55 """商品""" 56 57 category = models.ForeignKey(GoodsCategory, on_delete=models.CASCADE, verbose_name='商品类目') 58 goods_sn = models.CharField('商品唯一货号', max_length=50, default='') 59 name = models.CharField('商品名', max_length=100) 60 click_nums = models.IntegerField('点击数', default=0) 61 sold_num = models.IntegerField("商品销售量", default=0) 62 fav_num = models.IntegerField("收藏数", default=0) 63 goods_num = models.IntegerField("库存数", default=0) 64 market_price = models.FloatField("市场价格", default=0) 65 shop_price = models.FloatField("本店价格", default=0) 66 goods_brief = models.CharField('商品简短描述', max_length=500) 67 goods_desc = UEditorField(verbose_name="商品描述", imagePath="goods/images/", width=1000, height=300, 68 filePath="goods/files/", default='') 69 ship_free = models.BooleanField('是否承担运费', default=True) 70 goods_front_image = models.ImageField(upload_to='goods/images/', null=True, blank=True, verbose_name='首页封面图') 71 is_new = models.BooleanField('是否新品', default=False) # 首页新品展示 72 is_hot = models.BooleanField('是否热销', default=False) # 商品详情页的热卖商品 73 add_time = models.DateTimeField('添加时间', default=datetime.now) 74 75 class Meta: 76 verbose_name = '商品信息' 77 verbose_name_plural = verbose_name 78 79 def __str__(self): 80 return self.name 81 82 83 class GoodsImage(models.Model): 84 """商品轮播图""" 85 86 goods = models.ForeignKey(Goods, on_delete=models.CASCADE, verbose_name='商品', related_name='images') 87 image = models.ImageField(upload_to='goods/images/', verbose_name='图片', null=True, blank=True) 88 add_time = models.DateTimeField('添加时间', default=datetime.now) 89 90 class Meta: 91 verbose_name = '商品轮播图' 92 verbose_name_plural = verbose_name 93 94 def __str__(self): 95 return self.goods.name 96 97 98 class Banner(models.Model): 99 """首页轮播图""" 100 101 goods = models.ForeignKey(Goods, on_delete=models.CASCADE, verbose_name='商品') 102 image = models.ImageField(upload_to='banners/images/', verbose_name='轮播图') 103 index = models.IntegerField('轮播顺序', default=0) 104 add_time = models.DateTimeField('添加时间', default=datetime.now) 105 106 class Meta: 107 verbose_name = '首页轮播图' 108 verbose_name_plural = verbose_name 109 110 def __str__(self): 111 return self.goods.name 112 113 114 class IndexAd(models.Model): 115 """商品广告""" 116 category = models.ForeignKey(GoodsCategory, on_delete=models.CASCADE, related_name='category', verbose_name="商品类目") 117 goods = models.ForeignKey(Goods, on_delete=models.CASCADE, related_name='goods') 118 119 class Meta: 120 verbose_name = '首页广告' 121 verbose_name_plural = verbose_name 122 123 def __str__(self): 124 return self.goods.name 125 126 127 class HotSearchWords(models.Model): 128 """热搜词""" 129 130 keywords = models.CharField('热搜词', max_length=20, default='') 131 index = models.IntegerField('排序', default=0) 132 add_time = models.DateTimeField('添加时间', default=datetime.now) 133 134 class Meta: 135 verbose_name = '热搜排行' 136 verbose_name_plural = verbose_name 137 138 def __str__(self): 139 return self.keywords
2.3 trade的model设计
1 from datetime import datetime 2 3 from django.db import models 4 from django.contrib.auth import get_user_model 5 6 from goods.models import Goods 7 8 9 # get_user_model会去setting中找AUTH_USER_MODEL 10 User = get_user_model() 11 12 # Create your models here. 13 14 15 class ShoppingCart(models.Model): 16 """购物车""" 17 18 user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name='用户') 19 goods = models.ForeignKey(Goods, on_delete=models.CASCADE, verbose_name='商品') 20 nums = models.IntegerField('购买数量', default=0) 21 add_time = models.DateTimeField('添加时间', default=datetime.now) 22 23 class Meta: 24 verbose_name = '购物车' 25 verbose_name_plural = verbose_name 26 unique_together = ('user', 'goods') 27 28 def __str__(self): 29 return self.goods.name 30 31 32 class OrderInfo(models.Model): 33 """订单信息""" 34 35 ORDER_STATUS = ( 36 ("TRADE_SUCCESS", "成功"), 37 ("TRADE_CLOSED", "超时关闭"), 38 ("WAIT_BUYER_PAY", "交易创建"), 39 ("TRADE_FINISHED", "交易结束"), 40 ("paying", "待支付"), 41 ) 42 PAY_TYPE = ( 43 ("alipay", "支付宝"), 44 ("wechat", "微信"), 45 ) 46 47 user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name='用户') 48 order_sn = models.CharField('订单编号', max_length=30, null=True, blank=True, unique=True) 49 nonce_str = models.CharField('随机加密串', max_length=50, null=True, blank=True, unique=True) # 微信支付会用到 50 trade_no = models.CharField('交易号', max_length=100, null=True, blank=True, unique=True) # 支付号交易号 51 pay_status = models.CharField('订单状态', choices=ORDER_STATUS, default='paying', max_length=30) 52 pay_type = models.CharField('支付类型', choices=PAY_TYPE, default='alipay', max_length=10) 53 post_script = models.CharField('订单留言', max_length=200) 54 order_mount = models.FloatField('订单金额', default=0.0) 55 pay_time = models.DateTimeField('支付时间', null=True, blank=True) 56 address = models.CharField('收货地址', max_length=100, default='') 57 singer_name = models.CharField('签收人', max_length=20, default='') 58 singer_mobile = models.CharField('签收电话', max_length=11) 59 add_time = models.DateTimeField('添加时间', default=datetime.now) 60 61 class Meta: 62 verbose_name = '订单信息' 63 verbose_name_plural = verbose_name 64 65 def __str__(self): 66 return str(self.order_sn) 67 68 69 class OrderGoods(models.Model): 70 """订单内商品""" 71 72 order = models.ForeignKey(OrderInfo, on_delete=models.CASCADE, verbose_name='订单信息', related_name='goods') 73 goods = models.ForeignKey(Goods, on_delete=models.CASCADE, verbose_name='商品') 74 goods_num = models.IntegerField('商品数量', default=0) 75 add_time = models.DateTimeField('添加时间', default=datetime.now) 76 77 class Meta: 78 verbose_name = '订单商品' 79 verbose_name_plural = verbose_name 80 81 def __str__(self): 82 return str(self.order.order_sn)
2.4 user_operation的model设计
1 from datetime import datetime 2 3 from django.db import models 4 from django.contrib.auth import get_user_model 5 6 from goods.models import Goods 7 8 User = get_user_model() 9 10 11 # Create your models here. 12 13 14 class UserFav(models.Model): 15 """用户收藏""" 16 17 user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name='用户') 18 goods = models.ForeignKey(Goods, on_delete=models.CASCADE, verbose_name='商品', help_text='商品id') 19 add_time = models.DateTimeField('添加时间', default=datetime.now) 20 21 class Meta: 22 verbose_name = '用户收藏' 23 verbose_name_plural = verbose_name 24 unique_together = ('user', 'goods') 25 26 def __str__(self): 27 return self.user.username 28 29 30 class UserAddress(models.Model): 31 """收货地址""" 32 33 user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name='用户') 34 province = models.CharField("省份", max_length=100, default="") 35 city = models.CharField("城市", max_length=100, default="") 36 district = models.CharField("区域", max_length=100, default="") 37 address = models.CharField("详细地址", max_length=100, default="") 38 signer_name = models.CharField("签收人", max_length=100, default="") 39 signer_mobile = models.CharField("电话", max_length=11, default="") 40 add_time = models.DateTimeField("添加时间", default=datetime.now) 41 42 class Meta: 43 verbose_name = "收货地址" 44 verbose_name_plural = verbose_name 45 46 def __str__(self): 47 return self.address 48 49 50 class UserLeavingMessage(models.Model): 51 """用户留言""" 52 53 MESSAGE_CHOICES = ( 54 (1, "留言"), 55 (2, "投诉"), 56 (3, "询问"), 57 (4, "售后"), 58 (5, "求购") 59 ) 60 user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name="用户") 61 message_type = models.IntegerField("留言类型", default=1, choices=MESSAGE_CHOICES, 62 help_text="留言类型: 1(留言),2(投诉),3(询问),4(售后),5(求购)") 63 subject = models.CharField("主题", max_length=100, default="") 64 message = models.TextField("留言内容", default="", help_text="留言内容") 65 file = models.FileField(upload_to="message/images/", verbose_name="上传的文件", help_text="上传的文件") 66 add_time = models.DateTimeField("添加时间", default=datetime.now) 67 68 class Meta: 69 verbose_name = "用户留言" 70 verbose_name_plural = verbose_name 71 72 def __str__(self): 73 return self.subject