Django+Vue开发生鲜电商平台之3.数据模型设计和资源导入

永远不要跟别人比幸运,我从来没想过我比别人幸运,我也许比他们更有毅力,在最困难的时候,他们熬不住了,我可以多熬一秒钟、两秒钟。 ——马云

Github和Gitee代码同步更新https://github.com/PythonWebProject/Django_Fresh_Ecommercehttps://gitee.com/Python_Web_Project/Django_Fresh_Ecommerce

在正式开发项目之前,要确定数据库和表结构。

一、项目初始化

在虚拟环境安装好之后,需要安装DjangoDjango REST framework,直接在虚拟环境下使用pip install djangopip install djangorestframework。为了支持Django REST framework,还需要安装markdown和django-filter,命令类似。

在PyCharm新建项目,需要选择Django,而不是Pure Python,建立好之后,需要选择解释器为建立的虚拟环境所对应的解释器,选择模板语言为Django,设置应用名为users,并取消勾选Enable Django admin。

项目创建后,通过点击PyCharm导航栏Run下的Run 'Project Name'或者命令行执行python manage.py runserver即可运行项目,再访问http://127.0.0.1:8000/如果看到以下页面即说明项目初始化成功: 项目创建 运行成功

创建项目后,主应用目录下会有一个settings.py文件,是关于项目的配置,其中有关于数据库的配置,如下:

1DATABASES = { 2 'default': { 3 'ENGINE': 'django.db.backends.sqlite3', 4 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 5 } 6}

显然,指明了数据库为sqlite,这也是Django的默认数据库,需要修改为MySQL,如下:

1DATABASES = { 2 'default': { 3 'ENGINE': 'django.db.backends.mysql', 4 'NAME': 'fresh_ec', 5 'USER': 'root', 6 'PASSWORD': 'root', 7 'HOST':'127.0.0.1', 8 'OPTIONS': {'init_command': 'SET default_storage_engine=INNODB;'} 9 } 10}

因为后面第三方登录时进行数据迁移的需要,需要添加OPTIONS参数,设置存储引擎为INNODB,否则会报错。

此时再运行项目就会报错:

1django.core.exceptions.ImproperlyConfigured: Error loading MySQLdb module. 2Did you install mysqlclient?

提示安装MySQL驱动,直接通过pip install mysqlclient安装即可。

在安装过程中可能会报错ERROR: Command errored out with exit status 1,需要在https://www.lfd.uci.edu/~gohlke/pythonlibs/#mysqlclient中下载对应系统和Python版本的安装文件并将其拷贝到虚拟环境目录下通过pip install 文件名.whl进行安装。

另外,因为项目中需要进行图片处理,因此需要安装图片处理库pillow,通过pip install pillow安装即可。

还需要进行项目目录的优化调整: 在项目主目录下New一个Python Package为apps,保存项目中所有的app,并将自动生成的users移动到apps目录下; 再在主目录下创建extra_apps包,保存源码经修改的第三方包; 创建目录media,用于保存文件和图片等; 创建目录db_tools,用于保存数据库初始化的脚本等。

为了以后开发更加方便,可以将apps和extra_apps右键Mark Directory asSources Root,完成后文件夹颜色会发生改变。

还需要将apps和extra_apps加入到settings.py的根目录参数中,如下:

1import os 2import sys 3 4# Build paths inside the project like this: os.path.join(BASE_DIR, ...) 5BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 6sys.path.insert(0, BASE_DIR) 7sys.path.insert(0, os.path.join(BASE_DIR, 'apps')) 8sys.path.insert(0, os.path.join(BASE_DIR, 'extra_apps'))

二、数据模型设计

在进行需求分析之后,即可设计数据模型,即数据表。

在创建数据模型之前,需要创建所需的app,项目中需要的app包括商品goods、交易trade、用户users、操作user_operation(是为了防止相互引用而建立的)。

创建app可以直接点击导航栏ToolsRun manage.py Task,在命令行中分别输入startapp goodsstartapp tradestartapp user_operation创建对应的app,这比手动创建文件效率高很多。创建好之后,将3个目录移动到apps目录之下即可。

此时即可在每个app下分别创建数据模型。

为了保存数据,在进行删除操作时不真正删除数据,所有模型都增加一个属性is_delete,为布尔型值,为False时表示未删除,为True时表示被删除,以此来保证数据的安全。

1.用户数据模型设计

apps/users/models下创建数据模型如下:

1from datetime import datetime 2 3from django.db import models 4from django.contrib.auth.models import AbstractUser 5 6 7# Create your models here. 8 9class UserProfile(AbstractUser): 10 '''用户''' 11 name = models.CharField(max_length=30, null=True, blank=True, verbose_name='姓名') 12 birthday = models.DateField(null=True, blank=True, verbose_name='出生日期') 13 gender = models.CharField(max_length=6, choices=(('male', u'男'), ('female', u'女')), default='female', 14 verbose_name='性别') 15 mobile = models.CharField(max_length=11, verbose_name='电话') 16 email = models.CharField(max_length=50, null=True, blank=True, verbose_name='邮箱') 17 18 is_delete = models.BooleanField(default=False, verbose_name='是否删除') 19 20 class Meta: 21 verbose_name = '用户' 22 verbose_name_plural = '用户' 23 24 def __str__(self): 25 return self.name 26 27 28class VerifyCode(models.Model): 29 code = models.CharField(max_length=10, verbose_name='验证码') 30 mobile = models.CharField(max_length=11, verbose_name='电话') 31 32 add_time = models.DateField(default=datetime.now, verbose_name='添加时间') 33 is_delete = models.BooleanField(default=False, verbose_name='是否删除') 34 35 class Meta: 36 verbose_name = '短信验证码' 37 verbose_name_plural = verbose_name 38 39 def __str__(self): 40 return self.code

此时定义的用户还未替换系统自定义的用户,还需要在settings.py中进行设置:

1ALLOWED_HOSTS = [] 2 3AUTH_USER_MODEL = 'users.UserProfile'

2.商品数据模型设计

商品包括商品分类(分为3个层次,具有从属关系)、品牌名、商品、商品轮播图、轮播商品等实体,goods/models.py建立模型如下:

1from datetime import datetime 2 3from django.db import models 4from DjangoUeditor.models import UEditorField 5 6# Create your models here. 7 8class GoodsCategory(models.Model): 9 '''商品分类''' 10 CATEGORY_TYPE = ( 11 (1, '一级类目'), 12 (2, '二级类目'), 13 (3, '三级类目'), 14 ) 15 name = models.CharField(default='', max_length=30, verbose_name='类别名', help_text='类别名') 16 code = models.CharField(default='', max_length=30, verbose_name='类别code', help_text='类别code') 17 desc = models.TextField(default='', verbose_name='类别描述', help_text='类别描述') 18 category_type = models.IntegerField(choices=CATEGORY_TYPE, verbose_name='类目级别', help_text='类目级别') 19 parent_category = models.ForeignKey('self', null=True, blank=True, verbose_name='父类别', related_name='sub_cat', on_delete=models.SET_NULL) 20 is_tab = models.BooleanField(default=False, verbose_name='是否导航', help_text='是否导航') 21 is_delete = models.BooleanField(default=False, verbose_name='是否删除') 22 23 class Meta: 24 verbose_name = '商品类别' 25 verbose_name_plural = verbose_name 26 27 def __str__(self): 28 return self.name 29 30 31class GoodsCategoryBrand(models.Model): 32 '''品牌名''' 33 name = models.CharField(default='', max_length=30, verbose_name='品牌名', help_text='品牌名') 34 desc = models.TextField(default='', max_length=200, verbose_name='品牌描述', help_text='品牌描述') 35 image = models.ImageField(max_length=200, upload_to='brand/images/') 36 add_time = models.DateField(default=datetime.now, verbose_name=u'添加时间') 37 is_delete = models.BooleanField(default=False, verbose_name='是否删除') 38 39 class Meta: 40 verbose_name = '品牌' 41 verbose_name_plural = verbose_name 42 43 def __str__(self): 44 return self.name 45 46 47class Goods(models.Model): 48 '''商品''' 49 category = models.ForeignKey(GoodsCategory, verbose_name='商品类目', null=True, on_delete=models.SET_NULL) 50 goods_sn = models.CharField(max_length=50, default='', verbose_name='商品唯一货号') 51 name = models.CharField(max_length=300, verbose_name='商品名') 52 click_num = models.IntegerField(default=0, verbose_name='点击量') 53 sold_num = models.IntegerField(default=0, verbose_name='销售量') 54 fav_num = models.IntegerField(default=0, verbose_name='收藏量') 55 goods_num = models.IntegerField(default=0, verbose_name='库存量') 56 market_price = models.FloatField(default=0, verbose_name='市场价格') 57 shop_price = models.FloatField(default=0, verbose_name='本店价格') 58 goods_brief = models.TextField(max_length=500, verbose_name='商品简介') 59 goods_desc = UEditorField(verbose_name=u'内容', imagePath='goods/images/', width=1000, height=300, filePath='goods/files/', default='') 60 ship_free = models.BooleanField(default=True, verbose_name='是否承担运费') 61 goods_front_image = models.ImageField(upload_to='goods/images/', null=True, blank=True, verbose_name='封面图') 62 is_new = models.BooleanField(default=False, verbose_name='是否新品') 63 is_home = models.BooleanField(default=False, verbose_name='是否热销') 64 65 add_time = models.DateField(default=datetime.now, verbose_name=u'添加时间') 66 is_delete = models.BooleanField(default=False, verbose_name='是否删除') 67 68 69class GoodsImage(models.Model): 70 '''商品轮播图''' 71 goods = models.ForeignKey(Goods, verbose_name='', related_name='商品', null=True, on_delete=models.SET_NULL) 72 image = models.ImageField(upload_to='', null=True, blank=True, verbose_name='图片') 73 image_url = models.CharField(max_length=300, null=True, blank=True, verbose_name='图片链接') 74 75 add_time = models.DateField(default=datetime.now, verbose_name=u'添加时间') 76 is_delete = models.BooleanField(default=False, verbose_name='是否删除') 77 78 class Meta: 79 verbose_name = '商品轮播图' 80 verbose_name_plural = verbose_name 81 82 def __str__(self): 83 return self.goods.name 84 85 86class Banner(models.Model): 87 '''轮播商品''' 88 goods = models.ForeignKey(Goods, verbose_name='商品', null=True, on_delete=models.SET_NULL) 89 image = models.ImageField(upload_to='banner', verbose_name='轮播图片') 90 index = models.IntegerField(default=0, verbose_name='轮播顺序') 91 92 add_time = models.DateField(default=datetime.now, verbose_name='添加时间') 93 is_delete = models.BooleanField(default=False, verbose_name='是否删除') 94 95 class Meta: 96 verbose_name = '轮播商品' 97 verbose_name_plural = verbose_name 98 99 def __str__(self): 100 return self.goods.name

在建立商品模型时,需要用到百度的富文本编辑器UEditor,但是由于官方的Django UEditor停止维护、不再支持Python3,因此需要自行下载,可点击https://download.csdn.net/download/CUFEECR/12641702https://github.com/twz915/DjangoUeditor3/下载并解压后,将DjangoEeditor目录放入项目的extra_apps目录下,并在settings.py中添加app如下:

1INSTALLED_APPS = [ 2 'django.contrib.auth', 3 'django.contrib.contenttypes', 4 'django.contrib.sessions', 5 'django.contrib.messages', 6 'django.contrib.staticfiles', 7 'apps.users.apps.UsersConfig', 8 'goods', 9 'trade', 10 'user_operation', 11 'DjangoUeditor' 12]

当然,也可以如下:

1INSTALLED_APPS = [ 2 'django.contrib.auth', 3 'django.contrib.contenttypes', 4 'django.contrib.sessions', 5 'django.contrib.messages', 6 'django.contrib.staticfiles', 7 'apps.users.apps.UsersConfig', 8 'goods.apps.GoodsConfig', 9 'trade.apps.TradeConfig', 10 'user_operation.apps.UserOperationConfig', 11 'DjangoUeditor' 12]

效果是一样的,这里采用后者。

3.交易数据模型设计

交易涉及到购物车、订单等实体。 购物车中如果商品多次加入购物车,只有1条数据,其数量增加; 点击结算之后,购物车数量减少、结算数量增加。

trade/models.py建立购物车和订单模型如下:

1from datetime import datetime 2 3from django.db import models 4from django.contrib.auth import get_user_model # from user.models import UserProfile 5 6from goods.models import Goods 7 8User = get_user_model() 9 10 11# Create your models here. 12 13class ShoppingCart(models.Model): 14 '''购物车''' 15 user = models.ForeignKey(User, verbose_name='用户', null=True, on_delete=models.SET_NULL) 16 goods = models.ForeignKey(Goods, verbose_name='商品', null=True, on_delete=models.SET_NULL) 17 goods_num = models.IntegerField(default=0, verbose_name='商品数量') 18 19 add_time = models.DateField(default=datetime.now, verbose_name=u'添加时间') 20 is_delete = models.BooleanField(default=False, verbose_name='是否删除') 21 22 class Meta: 23 verbose_name = '购物车' 24 verbose_name_plural = verbose_name 25 26 def __str__(self): 27 return '%s(%d)'.format(self.goods.name, self.goods_num) 28 29 30class OrderInfo(models.Model): 31 '''订单信息''' 32 ORDER_STATUS = ( 33 ('success', '成功'), 34 ('cancel', '取消'), 35 ('paying', '待支付'), 36 ) 37 user = models.ForeignKey(User, verbose_name='用户', null=True, on_delete=models.SET_NULL) 38 order_sn = models.CharField(max_length=30, unique=True, verbose_name='订单号') 39 trade_no = models.CharField(max_length=50, unique=True, null=True, blank=True, verbose_name='交易号') 40 pay_status = models.CharField(max_length=100, choices=ORDER_STATUS, verbose_name='订单状态') 41 pay_script = models.CharField(max_length=11, verbose_name='订单留言') 42 order_mount = models.FloatField(default=0.0, verbose_name='订单金额') 43 pay_time = models.DateTimeField(null=True, blank=True, verbose_name='支付时间') 44 45 # 用户基本信息 46 address = models.CharField(max_length=100, default='', verbose_name='收货地址') 47 signer_name = models.CharField(max_length=20, default='', verbose_name='签收人') 48 signer_mobile = models.CharField(max_length=11, verbose_name='联系电话') 49 50 add_time = models.DateField(default=datetime.now, verbose_name=u'添加时间') 51 is_delete = models.BooleanField(default=False, verbose_name='是否删除') 52 53 54class OrderGoods(models.Model): 55 '''订单商品详情''' 56 order = models.ForeignKey(OrderInfo, verbose_name='订单信息', null=True, on_delete=models.SET_NULL) 57 goods = models.ForeignKey(Goods, verbose_name='商品', null=True, on_delete=models.SET_NULL) 58 goods_num = models.IntegerField(default=0, verbose_name='商品数量') 59 60 add_time = models.DateField(default=datetime.now, verbose_name=u'添加时间') 61 is_delete = models.BooleanField(default=False, verbose_name='是否删除') 62 63 class Meta: 64 verbose_name = '订单商品' 65 verbose_name_plural = verbose_name 66 67 def __str__(self): 68 return self.order.order_sn

在定义购物车模型、需要导入用户模型时,因为假如是第三方项目,不知道其定义的具体用户模型和存放目录,所以from user.models import UserProfile具有一定的局限性。因为之前已经将UserProfile注册到系统用户,所以可以直接用Django提供的函数get_user_model()来获取用户,这样显得更加灵活。

4.用户操作数据模型设计

最典型的操作是收藏、添加收货地址和留言。

user_operation/models.py建立模型如下:

1from datetime import datetime 2 3from django.db import models 4from django.contrib.auth import get_user_model 5 6from goods.models import Goods 7 8User = get_user_model() 9 10 11# Create your models here. 12 13class UserFav(models.Model): 14 '''用户收藏''' 15 user = models.ForeignKey(User, verbose_name='用户', null=True, on_delete=models.SET_NULL) 16 goods = models.ForeignKey(Goods, verbose_name='商品', null=True, on_delete=models.SET_NULL) 17 18 add_time = models.DateField(default=datetime.now, verbose_name=u'添加时间') 19 is_delete = models.BooleanField(default=False, verbose_name='是否删除') 20 21 class Meta: 22 verbose_name = '用户收藏' 23 verbose_name_plural = verbose_name 24 25 def __str__(self): 26 return self.user.name 27 28 29class UserLeavingMessage(models.Model): 30 '''用户留言''' 31 MESSAGE_CHOICES = ( 32 (1, '留言'), 33 (2, '投诉'), 34 (3, '询问'), 35 (4, '售后'), 36 (5, '求购'), 37 ) 38 user = models.ForeignKey(User, verbose_name='用户', null=True, on_delete=models.SET_NULL) 39 message_type = models.IntegerField(default=1, choices=MESSAGE_CHOICES, verbose_name='留言类型', 40 help_text='留言类型: 1(留言), 2(投诉), 3(询问),4(售后), 5(求购)') 41 subject = models.CharField(max_length=80, default='', verbose_name='主题') 42 message = models.TextField(default='', verbose_name='留言内容', help_text='留言内容') 43 file = models.FileField(verbose_name='上传的文件', help_text='上传的文件') 44 45 add_time = models.DateField(default=datetime.now, verbose_name=u'添加时间') 46 is_delete = models.BooleanField(default=False, verbose_name='是否删除') 47 48 class Meta: 49 verbose_name = '用户留言' 50 verbose_name_plural = verbose_name 51 52 def __str__(self): 53 return self.subject 54 55 56class UserAddress(models.Model): 57 '''用户收货地址''' 58 user = models.ForeignKey(User, verbose_name='用户', null=True, on_delete=models.SET_NULL) 59 district = models.CharField(max_length=50, default='', verbose_name='区域') 60 address = models.CharField(max_length=100, default='', verbose_name='详细地址') 61 signer_name = models.CharField(max_length=20, default='', verbose_name='签收人') 62 signer_mobile = models.CharField(max_length=11, default='', verbose_name='联系电话') 63 64 add_time = models.DateField(default=datetime.now, verbose_name=u'添加时间') 65 is_delete = models.BooleanField(default=False, verbose_name='是否删除') 66 67 class Meta: 68 verbose_name = '收货地址' 69 verbose_name_plural = verbose_name 70 71 def __str__(self): 72 return self.address

三、xadmin后台管理系统的配置

xadmin是一个Django自带后台管理工具的替代品,可以直接使用pip install xadmin命令安装,但是由于通过这种方式安装的官方版本对版本2.1及以后的Django支持不友好,因此可点击https://download.csdn.net/download/CUFEECR/12647622下载修改后的版本,并将其解压放入extra_apps下。

然后在4个apps下分别创建adminx.py,apps/goods/adminx.py如下:

1import xadmin 2from .models import Goods, GoodsCategory, GoodsImage, GoodsCategoryBrand, Banner 3 4class GoodsAdmin(object): 5 list_display = ["name", "click_num", "sold_num", "fav_num", "goods_num", "market_price", 6 "shop_price", "goods_brief", "goods_desc", "is_new", "is_hot", "add_time"] 7 search_fields = ['name', ] 8 list_editable = ["is_hot", ] 9 list_filter = ["name", "click_num", "sold_num", "fav_num", "goods_num", "market_price", 10 "shop_price", "is_new", "is_hot", "add_time", "category__name"] 11 style_fields = {"goods_desc": "ueditor"} 12 13 class GoodsImagesInline(object): 14 model = GoodsImage 15 exclude = ["add_time"] 16 extra = 1 17 style = 'tab' 18 19 inlines = [GoodsImagesInline] 20 21 22class GoodsCategoryAdmin(object): 23 list_display = ["name", "category_type", "parent_category", "add_time"] 24 list_filter = ["category_type", "parent_category", "name"] 25 search_fields = ['name', ] 26 27 28class GoodsBrandAdmin(object): 29 list_display = ["category", "image", "name", "desc"] 30 31 def get_context(self): 32 context = super(GoodsBrandAdmin, self).get_context() 33 if 'form' in context: 34 context['form'].fields['category'].queryset = GoodsCategory.objects.filter(category_type=1) 35 return context 36 37 38class BannerGoodsAdmin(object): 39 list_display = ["goods", "image", "index"] 40 41 42class HotSearchAdmin(object): 43 list_display = ["keywords", "index", "add_time"] 44 45 46class IndexAdAdmin(object): 47 list_display = ["category", "goods"] 48 49 50xadmin.site.register(Goods, GoodsAdmin) 51xadmin.site.register(GoodsCategory, GoodsCategoryAdmin) 52xadmin.site.register(Banner, BannerGoodsAdmin) 53xadmin.site.register(GoodsCategoryBrand, GoodsBrandAdmin)

apps/trade/adminx.py如下:

1import xadmin 2from .models import ShoppingCart, OrderInfo, OrderGoods 3 4 5class ShoppingCartAdmin(object): 6 list_display = ["user", "goods", "nums", ] 7 8 9class OrderInfoAdmin(object): 10 list_display = ["user", "order_sn", "trade_no", "pay_status", "post_script", "order_mount", 11 "order_mount", "pay_time", "add_time"] 12 13 class OrderGoodsInline(object): 14 model = OrderGoods 15 exclude = ['add_time', ] 16 extra = 1 17 style = 'tab' 18 19 inlines = [OrderGoodsInline, ] 20 21 22xadmin.site.register(ShoppingCart, ShoppingCartAdmin) 23xadmin.site.register(OrderInfo, OrderInfoAdmin)

apps/user_operation/adminx.py如下:

1import xadmin 2from .models import UserFav, UserLeavingMessage, UserAddress 3 4 5class UserFavAdmin(object): 6 list_display = ['user', 'goods', "add_time"] 7 8 9class UserLeavingMessageAdmin(object): 10 list_display = ['user', 'message_type', "message", "add_time"] 11 12 13class UserAddressAdmin(object): 14 list_display = ["signer_name", "signer_mobile", "district", "address"] 15 16 17xadmin.site.register(UserFav, UserFavAdmin) 18xadmin.site.register(UserAddress, UserAddressAdmin) 19xadmin.site.register(UserLeavingMessage, UserLeavingMessageAdmin)

apps/users/adminx.py如下:

1import xadmin 2from xadmin import views 3from .models import VerifyCode 4 5 6class BaseSetting(object): 7 enable_themes = True 8 use_bootswatch = True 9 10 11class GlobalSettings(object): 12 site_title = "生鲜后台" 13 site_footer = "fresh_ec" 14 15 16class VerifyCodeAdmin(object): 17 list_display = ['code', 'mobile', "add_time"] 18 19 20xadmin.site.register(VerifyCode, VerifyCodeAdmin) 21xadmin.site.register(views.BaseAdminView, BaseSetting) 22xadmin.site.register(views.CommAdminView, GlobalSettings)

将xadmin配置到settings.py中:

1INSTALLED_APPS = [ 2 'django.contrib.auth', 3 'django.contrib.contenttypes', 4 'django.contrib.sessions', 5 'django.contrib.messages', 6 'django.contrib.staticfiles', 7 'apps.users.apps.UsersConfig', 8 'goods', 9 'trade', 10 'user_operation', 11 'DjangoUeditor', 12 'xadmin', 13 'crispy_forms', 14 'django.contrib.admin' 15]

还需要安装xadmin的依赖包,从https://github.com/sshwsfc/xadmin/blob/master/requirements.txt可以看到,包括django、django-crispy-forms、django-import-export、django-reversion、django-formtools、future、httplib2和six,可以直接使用一条命令pip install django django-crispy-forms django-import-export django-reversion django-formtools future httplib2 six安装即可。

此外,还需要安装xlwt和xlsxwriter,这主要用于操作Excel文件、使功能更完善,直接使用命令pip install xlwt xlsxwriter安装即可。 最后还需要对xadmin进行数据映射,即执行makemigrationsmigrate即可。

如果遇到ImportError: cannot import name 'six' from 'django.utils',可按照下面方法解决: django xadmin six to django utils

如果遇到以下报错:

1forms.Field.__init__(self, required, widget, label, initial, help_text, 2TypeError: __init__() takes 1 positional argument but 6 were given

可直接在xadmin\views\dashboard.py中将forms.Field.__init__(self, required, widget, label, initial, help_text, *args, **kwargs)改为forms.Field.__init__(self)即可。

如果遇到其他问题,可参考https://blog.csdn.net/CUFEECR/article/details/104031620进行解决。

进行映射后,再查询数据库:

1+------------------------------------+ 2| Tables_in_fresh_ec | 3+------------------------------------+ 4| auth_group | 5| auth_group_permissions | 6| auth_permission | 7| django_content_type | 8| django_migrations | 9| django_session | 10| goods_banner | 11| goods_goods | 12| goods_goodscategory | 13| goods_goodscategorybrand | 14| goods_goodsimage | 15| trade_ordergoods | 16| trade_orderinfo | 17| trade_shoppingcart | 18| user_operation_useraddress | 19| user_operation_userfav | 20| user_operation_userleavingmessage | 21| users_userprofile | 22| users_userprofile_groups | 23| users_userprofile_user_permissions | 24| users_verifycode | 25| xadmin_bookmark | 26| xadmin_log | 27| xadmin_usersettings | 28| xadmin_userwidget | 29+------------------------------------+ 3025 rows in set (0.01 sec) 31

显然,xadmin的数据表已经映射进数据库。

此时,还需要对xadmin配置访问路径,urls.py如下:

1from django.conf.urls import url 2import xadmin 3 4urlpatterns = [ 5 url(r'^xadmin/', xadmin.site.urls), 6]

此时还需要创建超级用户,在manage.py@Fresh Ecommerce窗口中执行createsuperuser命令,输入用户名、邮箱和密码后即可创建超级管理员。

然后访问http://127.0.0.1:8000/xadmin/如下: django xadmin login

显然,此时可以(用刚刚创建的用户名和密码)登录后台,但是网页语言还是英文,需要对settings.py进行设置如下:

1LANGUAGE_CODE = 'zh-hans' # 中文支持 2 3TIME_ZONE = 'Asia/Shanghai' 4 5USE_I18N = True 6 7USE_L10N = True 8 9USE_TZ = False

apps/goods/apps.py如下:

1from django.apps import AppConfig 2 3 4class GoodsConfig(AppConfig): 5 name = 'goods' 6 verbose_name = '商品' 7

apps/trade/apps.py如下:

1from django.apps import AppConfig 2 3 4class TradeConfig(AppConfig): 5 name = 'trade' 6 verbose_name = '交易管理' 7

apps/user_operation/apps.py如下:

1from django.apps import AppConfig 2 3 4class UserOperationConfig(AppConfig): 5 name = 'user_operation' 6 verbose_name = '用户操作管理' 7

apps/user/apps.py如下:

1from django.apps import AppConfig 2 3 4class UsersConfig(AppConfig): 5 name = 'apps.users' 6 verbose_name = '用户管理' 7

此时再查看网页如下: django xadmin detail show 显然,此时已经变为中文,并且点击每个导航栏都能看到具体内容,并且可以进行导出数据等多种操作。

四、数据迁移和数据导入

1.migration原理和表的生成

在导航栏Tools选择点击Run manage.py Task...,在命令行中输入makemigrations并执行,执行完之后,可以看到每个app下的migrations均生成了0001_initial.py文件。 但是此时数据还并未真正映射到数据库中,还需要执行migrate命令来执行之前生成的Python文件来映射数据库。也可以在migrate后跟一个具体的app名称来对某个app进行数据库映射,如migrate users命令就只会映射users下的数据模型。

执行之后,数据库中已经创建出数据模型所对应的表,可以查询如下:

1show tables;

打印:

1+------------------------------------+ 2| Tables_in_fresh_ec | 3+------------------------------------+ 4| auth_group | 5| auth_group_permissions | 6| auth_permission | 7| django_content_type | 8| django_migrations | 9| django_session | 10| goods_banner | 11| goods_goods | 12| goods_goodscategory | 13| goods_goodscategorybrand | 14| goods_goodsimage | 15| trade_ordergoods | 16| trade_orderinfo | 17| trade_shoppingcart | 18| user_operation_useraddress | 19| user_operation_userfav | 20| user_operation_userleavingmessage | 21| users_userprofile | 22| users_userprofile_groups | 23| users_userprofile_user_permissions | 24| users_verifycode | 25+------------------------------------+ 2622 rows in set (0.00 sec) 27

可以看到,所有的表名称都是由两部分组成,前面是所在的app的名称,剩下的是模型名称的小写形式。

注意: (1)映射完之后,再修改模型,还需要再次执行makemigrationsmigrate命令再次同步表到数据库; django_migrations表保存了每次映射所执行的Python文件,因此不能随意删改这个表中的数据和映射产生的Python文件,否则会对数据映射产生影响。 (2)一旦使用Django模型设计和修改数据模型,就不要再轻易使用MySQL管理工具如Navicat等来手动修改表结构,这样两边不一致会很容易出错。

2.导入商品类别和商品数据

现在是没有数据的,但是为了测试的方便,需要制造一些测试数据并导入。

需要将测试商品的图片文件导入到media/goods目录下,将测试品牌的图片文件导入到media/brands目录下。

然后在db_tools目录下创建名为data的Package,下创建商品数据product_data.py如下:

1row_data = [ 2 { 3 'images': [ 4 'goods/images/1_P_1449024889889.jpg', 5 'goods/images/1_P_1449024889264.jpg', 6 'goods/images/1_P_1449024889726.jpg', 7 'goods/images/1_P_1449024889018.jpg', 8 'goods/images/1_P_1449024889287.jpg' 9 ], 10 'categorys': [ 11 '首页', 12 '生鲜食品', 13 '根茎类' 14 ], 15 'market_price': '¥232元', 16 'name': '新鲜水果甜蜜香脆单果约800克', 17 'desc': '食用百香果可以增加胃部饱腹感,减少余热量的摄入,还可以吸附胆固醇和胆汁之类有机分子,抑制人体对脂肪的吸收。因此,长期食用有利于改善人体营养吸收结构,降低体内脂肪,塑造健康优美体态。', 18 'sale_price': '¥156元', 19 '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>' 20 }, 21 ..., 22 { 23 'sale_price': '¥12元', 24 'images': [ 25 'goods/images/29_P_1448947631994.jpg' 26 ], 27 'market_price': '¥14元', 28 'categorys': [ 29 '首页', 30 '粮油副食', 31 '食用油' 32 ], 33 'desc': None, 34 'name': '融氏纯玉米胚芽油5l桶', 35 '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>' 36 } 37] 38 39pass 40

再创建category_data.py如下:

1row_data = [ 2 { 3 'sub_categorys': [ 4 { 5 'sub_categorys': [ 6 { 7 'code': 'yr', 8 'name': '羊肉' 9 }, 10 { 11 'code': 'ql', 12 'name': '禽类' 13 }, 14 { 15 'code': 'zr', 16 'name': '猪肉' 17 }, 18 { 19 'code': 'nr', 20 'name': '牛肉' 21 } 22 ], 23 'code': 'jprl', 24 'name': '精品肉类' 25 }, 26 { 27 'sub_categorys': [ 28 { 29 'code': 'cb', 30 'name': '参鲍' 31 }, 32 { 33 'code': 'yu', 34 'name': '鱼' 35 }, 36 { 37 'code': 'xia', 38 'name': '虾' 39 }, 40 { 41 'code': 'xb', 42 'name': '蟹/贝' 43 } 44 ], 45 'code': 'hxsc', 46 'name': '海鲜水产' 47 }, 48 { 49 'sub_categorys': [ 50 { 51 'code': 'xhd_xyd', 52 'name': '松花蛋/咸鸭蛋' 53 }, 54 { 55 'code': 'jd', 56 'name': '鸡蛋' 57 } 58 ], 59 'code': 'dzp', 60 'name': '蛋制品' 61 }, 62 { 63 'sub_categorys': [ 64 { 65 'code': 'sc', 66 'name': '生菜' 67 }, 68 { 69 'code': 'bc', 70 'name': '菠菜' 71 }, 72 { 73 'code': 'yj', 74 'name': '圆椒' 75 }, 76 { 77 'code': 'xlh', 78 'name': '西兰花' 79 } 80 ], 81 'code': 'ycl', 82 'name': '叶菜类' 83 }, 84 { 85 'sub_categorys': [ 86 87 ], 88 'code': 'gjl', 89 'name': '根茎类' 90 }, 91 { 92 'sub_categorys': [ 93 94 ], 95 'code': 'qgl', 96 'name': '茄果类' 97 }, 98 { 99 'sub_categorys': [ 100 101 ], 102 'code': 'jgl', 103 'name': '菌菇类' 104 }, 105 { 106 'sub_categorys': [ 107 108 ], 109 'code': 'jksx', 110 'name': '进口生鲜' 111 } 112 ], 113 'code': 'sxsp', 114 'name': '生鲜食品' 115 }, 116 ..., 117 { 118 'sub_categorys': [ 119 { 120 'sub_categorys': [ 121 122 ], 123 'code': '白茶', 124 'name': '白茶' 125 }, 126 { 127 'sub_categorys': [ 128 129 ], 130 'code': '红茶', 131 'name': '红茶' 132 }, 133 { 134 'sub_categorys': [ 135 136 ], 137 'code': '绿茶', 138 'name': '绿茶' 139 } 140 ], 141 'code': '精选茗茶', 142 'name': '精选茗茶' 143 } 144] 145

因为存在外键的限制,因此必须先导入category数据,再导入商品数据,这里需要独立于项目单独使用Django的Model。

先创建import_category_data.py如下:

1import sys, os 2 3pwd = os.path.dirname(os.path.realpath(__file__)) 4sys.path.append(pwd + '../') 5os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'Fresh_Ecommerce.settings') 6 7import django 8 9django.setup() 10 11from goods.models import GoodsCategory # 不能位于前面的代码之前,否则会出错 12 13from db_tools.data.category_data import raw_data 14 15for lev1_cat in raw_data: 16 lev1_instance = GoodsCategory() 17 lev1_instance.code = lev1_cat['code'] 18 lev1_instance.name = lev1_cat['name'] 19 lev1_instance.category_type = 1 20 lev1_instance.save() 21 for lev2_cat in lev1_cat['sub_categorys']: 22 lev2_instance = GoodsCategory() 23 lev2_instance.code = lev2_cat['code'] 24 lev2_instance.name = lev2_cat['name'] 25 lev2_instance.category_type = 2 26 lev2_instance.parent_category = lev1_instance 27 lev2_instance.save() 28 for lev3_cat in lev2_cat['sub_categorys']: 29 lev3_instance = GoodsCategory() 30 lev3_instance.code = lev3_cat['code'] 31 lev3_instance.name = lev3_cat['name'] 32 lev3_instance.category_type = 3 33 lev3_instance.parent_category = lev2_instance 34 lev3_instance.save() 35 36print('Category data imported successfully') 37

单独运行该文件,打印:

1Category data imported successfully

显然,执行成功。

说明: 因为这里是单独使用Django的model,因此需要先进行路径的设置,来保证可以访问项目和app中的内容,所以:

1from goods.models import GoodsCategory

必须在

1import sys, os 2 3pwd = os.path.dirname(os.path.realpath(__file__)) 4sys.path.append(pwd + '../') 5os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'Fresh_Ecommerce.settings') 6 7import django 8 9django.setup()

之后,否则会报错。

此时再查询数据据库如下:

1select * from goods_goodscategory;

打印:

1+-----+---------------------+---------------------+------+---------------+--------+-----------+--------------------+------------+ 2| id | name | code | desc | category_type | is_tab | is_delete | parent_category_id | add_time | 3+-----+---------------------+---------------------+------+---------------+--------+-----------+--------------------+------------+ 4| 1 | 生鲜食品 | sxsp | | 1 | 0 | 0 | NULL | 2020-07-21 | 5| 2 | 精品肉类 | jprl | | 2 | 0 | 0 | 1 | 2020-07-21 | 6| 3 | 羊肉 | yr | | 3 | 0 | 0 | 2 | 2020-07-21 | 7| 4 | 禽类 | ql | | 3 | 0 | 0 | 2 | 2020-07-21 | 8| 5 | 猪肉 | zr | | 3 | 0 | 0 | 2 | 2020-07-21 | 9... 10| 116 | 腊味 | 腊味 | | 2 | 0 | 0 | 108 | 2020-07-21 | 11| 117 | 精选茗茶 | 精选茗茶 | | 1 | 0 | 0 | NULL | 2020-07-21 | 12| 118 | 白茶 | 白茶 | | 2 | 0 | 0 | 117 | 2020-07-21 | 13| 119 | 红茶 | 红茶 | | 2 | 0 | 0 | 117 | 2020-07-21 | 14| 120 | 绿茶 | 绿茶 | | 2 | 0 | 0 | 117 | 2020-07-21 | 15+-----+---------------------+---------------------+------+---------------+--------+-----------+--------------------+------------+ 16120 rows in set (0.01 sec) 17

可以看到,共120条数据,分3个类别。

再查看后台管理系统如下: django xadmin category data insert

显然,可以清晰地看到每个商品类别的信息。

再新建import_goods_data.py如下:

1import sys, os 2 3pwd = os.path.dirname(os.path.realpath(__file__)) 4sys.path.append(pwd + '../') 5os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'Fresh_Ecommerce.settings') 6 7import django 8 9django.setup() 10 11from goods.models import Goods, GoodsCategory, GoodsImage 12 13from db_tools.data.product_data import raw_data 14 15for goods_detail in raw_data: 16 goods = Goods() 17 goods.name = goods_detail['name'] 18 goods.market_price = float(goods_detail['market_price'].replace('¥', '').replace('元', '')) 19 goods.shop_price = float(goods_detail['sale_price'].replace('¥', '').replace('元', '')) 20 goods.goods_brief = goods_detail['desc'] if goods_detail['desc'] is not None else '' 21 goods.goods_desc = goods_detail['desc'] if goods_detail['desc'] is not None else '' 22 goods.goods_front_image = goods_detail['images'][0] if goods_detail['images'] is not None else '' 23 category_name = goods_detail['categorys'][-1] 24 category = GoodsCategory.objects.filter(name=category_name) 25 if category: 26 goods.category = category[0] 27 goods.save() 28 29 for goods_image in goods_detail['images']: 30 goods_iamge_instance = GoodsImage() 31 goods_iamge_instance.image = goods_image 32 goods_iamge_instance.goods = goods 33 goods_iamge_instance.save() 34 35 36print('Goods data imported successfully')

单独运行该文件,打印:

1Goods data imported successfully

即数据导入成功。

因为商品关系到图片,因此需要再settings.py中设置图访问路径,如下:

1STATIC_URL = '/static/' 2 3MEDIA_URL = '/media/' 4MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

urls.py配置如下:

1from django.conf.urls import url 2from django.views.static import serve 3import xadmin 4from Fresh_Ecommerce.settings import MEDIA_ROOT 5 6urlpatterns = [ 7 url(r'^xadmin/', xadmin.site.urls), 8 url(r'^media/(?P<path>.*)$', serve, {'document_root':MEDIA_ROOT}), 9] 10

再访问后台如下: django xadmin goods data insert

显然,数据已经插入成功。

本文原文首发来自博客专栏Python Web开发实战,由本人转发至https://www.helloworld.net/p/QgJupgSpkFyz,其他平台均属侵权,可点击https://blog.csdn.net/CUFEECR/article/details/107495118查看原文,也可点击https://blog.csdn.net/CUFEECR浏览更多优质原创内容。

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )

4cast

4castpackageloadcsv.KumarAwanish发布:2020122117:43:04.501348作者:KumarAwanish作者邮箱:awanish00@gmail.com首页: