赞
踩
1.创建项目
项目架构:
1)前端、后端部分(各五个分类):
1: 用户user 2: 商品goods 3: 购物车cart 4: 订单order 5: 后台admin
2)关系数据库:mysql
3)缓存服务器(session):redis内存型数据库
4)异步任务处理:celery
5)分布式文件存储系统:fastdfs
数据库设计:
(1)用户表:id,用户名,密码,邮箱,激活标识,权限标识
class User(AbstractUser, BaseModel):
'''用户模型类'''
class Meta:
db_table = 'df_user'
verbose_name = '用户'
verbose_name_plural = verbose_name
(2)地址表:id,收件人,收件地址,邮编,联系方式,是否默认,用户id
class Address(BaseModel): '''地址模型类''' user = models.ForeignKey('User', verbose_name='所属账户') receiver = models.CharField(max_length=20, verbose_name='收件人') addr = models.CharField(max_length=256, verbose_name='收件地址') zip_code = models.CharField(max_length=6, null=True, verbose_name='邮政编码') phone = models.CharField(max_length=11, verbose_name='联系电话') is_default = models.BooleanField(default=False, verbose_name='是否默认') # 自定义一个模型管理器对象,Django 会确保在模型类中至少有一个默认的Manager # 若没有添加自己的Manager,Django 将添加一个属性objects,它包含默认的Manager 实例 # 若添加自己的Manager实例的属性,默认值则不会出现 objects = AddressManager() class Meta: db_table = 'df_address' verbose_name = '地址' verbose_name_plural = verbose_name class AddressManager(models.Manager): '''地址模型管理器类''' # 1.改变原有查询的结果集:all() # 2.封装方法:用户操作模型类对应的数据表(增删改查) def get_default_address(self, user): '''获取用户默认收货地址''' # self.model:获取self对象所在的模型类 try: address = self.get(user=user, is_default=True) # models.Manager except self.model.DoesNotExist: # 不存在默认收货地址 address = None return address
(3)商品SKU表:id,名称,简介,价格,单位,库存,销量,图片,状态,种类ID,SPU ID
class GoodsSKU(BaseModel): '''商品SKU模型类''' status_choices = ( (0, '下线'), (1, '上线'), ) type = models.ForeignKey('GoodsType', verbose_name='商品种类') goods = models.ForeignKey('Goods', verbose_name='商品SPU') name = models.CharField(max_length=20, verbose_name='商品名称') desc = models.CharField(max_length=256, verbose_name='商品简介') price = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='商品价格') unite = models.CharField(max_length=20, verbose_name='商品单位') image = models.ImageField(upload_to='goods', verbose_name='商品图片') stock = models.IntegerField(default=1, verbose_name='商品库存') sales = models.IntegerField(default=0, verbose_name='商品销量') status = models.SmallIntegerField(default=1, choices=status_choices, verbose_name='商品状态') class Meta: db_table = 'df_goods_sku' verbose_name = '商品' verbose_name_plural = verbose_name
(4)商品种类表:id,种类名称,logo,图片
class GoodsType(BaseModel):
'''商品类型模型类'''
name = models.CharField(max_length=20, verbose_name='种类名称')
logo = models.CharField(max_length=20, verbose_name='标识')
image = models.ImageField(upload_to='type', verbose_name='商品类型图片')
class Meta:
db_table = 'df_goods_type'
verbose_name = '商品种类'
verbose_name_plural = verbose_name
def __str__(self):
return self.name
(5)首页轮播商品表:id,sku_id,图片,index(代码略,同下模型类)
(6)首页促销活动表:id,图片,活动url,index
(7)首页SPU表:id,名称,详情
(8)首页分类商品展示表:id,sku_id,种类id,展示标识,index
(9)商品图片表:id,图片,sku_id
(10)订单商品表:id,订单id,sku_id,商品数量,商品价格,评论
(11)订单信息表:订单id,地址id,用户id,支付方式,总数目,总金额,运费,支付状态,创建时间
2.创建项目
项目开发环境:linux
安装好虚拟环境(virtualenvwrapper)以及相关第三方库
输入指令:
django-admin startproject 项目名称
cd 项目目录
进入项目目录当中进行开发
3.创建应用
一个项目中可包含很多应用,本项目应用进行了模块化处理。
输入命令创建四个主要应用:
python manage.py startapp users
python manage.py startapp goods
python manage.py startapp orders
python manage.py startapp cart
在settings中的INSTALLED_APPS中配置四个应用:
(1)users(2)goods(3)orders(4) cart
python manage.py createsuperuser
创建的超级管理员也会在df_user的表中。
3.配置数据库
Django支持多种数据库,这里演示使用 sqlite,具体数据库配置于项目下的settings.py中进行。
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': os.path.join(BASE_DIR, 'db.mysql'),
}
}
5.编写models.py文件
MVT框架的M,表示model,负责与数据库交互。
进行各模型类代码编写(部分代码见项目数据库设计部分)
6.迁移模型至数据库
(1)激活模型:
于settings的INSTALLED_APPS中注册应用(如上图)
(2)生成迁移文件
进行迁移这一过程,会根据定义的模型类来生成对应的sql语句:
终端执行如下指令:
python manage.py makemigrations
如此mysql数据库部分已搭建好了。
7. 编写模板文件
MVT框架的T,表示template,负责呈现内容到浏览器。 模板是Django项目中用来向用户展示网站具体信息的部分,为html文件,不过在其基础上添加了类python的可执行代码,具有python代码的html文件通过渲染后,可生成普通的html文件。
Django项目中模板的路径为项目根目录下的templates中。
8.编写视图文件
视图Django当中用来处理用户请求的部分,对应MVT中的V(view),是框架的核心,负责接收请求、获取数据和返回结果。
视图会根据用户所发出的请求向模型获取所需数据,并将数据发送给模板,并对模板进行渲染操作,将渲染好的html文件返回给浏览器进行展示。(鉴于篇幅,本文展示项目当中购物车cart模块的view文件内容)
from django.shortcuts import render from django.views.generic import View from django.http import JsonResponse from goods.models import GoodsSKU from django_redis import get_redis_connection from utils.mixin import LoginRequiredMixin # Create your views here. # 添加商品到购物车: # 1)请求方式,采用ajax post # 如果涉及到数据的修改(新增,更新,删除), 采用post # 如果只涉及到数据的获取,采用get # 2) 传递参数: 商品id(sku_id) 商品数量(count) # ajax发起的请求都在后台,在浏览器中看不到效果 # /cart/add class CartAddView(View): '''购物车记录添加''' def post(self, request): '''购物车记录添加''' user = request.user if not user.is_authenticated(): # 用户未登录 return JsonResponse({'res':0, 'errmsg':'请先登录'}) # 接收数据 sku_id = request.POST.get('sku_id') count = request.POST.get('count') # 数据校验 if not all([sku_id, count]): return JsonResponse({'res':1, 'errmsg':'数据不完整'}) # 校验添加的商品数量 try: count = int(count) except Exception as e: # 数目出错 return JsonResponse({'res':2, 'errmsg':'商品数目出错'}) # 校验商品是否存在 try: sku = GoodsSKU.objects.get(id=sku_id) except GoodsSKU.DoesNotExist: # 商品不存在 return JsonResponse({'res':3, 'errmsg':'商品不存在'}) # 业务处理:添加购物车记录 conn = get_redis_connection('default') cart_key = 'cart_%d'%user.id # 先尝试获取sku_id的值 -> hget cart_key 属性 # 如果sku_id在hash中不存在,hget返回None cart_count = conn.hget(cart_key, sku_id) if cart_count: # 累加购物车中商品的数目 count += int(cart_count) # 校验商品的库存 if count > sku.stock: return JsonResponse({'res':4, 'errmsg':'商品库存不足'}) # 设置hash中sku_id对应的值 # hset->如果sku_id已经存在,更新数据, 如果sku_id不存在,添加数据 conn.hset(cart_key, sku_id, count) # 计算用户购物车商品的条目数 total_count = conn.hlen(cart_key) # 返回应答 return JsonResponse({'res':5, 'total_count':total_count, 'message':'添加成功'}) # /cart/ class CartInfoView(LoginRequiredMixin, View): '''购物车页面显示''' def get(self, request): '''显示''' # 获取登录的用户 user = request.user # 获取用户购物车中商品的信息 conn = get_redis_connection('default') cart_key = 'cart_%d'%user.id # {'商品id':商品数量, ...} cart_dict = conn.hgetall(cart_key) skus = [] # 保存用户购物车中商品的总数目和总价格 total_count = 0 total_price = 0 # 遍历获取商品的信息 for sku_id, count in cart_dict.items(): # 根据商品的id获取商品的信息 sku = GoodsSKU.objects.get(id=sku_id) # 计算商品的小计 amount = sku.price*int(count) # 动态给sku对象增加一个属性amount, 保存商品的小计 sku.amount = amount # 动态给sku对象增加一个属性count, 保存购物车中对应商品的数量 sku.count = count # 添加 skus.append(sku) # 累加计算商品的总数目和总价格 total_count += int(count) total_price += amount # 组织上下文 context = {'total_count':total_count, 'total_price':total_price, 'skus':skus} # 使用模板 return render(request, 'cart.html', context) # 更新购物车记录 # 采用ajax post请求 # 前端需要传递的参数:商品id(sku_id) 更新的商品数量(count) # /cart/update class CartUpdateView(View): '''购物车记录更新''' def post(self, request): '''购物车记录更新''' user = request.user if not user.is_authenticated(): # 用户未登录 return JsonResponse({'res': 0, 'errmsg': '请先登录'}) # 接收数据 sku_id = request.POST.get('sku_id') count = request.POST.get('count') # 数据校验 if not all([sku_id, count]): return JsonResponse({'res': 1, 'errmsg': '数据不完整'}) # 校验添加的商品数量 try: count = int(count) except Exception as e: # 数目出错 return JsonResponse({'res': 2, 'errmsg': '商品数目出错'}) # 校验商品是否存在 try: sku = GoodsSKU.objects.get(id=sku_id) except GoodsSKU.DoesNotExist: # 商品不存在 return JsonResponse({'res': 3, 'errmsg': '商品不存在'}) # 业务处理:更新购物车记录 conn = get_redis_connection('default') cart_key = 'cart_%d'%user.id # 校验商品的库存 if count > sku.stock: return JsonResponse({'res':4, 'errmsg':'商品库存不足'}) # 更新 conn.hset(cart_key, sku_id, count) # 计算用户购物车中商品的总件数 {'1':5, '2':3} total_count = 0 vals = conn.hvals(cart_key) for val in vals: total_count += int(val) # 返回应答 return JsonResponse({'res':5, 'total_count':total_count, 'message':'更新成功'}) # 删除购物车记录 # 采用ajax post请求 # 前端需要传递的参数:商品的id(sku_id) # /cart/delete class CartDeleteView(View): '''购物车记录删除''' def post(self, request): '''购物车记录删除''' user = request.user if not user.is_authenticated(): # 用户未登录 return JsonResponse({'res': 0, 'errmsg': '请先登录'}) # 接收参数 sku_id = request.POST.get('sku_id') # 数据的校验 if not sku_id: return JsonResponse({'res':1, 'errmsg':'无效的商品id'}) # 校验商品是否存在 try: sku = GoodsSKU.objects.get(id=sku_id) except GoodsSKU.DoesNotExist: # 商品不存在 return JsonResponse({'res':2, 'errmsg':'商品不存在'}) # 业务处理:删除购物车记录 conn = get_redis_connection('default') cart_key = 'cart_%d'%user.id # 删除 hdel conn.hdel(cart_key, sku_id) # 计算用户购物车中商品的总件数 {'1':5, '2':3} total_count = 0 vals = conn.hvals(cart_key) for val in vals: total_count += int(val) # 返回应答 return JsonResponse({'res':3, 'total_count':total_count, 'message':'删除成功'})
9.配置url 在完成网站各个功能模块的model、templates、view创建后,接下来需要将这几个部分打通起来,使其组合起来协调工作。此时,需要进行url的配置。
当客户端浏览器一个request请求到服务器的时候,首先要对请求的url信息进行解析,获取当前请求需要的信息是什么,请求会对应一个具体的view视图,视图会将模板和模型组合起来。
10.项目配置
有关项目所需进行的配置:
(1)设置应用所在路径,以便于应用注册可找到相应应用
import os
import sys
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, os.path.join(BASE_DIR, 'apps'))
(2)uwsgi上线部署
DEBUG = False
# 为了让我们的项目可以被远程访问,在设置文件中指定项目运行的主机IP:
# 在uwsgi服务器中可设置为‘*’
ALLOWED_HOSTS = ['*']
(3)uwsgi应用路径设置
WSGI_APPLICATION = 'dailyfresh.wsgi.application'
(4)url全局配置
ROOT_URLCONF = 'dailyfresh.urls'
(5)url全局配置
ROOT_URLCONF = 'dailyfresh.urls'
(6)用户模型配置
# django认证系统使用的用户模型类(由于自行定制了用户模型类)
AUTH_USER_MODEL='user.User'
(7)url全局配置
# 修改站点语言
# LANGUAGE_CODE = 'en-us'
LANGUAGE_CODE = 'zh-Hans'
# 修改站点时区
# TIME_ZONE = 'UTC'
TIME_ZONE = 'Asia/Shanghai'
(8)静态页面及文件的配置
STATIC_URL = '/static/' # 静态文件的路径设置
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')]
# 指定收集静态文件的路径
STATIC_ROOT='/var/www/dailyfresh/static'
(9)Tinymce富文本编辑器配置
# 富文本编辑器配置
TINYMCE_DEFAULT_CONFIG = {
'theme': 'advance',
'width': 600,
'height': 400,
}
(10)邮件配置
# 发送邮件配置
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
# smpt服务地址
EMAIL_HOST = 'smtp.163.com'
EMAIL_PORT = 25
# 发送邮件的邮箱
EMAIL_HOST_USER = 'smartli_it@163.com'
# 在邮箱中设置的客户端授权密码
EMAIL_HOST_PASSWORD = 'smartli123'
# 收件人看到的发件人
EMAIL_FROM = '天天生鲜<smartli_it@163.com>'
(11)Django缓存配置
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://172.16.179.142:6379/9", # redis对应的服务器ip和端口
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
}
}
}
(12)配置session存储
SESSION_ENGINE = "django.contrib.sessions.backends.cache"
SESSION_CACHE_ALIAS = "default"
(13)配置登录url地址
登录地址因项目需要而定制url登录地址,故需于settings文件中自行配置
LOGIN_URL='/user/login' # /accounts/login?next=/user
(14)FDFS配置
# 设置Django的文件存储类
DEFAULT_FILE_STORAGE='utils.fdfs.storage.FDFSStorage'
# 设置fdfs使用的client.conf文件路径
FDFS_CLIENT_CONF='./utils/fdfs/client.conf'
# 设置fdfs存储服务器上nginx的IP和端口号
FDFS_URL='http://172.16.179.131:8888/'
(15)全文检索框架的配置
# 全文检索框架HAYSTACK的配置 HAYSTACK_CONNECTIONS = { 'default': { # 使用whoosh引擎 # 'ENGINE': 'haystack.backends.whoosh_backend.WhooshEngine', 'ENGINE': 'haystack.backends.whoosh_cn_backend.WhooshEngine', # 索引文件路径 'PATH': os.path.join(BASE_DIR, 'whoosh_index'), } } # 当添加、修改、删除数据时,自动生成索引 HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor' # 指定搜索结果每页显示的条数 HAYSTACK_SEARCH_RESULTS_PER_PAGE=1
11.启动服务
# 启用django正常指令
python manage.py runserver ip:port
# 配置uwsgi服务器
启动:uwsgi –-ini 配置文件路径 例如:uwsgi –-ini uwsgi.ini
停止:uwsgi --stop uwsgi.pid路径 例如:uwsgi –-stop uwsgi.pid
12.站点管理
Django自带一套完整可定制的后端站点管理系统,可实现对项目数据库的增删改查操作。
进入方式是在项目网址后面加 /admin
(1)创建超级用户
但在进入站点管理前必须创建一个超级用户,通过超级用户才能登陆到站点管理后台。
# 创建超级用户指令
python manage.py createsuperuser
(2)注册模型
进入网站管理界面主要是为了管理数据库中的内容,但之前的工作中只是定义了模型并完成模型带数据库的迁移操作,这些只是准备操作。
要想在站点中管理数据库对象必须要先在系统管理中进行注册。
注册方法:在所创建的应用目录下的admin.py文件,在该文件中导入对应的模型列,调用admin模块的register模块。
from django.contrib import admin
from django.core.cache import cache
from goods.models import GoodsType,IndexPromotionBanner,IndexGoodsBanner,IndexTypeGoodsBanner
admin.site.register(GoodsType)
admin.site.register(IndexGoodsBanner)
admin.site.register(IndexTypeGoodsBanner)
admin.site.register(IndexPromotionBanner)
对相应的模型类注册后,便可以登录到管理界面进行数据处理了。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。