一、概述
本系统基于Django 3.0.5、PyCharm 2018.3.7、Python3.6.0,类似于淘宝的购物网站,对于用户而言能够实现登录、注册、浏览商品、加入购物车、购买等操作;对于商家而言,能够对商品进行管理,即上架、下架、修改等操作。为了保证记录遇到的每个问题,本文将边进行网站搭建边撰写。
二、需求分析
购物网站的功能相对不复杂(只实现功能、不关注访问量等因素),主要以购物为主。
从功能的需求来看,这个网站的功能分为:网站首页、用户管理、商品管理、购物车管理、订单管理、网站后台管理。
1、网站首页
网站首页是整个网站的主界面,也是网站入口界面,里面主要展示网站的动态信息及商品分类信息。
网站动态信息以推进商品为主。导航栏主要是将用户中心、订单、购物车展示,方便用户浏览。
2、用户管理
即用户信息管理与用户浏览过的商品管理。
3、商品管理
对商品进行分类管理、商品详细信息管理。商家可以在后台进行增删改查。
4、购物车管理
对用户的购物车进行管理。
5、订单管理
对用户的订单进行管理。
6、网站后台管理
可以通过网站后台对网站所有信息进行管理。
根据需求,大致将功能划分为4个app:
shoppingCart #对购物车进行管理
goods #商品以及后台管理
user #用户管理
order #订单管理
三、数据库设计分析
网站的搭建最重要的一步也是一开始就要完成的步骤就是数据库的设计。
从网站需求分析及网站功能可以知道,我们的网站主要以商品为主。所以我们在设计数据库的时候,我们主要以商品为核心数据,然后逐步向外扩展相关联的数据信息。
很显然,首先我们需要商品存储数据库,用来保存商品信息与商品分类信息。商品与分类属于多对一的关系
其次,要考虑用户的存储,用来保存用户信息。用户与浏览过的商品属于一对多的关系。
接着是购物车,购物车需要关联用户、商品。
最后是订单,订单分为总订单与分订单,定义如下:
分订单:一种商品+数量
总订单:多个分订单,即多种商品+数量
1、goods商品
goods
商品分类信息: 生鲜、肉类、日用品等
TypeInfo:type_name名称,serial_number系统编号
具体商品信息
GoodsInfo:goods_name名称 goods_image图片 goods_price价格 goods_unit单位重量 goods_click点击量 goods_description简介 goods_inventories库存 goods_details详情 goods_type分类(typeInfo) goods_suggest商品是否推荐
2、user用户名
user:
用户信息
Userinfo: user_name用户名 user_pwd密码 user_real_name真实姓名 user_sex性别 user_email邮箱 user_addr收货地址 user_postal_code邮编 user_tel电话 user_register_time注册时间
商品浏览:用户浏览过的商品
GoodsBrowser: user用户名(UserInfo) goods商品(GoodsInfo) browser_time浏览时间
3、shoppingCart购物车
shoppingCart
ShoppingCartInfo:
user用户名(userInfo) goods商品(goodsInfo) count数量
4、order订单
order
总订单:即包含多种商品
OrderInfo:orderID订单号 user用户名(UserInfo) order_time下单时间 order_pay是否支付 order_total订单总价 order_addr订单收货地址
分订单:一种商品
OrderDetailInfo:goods商品(GoodsInfo) order属于哪个总订单(OrderInfo) price价格 count数量
四、搭建项目环境
1、创建工程
当前,Pycharm版本都支持同时创建虚拟环境和Django工程。所以我们下面的操作都在Pycharm中进行。
首先打开Pycharm,进入创建工程的对话框,注意下面的红框提示:
- 在Location处选择工程目录
- 在New environment using处选择Virtualenv(这可能需要你提前pip install virtualenv进行虚拟工具virtualenv的安装)。通常情况下,虚拟环境会以venv的名字,自动在工程目录下生成。
- 在Base interpreter处,选择你要使用的Python解释器
- 下面两个单选框,根据需要自行选择。(推荐勾上inhert global site-packages,不然系统的库就没法用了)
- 如果想使用现成的解释器或者虚拟环境,请选择Existing interpreter
再点开下方的More Settings:
- Template language选择使用的模板语言,默认Django就行,可选Jinjia。
- Templates folder:Pycharm安利给我们的功能,额外创建一个工程级别的模板文件的保存目录,可以不设置,空着,这里使用默认设置吧。
- 启用Admin,一般勾上。
没什么问题了,就点击Create吧。
下面就是一段时间的等待,Pycharm会帮助我们自动创建虚拟环境,以及安装最新版本的Django。
创建完成之后,进入Pycharm的设置菜单,可以看到当前Django版本是最新的3.0.5版本。如果你要指定过去的版本,比如2.1、1.11等,那就不能这么操作了,需要在命令行下自己创建虚拟环境并安装django。或者在这里先删除Django,再安装你想要的指定版本。
看下我们当前的状态,注意venv这个虚拟环境目录,以及我们额外创建的templats目录:
2、创建app
点击Pycharm最下方工具栏中的Terminal按钮,进入终端界面,可以看到,我们已经在工程的根目录下,并且自动进入了虚拟环境内。(如果你不是通过Pycharm创建的虚拟环境,那么在这里,你可能需要手动激活虚拟环境。)
使用where python和python -V查看一下环境:
(venv) D:\pyCharm\pyCharmProjects\fatfatDaily>where python
D:\pyCharm\pyCharmProjects\fatfatDaily\venv\Scripts\python.exe
C:\Users\Administrator\AppData\Local\Programs\Python\Python36-32\python.exe
(venv) D:\pyCharm\pyCharmProjects\fatfatDaily>python -V
Python 3.6.0
根据需求分析,我们需要创建4个app,因此,首先我们在根目录下创建一个文件夹,命名为apps,并在apps文件夹下分别创建4个文件夹,名字分别为:shoppingCart、goods、order、user,然后分别运行如下命令:
python manage.py startapp shoppingCart apps/shoppingCart 在apps下创建shoppingCart这个app;
python manage.py startapp goods apps/goods 在apps下创建goods这个app;
python manage.py startapp order apps/order 在apps下创建order这个app;
python manage.py startapp user apps/user 在apps下创建user这个app;
最后,在pycharm 中,右键apps文件夹-–选择mark directory as—-选择sources root。
工程的setting.py代码中添加
sys.path.insert(0,os.path.join(BASE_DIR,'apps'))
按照上面的步骤操作完后,应用就创建成功了,让我们看一下Pycharm中的目录结构:
3、设置时区和语言
Django默认使用美国时间和英语,在项目的settings文件中,如下所示:
# Internationalization
# https://docs.djangoproject.com/en/1.11/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
我们把它改为亚洲/上海时间和中文(别问我为什么没有北京时间,也别把语言写成zh-CN),注意USE_TZ 改成False了。
# Internationalization
# https://docs.djangoproject.com/en/1.11/topics/i18n/
LANGUAGE_CODE = 'zh-hans' # 这里修改了
TIME_ZONE = 'Asia/Shanghai' # 这里修改了
USE_I18N = True
USE_L10N = True
USE_TZ = False # 这里修改了
4、启动开发服务器
现在,我们可以启动一下开发服务器,测试一下我们的工程了。
在Pycharm的Run/Debug Configurations配置界面里,将HOST设置为127.0.0.1,Port保持原样的8000,确定后,点击绿色三角,走你!
在本机的浏览器中访问http://127.0.0.1:8000/,或者点击Pycharm界面里的链接:
顺利的话,在浏览器中,你可以看到如下的欢迎界面:
五、设计数据模型
使用Django开发Web应用的过程中,很多人都是急急忙忙地写视图,写前端页面,把最根本的模型设计给忽略了。模型中定义了数据如何在数据库内保存,也就是数据表的定义方式。这部分工作体现在Django的代码中,其实就是model类的设计。
1、数据库模型设计
(1)goods
根据之前的分析,首先我们要有一张商品表,在商品表里需要保存下面的信息:
goods
商品分类信息: 生鲜、肉类、日用品等
TypeInfo:type_name名称,serial_number系统编号
具体商品信息
GoodsInfo:goods_name名称 goods_image图片 goods_price价格 goods_unit单位重量 goods_click点击量 goods_description简介 goods_inventories库存 goods_details详情 goods_type分类(typeInfo) goods_suggest商品是否推荐
Note:
为了满足商家的上架、下架、修改商品的需求,我们使用一个富文本编辑框tinymce:
① pip install django-tinymce
使用如上命令如果遇到问题:During handling of the above exception, another exception occurred:
请改用如下命令:
pip install django-tinymce -i http://pypi.douban.com/simple --trusted-host=pypi.douban.com
② 在project的settings.py里注册tinymce
INSTALLED_APPS = (
...
'tinymce', # 注册安装应用。
)
# 富文本编辑器的配置
TINYMCE_DEFAULT_CONFIG = {
'theme': 'advanced',
'width': 600,
'height': 400,
}
③ 编辑 项目名/urls.py(项目url路由配置,引入富文本编辑器的url路由):
urlpatterns = [
...
re_path(r'^tinymce/', include('tinymce.urls')), # 引入富文本编辑器的url路由。
]
④ 编辑 应用名/models.py(模型类,HTMLField字段类型):
```python
from django.db import models
from tinymce.models import HTMLField
# 定义模型类
class GoodsInfo(models.Model):
gcontent=HTMLField() # 字段类型HTMLField
⑤ 在admin中编辑,并显示效果:
from django.contrib import admin
from .models import GoodsInfo
admin.site.register(GoodsInfo)
进入admin 并编辑:
进入apps/goods/models.py文件,这里将是我们整个goods应用中所有模型的存放地点,代码如下:
from django.db import models
from datetime import datetime
from tinymce.models import HTMLField
class TypeInfo(models.Model):
#商品分类信息
isDelete = models.BooleanField(default=False) #分类信息属于重要信息,需要使用逻辑删除,及假删除
type_name = models.CharField(verbose_name="分类", max_length=20)
serial_number = models.CharField(verbose_name="系统编号", max_length=20)
def __str__(self):
return self.type_name
class Meta:
verbose_name = "商品类型"
verbose_name_plural = "商品类型"
class GoodsInfo(models.Model):
#具体商品信息
isDelete = models.BooleanField(default=False) #商品信息属于重要信息,需要使用逻辑删除,及假删除
goods_name = models.CharField(verbose_name="商品名称", max_length=40, unique=True)
goods_image = models.ImageField(verbose_name="商品图片", upload_to='goods/image/%Y/%m', null=True, blank=True)
goods_price = models.DecimalField(verbose_name="商品价格", max_digits=7, decimal_places=2) #要存储的数字最大长度为7位,而带有两个小数位
goods_unit = models.CharField(verbose_name="单位重量", max_length=20, default='500g')
goods_click = models.IntegerField(verbose_name="点击量", default=0)
goods_description = models.CharField(verbose_name="商品简介", max_length=128)
goods_inventories = models.IntegerField(verbose_name="商品库存", default=0)
goods_details = models.CharField(verbose_name="商品详情", max_length=256)
goods_type = models.ForeignKey(TypeInfo, on_delete=models.CASCADE, verbose_name="分类")
goods_suggest = models.BooleanField(verbose_name="是否推荐", default=False)
def __str__(self):
return self.goods_name
class Meta:
verbose_name = "商品信息"
verbose_name_plural = "商品信息"
(2)user
作为一个购物网站,需要保存的都是各种用户及商品的相关信息。很显然,我们至少需要一张用户表,在用户表里需要保存下面的信息:
user:
用户信息
Userinfo: user_name用户名 user_pwd密码 user_real_name真实姓名 user_sex性别 user_email邮箱 user_addr收货地址 user_postal_code邮编 user_tel电话 user_register_time注册时间
商品浏览:用户浏览过的商品
GoodsBrowser: user用户名(UserInfo) goods商品(GoodsInfo) browser_time浏览时间
进入apps/user/models.py文件,这里将是我们整个user应用中所有模型的存放地点,代码如下:
注意:关于密码,建议至少128位长度,后续如果对密码加密会使得长度很长。
from django.db import models
from datetime import datetime
from goods.models import GoodsInfo
class UserInfo(models.Model):
gender = (
('male', "男"),
('female', "女"),
)
user_name = models.CharField(verbose_name="用户名", max_length=40, unique=True)
user_pwd = models.CharField(verbose_name="用户密码", max_length=128, blank=False)
user_real_name = models.CharField(verbose_name="真实姓名", max_length=40)
user_sex = models.CharField(verbose_name="性别", max_length=20, choices=gender, default="male")
user_email = models.EmailField(verbose_name="邮箱", unique=True)
user_addr = models.CharField(verbose_name="收货地址", max_length=128, default="")
user_postal_code = models.CharField(verbose_name="邮编", max_length=6, default="")
user_tel = models.CharField(verbose_name="联系方式", max_length=11, default="")
user_register_time = models.DateTimeField(verbose_name="注册时间", auto_now_add=True)
def __str__(self):
return self.user_name
class Meta:
ordering = ['-user_register_time']
verbose_name = "用户信息"
verbose_name_plural = "用户信息"
class GoodsBrowser(models.Model):
user = models.ForeignKey(UserInfo, on_delete=models.CASCADE, verbose_name="用户ID")
goods = models.ForeignKey(GoodsInfo, on_delete=models.CASCADE, verbose_name="商品ID")
browser_time = models.DateTimeField(verbose_name="浏览时间", default=datetime.now)
def __str__(self):
return "{0}浏览记录{1}".format(self.user.user_name, self.goods.goods_name)
class Meta:
verbose_name = "用户浏览记录"
verbose_name_plural = "用户浏览记录"
(3)shoppingCart
作为一个购物网站,购物车表也是必不可少的,需要包含如下信息:
shoppingCart
ShoppingCartInfo:
user用户名(userInfo) goods商品(goodsInfo) count数量
代码如下:
from django.db import models
from user.models import UserInfo
from goods.models import GoodsInfo
class ShoppingCartInfo(models.Model):
user = models.ForeignKey(UserInfo, on_delete=models.CASCADE, verbose_name="用户")
goods = models.ForeignKey(GoodsInfo, on_delete=models.CASCADE, verbose_name="商品")
count = models.IntegerField(verbose_name="数量", default=0)
def __str__(self):
return self.user.user_name + "的购物车"
class Meta:
verbose_name = "购物车"
verbose_name_plural = "购物车"
(4)order
作为一个购物网站,订单表也是必不可少的,需要包含如下信息:
order
总订单:即包含多种商品
OrderTotalInfo:orderID订单号 user用户名(UserInfo) order_time下单时间 order_pay是否支付 order_total订单总价 order_addr订单收货地址
分订单:一种商品
OrderPartInfo:goods商品(GoodsInfo) order属于哪个总订单(OrderInfo) price价格 count数量
代码如下:
from django.db import models
from goods.models import GoodsInfo
from user.models import UserInfo
class OrderTotalInfo(models.Model):
orderID = models.CharField(verbose_name="总订单ID", max_length=30, primary_key=True)
user = models.ForeignKey(UserInfo, on_delete=models.CASCADE, verbose_name="订单用户")
order_time = models.DateTimeField(verbose_name="下单时间", auto_now=True)
order_pay = models.BooleanField(verbose_name="是否支付", default=False)
order_total = models.DecimalField(verbose_name="订单总价", max_digits=10, decimal_places=2)
order_addr = models.CharField(verbose_name="订单收货地址", max_length=128)
def __str__(self):
return "{0}在{1}的订单".format(self.user.user_name, self.order_time)
class Meta:
verbose_name = "订单"
verbose_name_plural = "订单"
class OrderPartInfo(models.Model):
goods = models.ForeignKey(GoodsInfo, on_delete=models.CASCADE, verbose_name="商品")
order = models.ForeignKey(OrderTotalInfo, on_delete=models.CASCADE, verbose_name="订单")
price = models.DecimalField(verbose_name="商品价格", max_digits=7, decimal_places=2)
count = models.IntegerField(verbose_name="商品数量", default=0)
def __str__(self):
return "{0}的数量为{1}".format(self.goods.goods_name, self.count)
class Meta:
verbose_name = "订单详情"
verbose_name_plural = "订单详情"
2、设置数据库后端
定义好了模型后,就必须选择我们用来保存数据的数据库系统。Django支持Mysql,SQLite,Oracle等等。
Django中对数据库的设置在settings文件中,如下部分:
# Database
# https://docs.djangoproject.com/en/2.2/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
Django默认使用SQLite数据库,并内置SQLite数据库的访问API,也就是说和Python一样原生支持SQLite。本项目使用SQLite作为后端数据库,因此不需要修改settings中这部分内容。如果你想要使用别的数据库,请自行修改该部分设置。
3、注册app
每次创建了新的app后,都需要在全局settings中注册,这样Django才知道你有新的应用上线了。
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'tinymce',
'goods',
'order',
'shoppingCart',
'user',
]
4、创建记录和数据表
app中的models建立好了后,并不会自动地在数据库中生成相应的数据表,需要你手动创建。
进入Pycharm的terminal终端,执行下面的命令:
python manage.py makemigrations
返回结果:
(venv) D:\pyCharm\pyCharmProjects\fatfatDaily>python manage.py makemigrations
Migrations for 'goods':
apps\goods\migrations\0001_initial.py
- Create model TypeInfo
- Create model GoodsInfo
Migrations for 'user':
apps\user\migrations\0001_initial.py
- Create model UserInfo
- Create model GoodsBrowser
Migrations for 'order':
apps\order\migrations\0001_initial.py
- Create model OrderTotalInfo
- Create model OrderPartInfo
Migrations for 'shoppingCart':
apps\shoppingCart\migrations\0001_initial.py
- Create model ShoppingCartInfo
Django自动为我们创建了migrations\0001_initial.py文件,保存了我们的第一次数据迁移工作,也就是创建了User模型。
接着执行下面的命令:
python manage.py migrate
Django将在数据库内创建真实的数据表。如果是第一次执行该命令,那么一些内置的框架,比如auth、session等的数据表也将被一同创建,如下所示:
Operations to perform:
Apply all migrations: admin, auth, contenttypes, goods, order, sessions, shoppingCart, user
Running migrations:
Applying contenttypes.0001_initial... OK
Applying auth.0001_initial... OK
Applying admin.0001_initial... OK
Applying admin.0002_logentry_remove_auto_add... OK
Applying admin.0003_logentry_add_action_flag_choices... OK
Applying contenttypes.0002_remove_content_type_name... OK
Applying auth.0002_alter_permission_name_max_length... OK
Applying auth.0003_alter_user_email_max_length... OK
Applying auth.0004_alter_user_username_opts... OK
Applying auth.0005_alter_user_last_login_null... OK
Applying auth.0006_require_contenttypes_0002... OK
Applying auth.0007_alter_validators_add_error_messages... OK
Applying auth.0008_alter_user_username_max_length... OK
Applying auth.0009_alter_user_last_name_max_length... OK
Applying auth.0010_alter_group_name_max_length... OK
Applying auth.0011_update_proxy_permissions... OK
Applying goods.0001_initial... OK
Applying user.0001_initial... OK
Applying order.0001_initial... OK
Applying sessions.0001_initial... OK
Applying shoppingCart.0001_initial... OK
六、admin后台
在我们开发的初期,没有真实的用户数据,也没有完整的测试环境,为了测试和开发的方便,通常我们会频繁地使用Django给我们提供的Admin后台管理界面,创建测试用例,观察模型效果等等。
1、在admin中注册模型
admin后台本质上是Django给我们提供的一个app,默认情况下,它已经在settings中注册了,如下所示的第一行!同样的还有session会话框架,后面我们会使用的。
(1)在goods/admin中注册模型
进入goods/admin.py文件,代码如下:
from django.contrib import admin
from .models import TypeInfo, GoodsInfo
admin.site.site_header = '商品管理'
admin.site.site_title = '商品管理'
#注册模型类
@admin.register(TypeInfo)
class TypeInfoAdmin(admin.ModelAdmin):
#列表里想要显示的字段
list_display = ("id", "type_name")
#满10条自动分页
list_per_page = 10
#设置哪些字段点击可以进入编辑界面
list_display_links = ("id", "type_name")
search_fields = ["type_name"]
@admin.register(GoodsInfo)
class GoodsInfoAdmin(admin.ModelAdmin):
#列表里想要显示的字段
list_display = ("id", "goods_name", "goods_price", "goods_unit", "goods_click", "goods_description", "goods_inventories", "goods_type", "goods_suggest")
#满10条自动分页
list_per_page = 20
#设置哪些字段点击可以进入编辑界面
list_display_links = ("id", "goods_name")
search_fields = ("goods_name", "goods_description", "goods_details")
list_editable = ["goods_inventories"]
readonly_fields = ["goods_click"]
(2)在user/admin中注册模型
from django.contrib import admin
from .models import UserInfo, GoodsBrowser
admin.site.site_header = '用户管理'
admin.site.site_title = '用户管理'
#注册模型类
@admin.register(UserInfo)
class UserInfoAdmin(admin.ModelAdmin):
#列表里想要显示的字段
list_display = ("id", "user_name")
#满10条自动分页
list_per_page = 10
#设置哪些字段点击可以进入编辑界面
list_display_links = ("id", "user_name")
search_fields = ["user_name"]
list_filter = ("user_name", "user_postal_code")
readonly_fields = ["user_name"]
@admin.register(GoodsBrowser)
class GoodsBrowserAdmin(admin.ModelAdmin):
#列表里想要显示的字段
list_display = ("id", "user", "goods")
#满10条自动分页
list_per_page = 10
list_filter = ("user__user_name", "goods__goods_name")
#设置哪些字段点击可以进入编辑界面
list_display_links = ["id", "goods"]
search_fields = ("user__user_name","goods__goods_name")
readonly_fields = ("user", "goods")
refresh_time = (3, 5)
(3)在shoppingCart/admin中注册模型
from django.contrib import admin
from .models import ShoppingCartInfo
admin.site.site_header = '购物车管理'
admin.site.site_title = '购物车管理'
@admin.register(ShoppingCartInfo)
class ShoppingCartInfoAdmin(admin.ModelAdmin):
# 列表里想要显示的字段
list_display = ("user", "goods", "count")
# 满10条自动分页
list_per_page = 10
# 设置哪些字段点击可以进入编辑界面
list_display_links = ["user"]
search_fields = ("user__user_name", "goods__goodsname")
list_filter = ["user", "goods", "count"]
readonly_fields = ("user", "goods", "count")
(4)在order/admin中注册模型
from django.contrib import admin
from .models import OrderTotalInfo, OrderPartInfo
admin.site.site_header = '订单管理'
admin.site.site_title = '订单管理'
#注册模型类
@admin.register(OrderTotalInfo)
class OrderTotalInfoAdmin(admin.ModelAdmin):
#列表里想要显示的字段
list_display = ("orderID", "user", "order_addr")
#满10条自动分页
list_per_page = 10
list_filter = ["user", "order_time", "order_addr"]
#设置哪些字段点击可以进入编辑界面
list_display_links = ("user", "order_addr")
search_fields = ["user__username"]
ordering = ["-order_time"]
@admin.register(OrderPartInfo)
class OrderPartInfoAdmin(admin.ModelAdmin):
#列表里想要显示的字段
list_display = ("goods", "order", "price", "count")
#满10条自动分页
list_per_page = 10
#设置哪些字段点击可以进入编辑界面
list_display_links = ("goods", "order", "price", "count")
list_filter = ["goods"]
2、创建超级管理员
Django的admin后台拥有完整的较为安全的用户认证和授权机制,防护等级还算可以。
要进入该后台,需要创建超级管理员,该管理员和我们先前创建的User用户不是一个概念,要注意区别对待。
同样在Pycharm的终端中,执行下面的命令:
python manage.py createsuperuser
用户名、邮箱和密码请自行设定,但一定不要忘记。密码最好有一定强度。
(venv) D:\pyCharm\pyCharmProjects\fatfatDaily>python manage.py createsuperuser
用户名 (leave blank to use 'administrator'): admin
电子邮件地址: 2103559134@qq.com
Password: 12345@MM
Password (again): 12345@MM
Superuser created successfully.
3、使用admin后台
创建好超级管理员后,就可以启动我们的开发服务器了,然后在浏览器中访问http://127.0.0.1:8000/admin/地址,可以看到如下的登录界面:
输入我们先前创建的超级管理员账户,进入管理界面:
注意,图中下方的认证和授权是admin应用自身的账户管理,上面的栏目才是我们创建的应用所对应的模型。
点击USER栏目中的用户信息链接,进入用户列表界面,发现是空的,因为我们当前没有任何用户。点击右上方的增加用户按钮,可以自己创建几个测试用户试试。
七、URL路由和视图
前面我们已经创建好数据模型了。下面我们就要设计好站点的url路由、对应的处理视图函数以及使用的前端模板了。
1、路由设计
由于网站涉及到多个app,因此采用二级路由的方式显得结构更为清晰严谨。实际上Django提倡项目有个根urls.py,各app下分别有自己的一个urls.py,既集中又分治,是一种解耦的模式。
(1)项目一级路由设计
一级路由需要包含所有二级路由,其原理是将二级路由囊括到一级路由中,Django才能找到对应的URL。
"""fatfatDailyFresh URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/3.0/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path
from django.conf.urls import url, include, re_path
urlpatterns = [
path('admin/', admin.site.urls),
re_path(r'^', include('goods.urls', namespace='goods')),
re_path(r'^user/', include('user.urls', namespace='user')),
re_path(r'^shoppingCart/', include('shoppingCart.urls', namespace='shoppingCart')),
re_path(r'^order/', include('order.urls', namespace='order')),
re_path(r'^tinymce/', include('tinymce.urls')), # 使用富文本编辑框配置confurl
]
(2)goods的URL设计
goods
商品分类信息: 生鲜、肉类、日用品等
TypeInfo:type_name名称,serial_number系统编号
具体商品信息
GoodsInfo:goods_name名称 goods_image图片 goods_price价格 goods_unit单位重量 goods_click点击量 goods_description简介 goods_inventories库存 goods_details详情 goods_type分类(typeInfo) goods_suggest商品是否推荐
根据goods的模型设计,我们发现商品包含分类与详细信息,因此需要一个首页,即index界面,一个goods list的界面,一个详细信息界面以及一个搜索界面。
from django.conf.urls import re_path
from . import views
app_name = 'goods'
urlpatterns = [
re_path('^$', views.index, name="index"),
re_path('^list(\d+)_(\d+)_(\d+)/$', views.goods_list, name="goods_list"),
re_path('^(\d+)/$', views.detail, name="detail"),
re_path(r'^*search/', views.ordinary_search, name='ordinary_search'), #全文检索
]
(3)user的URL设计
user:
用户信息
Userinfo: user_name用户名 user_pwd密码 user_real_name真实姓名 user_sex性别 user_email邮箱 user_addr收货地址 user_postal_code邮编 user_tel电话 user_register_time注册时间
商品浏览:用户浏览过的商品
GoodsBrowser: user用户名(UserInfo) goods商品(GoodsInfo) browser_time浏览时间
user包含用户信息与商品浏览记录,首先需要有注册、登录、登出功能,需要有个人中心。
#!/user/bin/env python
# -*- coding: utf-8 -*-
from django.conf.urls import url, re_path
from . import views
app_name = 'user'
urlpatterns = [
re_path(r'^register/$', views.register, name="register"),
re_path(r'^register_handle/$', views.register_handle, name="register_handle"),
re_path(r'^register_exist/$', views.register_exist, name="register_exist"),
re_path(r'^login/$', views.login, name="login"),
re_path(r'^login_handle/$', views.login_handle, name="login_handle"),
re_path(r'^info/$', views.info, name="info"),
re_path(r'^order/(\d+)$', views.order, name="order"),
re_path(r'^site/$', views.site, name="site"),
re_path(r'^logout/$', views.logout, name="logout"),
]
(4)shoppingCart的URL设计
shoppingCart
ShoppingCartInfo:
user用户名(userInfo) goods商品(goodsInfo) count数量
购物车需要提供加入、编辑、删除的功能。
#!/user/bin/env python
# -*- coding: utf-8 -*-
from django.conf.urls import url, re_path
from . import views
app_name = 'shoppingCart'
urlpatterns = [
re_path(r'^$', views.user_cart, name="cart"),
re_path(r'^add(\d+)_(\d+)/$', views.add, name="add"),
re_path(r'^edit(\d+)_(\d+)/$', views.edit, name="edit"),
re_path(r'^delete(\d+)/$', views.delete, name="delete"),
]
(5)order的URL设计
order
总订单:即包含多种商品
OrderTotalInfo:orderID订单号 user用户名(UserInfo) order_time下单时间 order_pay是否支付 order_total订单总价 order_addr订单收货地址
分订单:一种商品
OrderPartInfo:goods商品(GoodsInfo) order属于哪个总订单(OrderInfo) price价格 count数量
订单需要有查看及管理的功能。
#!/user/bin/env python
# -*- coding: utf-8 -*-
from django.conf.urls import url
from . import views
app_name = 'order'
urlpatterns = [
url(r'^$', views.order, name="order"),
url(r'^push/$', views.order_handle, name="push"),
]
2、架构初步视图
路由写好了,就进入xxx/views.py文件编写视图的框架,我们先不着急完成视图内部的具体细节,而是把框架先搭建起来。
注意:
- 在顶部额外导入了redirect,用于logout后,页面重定向;
- render方法接收request作为第一个参数,要渲染的页面为第二个参数,以及需要传递给页面的数据字典作为第三个参数(可以为空),表示根据请求的部分,以渲染的HTML页面为主体,使用模板语言将数据字典填入,然后返回给用户的浏览器。
- 渲染的对象为template目录下的html文件,这是一种安全可靠的文件组织方式,我们现在还没有创建这些文件。
代码如下:
(1)goods/views.py
from django.shortcuts import render
def index(request):
pass
return render(request, 'goods/index.html')
def good_list(request, tid, pindex, sort):
pass
return render(request, 'goods/list.html')
def detail(request, gid):
pass
return render(request, 'goods/detail.html')
def ordinary_search(request):
pass
return render(request, 'goods/ordinary_search.html')
(2)user/views.py
from django.shortcuts import render, redirect, reverse
def register(request):
pass
return render(request, 'user/register.html')
def register_handle(request):
pass
return render(request, 'user/login.html')
def register_exist(request):
pass
return None
def login(request):
pass
return render(request, 'user/login.html')
def login_handle(request):
pass
return render(request, 'user/login.html')
def logout(request): # 用户登出
request.session.flush() # 清空当前用户所有session
return redirect(reverse("goods:index"))
def info(request): # 用户中心
pass
return render(request, 'user/user_center_info.html')
def order(request, index):
pass
return render(request, 'user/user_center_order.html')
def site(request):
pass
return render(request, 'user/user_center_site.html')
(3)shoppingCart/views.py
from django.shortcuts import render, redirect, reverse
def user_cart(request):
pass
return render(request, 'shoppingCart/cart.html')
def add(request):
pass
return redirect(reverse("shoppingCart:shoppingCart"))
def edit(request):
pass
return None
def delete(request):
pass
return None
(4)order/views.py
from django.shortcuts import render
def order(request):
pass
return render(request, 'order/place_order.html')
def order_handle(request):
pass
return None
def pay(request):
pass
return None
3、创建HTML页面文件
在项目根路径的中创建一个templates目录,再在templates目录里分别创建goods/user/shoppingCart/order四个文件夹。这么做有助于app复用,防止命名冲突,能更有效地组织大型工程。
(1)创建goods的HTML页面文件
在template/goods目录中创建base.html, index.html, list.html, detail.html, ordinary_search.html五个文件,并写入如下的代码:
base.html:
{% extends 'base.html' %}
{% block center_body %}
<div class="navbar_con">
<div class="navbar clearfix">
<div class="subnav_con fl">
<h1>全部商品分类</h1>
<span></span>
<ul class="subnav">
<li><a href="/list1_1_1" class="fruit">新鲜水果</a></li>
<li><a href="/list2_1_1" class="seafood">海鲜水产</a></li>
<li><a href="#" class="meet">猪牛羊肉</a></li>
<li><a href="#" class="egg">禽类蛋品</a></li>
<li><a href="#" class="vegetables">新鲜蔬菜</a></li>
<li><a href="#" class="ice">速冻食品</a></li>
</ul>
</div>
<ul class="navlist fl">
<li><a href="{% url "goods:index" %}">首页</a></li>
<li class="interval">|</li>
<li><a href="">手机生鲜</a></li>
<li class="interval">|</li>
<li><a href="">抽奖</a></li>
</ul>
</div>
</div>
<div class="breadcrumb">
全部分类 > {{ title }}
{% if id|default:' ' != ' ' %}
> 商品详情
{% endif %}
</div>
{% block center_content %}
{% endblock center_content %}
{% endblock center_body %}
index.html:
{% extends 'base.html' %}
{% block head %}
<script type="text/javascript" src="/static/js/jquery-ui.min.js"></script>
<script type="text/javascript" src="/static/js/slide.js"></script>
{% endblock head %}
{% block center_body %}
<div class="navbar_con">
<div class="navbar">
<h1 class="fl">全部商品分类</h1>
<ul class="navlist fl">
<li><a href="{% url "goods:index" %}">首页</a></li>
<li class="interval">|</li>
<li><a href="#">手机生鲜</a></li>
<li class="interval">|</li>
<li><a href="#">抽奖</a></li>
</ul>
</div>
</div>
<div class="center_con clearfix">
<ul class="subnav fl">
<li><a href="#model01" class="fruit">新鲜水果</a></li>
<li><a href="#model02" class="seafood">海鲜水产</a></li>
<li><a href="#model03" class="meet">猪牛羊肉</a></li>
<li><a href="#model04" class="egg">禽类蛋品</a></li>
<li><a href="#model05" class="vegetables">新鲜蔬菜</a></li>
<li><a href="#model06" class="ice">速冻食品</a></li>
</ul>
<div class="slide fl">
<ul class="slide_pics">
<li><img src="/static/images/slide.jpg" alt="幻灯片"></li>
<li><img src="/static/images/slide02.jpg" alt="幻灯片"></li>
<li><img src="/static/images/slide03.jpg" alt="幻灯片"></li>
<li><img src="/static/images/slide04.jpg" alt="幻灯片"></li>
</ul>
<div class="prev"></div>
<div class="next"></div>
<ul class="points"></ul>
</div>
<div class="adv fl">
<a href="#"><img src="/static/images/adv01.jpg"></a>
<a href="#"><img src="/static/images/adv02.jpg"></a>
</div>
</div>
<div class="list_model">
<div class="list_title clearfix">
<h3 class="fl" id="model01">新鲜水果</h3>
<div class="subtitle fl">
<span>|</span>
{# <a href="#">鲜芒</a>#}
{# <a href="#">加州提子</a>#}
{# <a href="#">亚马逊牛油果</a>#}
{% for g in type01 %}
<a href="/{{ g.id }}/">{{ g.gtitle|slice:'10' }}</a>
{# 这里建立一个点击量前四位的商品的链接#}
{# 模板过滤器slice, 取变量前 N 个字符,可用于中文 #}
{% endfor %}
</div>
<a href="/list1_1_1/" class="goods_more fr" id="fruit_more">查看更多 ></a>
</div>
<div class="goods_con clearfix">
<div class="goods_banner fl"><img src="/static/images/banner01.jpg"></div>
<ul class="goods_list fl">
{# <li>#}
{# <h4><a href="#">草莓</a></h4>#}
{# <a href="#"><img src="/static/goods/goods003.jpg"></a>#}
{# <div class="prize">¥ 30.00</div>#}
{# </li>#}
{% for goods in type0 %}
{# 按照商品的最新上穿建立显示#}
<li>
<h4><a href="/{{ goods.id }}/">{{ goods.gtitle }}</a></h4>
<a href="/{{ goods.id }}/"><img src="{{ MEDIA_URL }}{{ goods.gpic }}"></a>
<div class="prize"> ¥ {{ goods.gprice }} </div>
</li>
{% endfor %}
</ul>
</div>
</div>
<div class="list_model">
<div class="list_title clearfix">
<h3 class="fl" id="model02">海鲜水产</h3>
<div class="subtitle fl">
<span>|</span>
{# <a href="#">河虾</a>#}
{# <a href="#">扇贝</a> #}
{% for g in type1 %}
<a href="/{{ g.id }}/">{{ g.gtitle|slice:'10' }}</a>
{% endfor %}
</div>
<a href="/list2_1_1/" class="goods_more fr">查看更多 ></a>
</div>
<div class="goods_con clearfix">
<div class="goods_banner fl"><img src="/static/images/banner02.jpg"></div>
<ul class="goods_list fl">
{% for goods in type11 %}
<li>
<h4><a href="/{{ goods.id }}/">{{ goods.gtitle }}</a></h4>
<a href="/{{ goods.id }}/"><img src="{{ MEDIA_URL }}{{ goods.gpic }}"></a>
{# 静态文件添加目录static前一定加"/"#}
<div class="prize"> ¥ {{ goods.gprice }} </div>
</li>
{% endfor %}
</ul>
</div>
</div>
<div class="list_model">
<div class="list_title clearfix">
<h3 class="fl" id="model03">猪牛羊肉</h3>
<div class="subtitle fl">
<span>|</span>
<a href="#">鲜芒</a>
<a href="#">加州提子</a>
<a href="#">亚马逊牛油果</a>
</div>
<a href="#" class="goods_more fr">查看更多 ></a>
</div>
<div class="goods_con clearfix">
<div class="goods_banner fl"><img src="/static/images/banner03.jpg"></div>
<ul class="goods_list fl">
<li>
<h4><a href="#">维多利亚葡萄维多利亚葡萄维多利亚葡萄维多利亚葡萄</a></h4>
<a href="#"><img src="/static/images/goods.jpg"></a>
<div class="prize">¥ 38.00</div>
</li>
<li>
<h4><a href="#">维多利亚葡萄</a></h4>
<a href="#"><img src="/static/images/goods.jpg"></a>
<div class="prize">¥ 38.00</div>
</li>
<li>
<h4><a href="#">维多利亚葡萄</a></h4>
<a href="#"><img src="/static/images/goods.jpg"></a>
<div class="prize">¥ 38.00</div>
</li>
<li>
<h4><a href="#">维多利亚葡萄</a></h4>
<a href="#"><img src="/static/images/goods.jpg"></a>
<div class="prize">¥ 38.00</div>
</li>
</ul>
</div>
</div>
<div class="list_model">
<div class="list_title clearfix">
<h3 class="fl" id="model04">禽类蛋品</h3>
<div class="subtitle fl">
<span>|</span>
<a href="#">鲜芒</a>
<a href="#">加州提子</a>
<a href="#">亚马逊牛油果</a>
</div>
<a href="#" class="goods_more fr">查看更多 ></a>
</div>
<div class="goods_con clearfix">
<div class="goods_banner fl"><img src="/static/images/banner04.jpg"></div>
<ul class="goods_list fl">
<li>
<h4><a href="#">维多利亚葡萄维多利亚葡萄维多利亚葡萄维多利亚葡萄</a></h4>
<a href="#"><img src="/static/images/goods.jpg"></a>
<div class="prize">¥ 38.00</div>
</li>
<li>
<h4><a href="#">维多利亚葡萄</a></h4>
<a href="#"><img src="/static/images/goods.jpg"></a>
<div class="prize">¥ 38.00</div>
</li>
<li>
<h4><a href="#">维多利亚葡萄</a></h4>
<a href="#"><img src="/static/images/goods.jpg"></a>
<div class="prize">¥ 38.00</div>
</li>
<li>
<h4><a href="#">维多利亚葡萄</a></h4>
<a href="#"><img src="/static/images/goods.jpg"></a>
<div class="prize">¥ 38.00</div>
</li>
</ul>
</div>
</div>
<div class="list_model">
<div class="list_title clearfix">
<h3 class="fl" id="model05">新鲜蔬菜</h3>
<div class="subtitle fl">
<span>|</span>
<a href="#">鲜芒</a>
<a href="#">加州提子</a>
<a href="#">亚马逊牛油果</a>
</div>
<a href="#" class="goods_more fr">查看更多 ></a>
</div>
<div class="goods_con clearfix">
<div class="goods_banner fl"><img src="/static/images/banner05.jpg"></div>
<ul class="goods_list fl">
<li>
<h4><a href="#">维多利亚葡萄维多利亚葡萄维多利亚葡萄维多利亚葡萄</a></h4>
<a href="#"><img src="/static/images/goods.jpg"></a>
<div class="prize">¥ 38.00</div>
</li>
<li>
<h4><a href="#">维多利亚葡萄</a></h4>
<a href="#"><img src="/static/images/goods.jpg"></a>
<div class="prize">¥ 38.00</div>
</li>
<li>
<h4><a href="#">维多利亚葡萄</a></h4>
<a href="#"><img src="/static/images/goods.jpg"></a>
<div class="prize">¥ 38.00</div>
</li>
<li>
<h4><a href="#">维多利亚葡萄</a></h4>
<a href="#"><img src="/static/images/goods.jpg"></a>
<div class="prize">¥ 38.00</div>
</li>
</ul>
</div>
</div>
<div class="list_model">
<div class="list_title clearfix">
<h3 class="fl" id="model06">速冻食品</h3>
<div class="subtitle fl">
<span>|</span>
<a href="#">鲜芒</a>
<a href="#">加州提子</a>
<a href="#">亚马逊牛油果</a>
</div>
<a href="#" class="goods_more fr">查看更多 ></a>
</div>
<div class="goods_con clearfix">
<div class="goods_banner fl"><img src="/static/images/banner06.jpg"></div>
<ul class="goods_list fl">
<li>
<h4><a href="#">维多利亚葡萄维多利亚葡萄维多利亚葡萄维多利亚葡萄</a></h4>
<a href="#"><img src="/static/images/goods.jpg"></a>
<div class="prize">¥ 38.00</div>
</li>
<li>
<h4><a href="#">维多利亚葡萄</a></h4>
<a href="#"><img src="/static/images/goods.jpg"></a>
<div class="prize">¥ 38.00</div>
</li>
<li>
<h4><a href="#">维多利亚葡萄</a></h4>
<a href="#"><img src="/static/images/goods.jpg"></a>
<div class="prize">¥ 38.00</div>
</li>
<li>
<h4><a href="#">维多利亚葡萄</a></h4>
<a href="#"><img src="/static/images/goods.jpg"></a>
<div class="prize">¥ 38.00</div>
</li>
</ul>
</div>
</div>
<script type="text/javascript" src="/static/js/slide.js"></script>
<script type="text/javascript">
BCSlideshow('focuspic');
var oFruit = document.getElementById('fruit_more');
var oShownum = document.getElementById('show_count');
var hasorder = localStorage.getItem('order_finish');
if(hasorder)
{
oShownum.innerHTML = '2';
}
oFruit.onclick = function(){
window.location.href = 'list.html';
}
</script>
{% endblock center_body %}
list.html:
{% extends 'goods/base.html' %}
{% block center_content %}
<div class="main_wrap clearfix">
<div class="l_wrap fl clearfix">
<div class="new_goods">
<h3>新品推荐</h3>
<ul>
{# <li>#}
{# <a href="#"><img src="/static/images/goods/goods001.jpg"></a>#}
{# <h4><a href="#">进口柠檬</a></h4>#}
{# <div class="prize">¥3.90</div>#}
{# </li>#}
{% for goods in news %}
{# 新品推荐两种#}
<li>
<a href="/{{ goods.id }}"><img src="{{ MEDIA_URL }}{{ goods.gpic }}"></a>
<h4><a href="/{{ goods.id }}">{{ goods.gtitle }}</a></h4>
<div class="prize">¥{{ goods.gprice }}</div>
</li>
{% endfor %}
</ul>
</div>
</div>
<div class="r_wrap fr clearfix">
<div class="sort_bar">
{# <a href="#" class="active">默认</a>#}
{# <a href="#">价格</a>#}
{# <a href="#">人气</a>#}
{# 注意视图函数中的传参顺序 另外在url中传递的链接全为字符型 #}
<a href="/list{{ typeinfo.id }}_1_1"
{% if sort == '1' %}
class="active"
{% endif %}
>默认</a>
<a href="/list{{ typeinfo.id }}_1_2"
{% if sort == '2' %}
class="active"
{% endif %}
>价格</a>
<a href="/list{{ typeinfo.id }}_1_3"
{% if sort == '3' %}
class="active"
{% endif %}
>人气</a>
</div>
<ul class="goods_type_list clearfix">
{# <li>#}
{# <a href="detail.html"><img src="/static/images/goods/goods003.jpg"></a>#}
{# <h4><a href="detail.html">大兴大棚草莓</a></h4>#}
{# <div class="operate">#}
{# <span class="prize">¥16.80</span>#}
{# <span class="unit">16.80/500g</span>#}
{# <a href="#" class="add_goods" title="加入购物车"></a>#}
{# </div>#}
{# </li>#}
{% for g in page %}
<li>
<a href="/{{ g.id }}/"><img src="{{ MEDIA_URL }}{{ g.gpic }}"></a>
<h4><a href="/{{ g.id }}/">{{ g.gtitle }}</a></h4>
<div class="operate">
<span class="prize">¥{{ g.gprice }}</span>
<span class="unit">{{ g.gunit }}</span>
<a href="/cart/add{{ g.id }}_1/" class="add_goods" title="加入购物车"></a>
{# <a href="javasript:;/" class="add_goods" title="加入购物车"></a>#}
</div>
</li>
{% endfor %}
</ul>
<div class="pagenation">
{# 判断是否是第一页#}
{% if page.has_previous %}
<a href="/list{{ typeinfo.id }}_{{ page.previous_page_number }}_{{ sort }}">上一页</a>
{% endif %}
{% for pindex in paginator.page_range %}
{% if pindex == page.number %}
<a href="/list{{ typeinfo.id }}_{{pindex}}_{{ sort }}" class="active">{{ pindex }}</a>
{% else %}
<a href="/list{{ typeinfo.id }}_{{pindex}}_{{ sort }}">{{ pindex }}</a>
{% endif %}
{% endfor %}
{# 是否为第二页#}
{% if page.has_next %}
<a href="/list{{ typeinfo.id }}_{{ page.next_page_number }}_{{ sort }}">下一页></a>
{% endif %}
</div>
</div>
</div>
{% endblock center_content %}
detail.html:
{% extends 'goods/base.html' %}
{% block head %}
<script type="text/javascript">
{# 通过绑定js事件实现随着商品数量的增长商品总价上涨#}
function plus() {
num = parseFloat($('.num_show').val());
kucun = parseFloat($('.goods_kucun').html());
if(num<=kucun){
$('.num_show').val(num+1);
$('.num_show').blur();
}
}
function minus() {
num = parseFloat($('.num_show').val());
if(num>1)
{
$('.num_show').val(num-1);
$('.num_show').blur();
}
else {
{#商品的数量不可以小于1#}
}
}
$(function () {
$('.num_show').blur(function () {
num = parseInt($('.num_show').val());
if(num<=1)
num = 1;
kucun = parseInt($('.goods_kucun').text());
if(num>=kucun)
num = kucun;
price = parseFloat($('#gprice').text());
total = num*price;
$('.num_show').val(num);
$('#gtotal').text(total.toFixed(2)+'元');
{# $('add_cart').attr('href', '/cart/add'+$('gid').val())#}
});
});
</script>
{% endblock head %}
{% block center_content %}
<div class="goods_detail_con clearfix">
<div class="goods_detail_pic fl"><img src="{{ MEDIA_URL }}{{ goods.gpic }}"></div>
<div class="goods_detail_list fr">
<h3>{{ goods.gtitle }}</h3>
<p>{{ goods.gjianjie }}</p>
<div class="prize_bar">
<span class="show_pirze">¥<em id="gprice">{{ goods.gprice }}</em></span>
<span class="show_unit">单 位:{{ goods.gunit }}</span>
<span class="show_unit">库 存:<span class="goods_kucun">{{ goods.gkucun }}</span></span>
</div>
<div class="goods_num clearfix">
<div class="num_name fl">数 量:</div>
<div class="num_add fl">
<input type="text" class="num_show fl" value="1">
<a href="javascript:plus();" class="add fr">+</a>
<a href="javascript:minus();" class="minus fr">-</a>
</div>
</div>
<div class="total">总价:<em id="gtotal">{{ goods.gprice }}元</em></div>
<div class="operate_btn">
{% if request.session.user_name|default:'' != '' %}
<a href="javascript:;" class="buy_btn" id="buy_now">立即购买</a>
{% else %}
<a href="{% url "user:login" %}" class="buy_btn">立即购买</a>
{% endif %}
{% if request.session.user_name|default:'' != '' %}
<a href="javascript:;" class="add_cart" id="add_cart">加入购物车</a>
{% else %}
<a href="{% url "user:login" %}" class="add_cart" id="add_cart">加入购物车</a>
{% endif %}
</div>
</div>
</div>
<div class="main_wrap clearfix">
<div class="l_wrap fl clearfix">
<div class="new_goods">
<h3>新品推荐</h3>
<ul>
{% for goods in news %}
<li>
<a href="/{{ goods.id }}"><img src="{{ MEDIA_URL }}{{ goods.gpic }}"></a>
<h4><a href="#">{{ goods.gtitle }}</a></h4>
<div class="prize">¥{{ goods.gprice }}</div>
</li>
{% endfor %}
</ul>
</div>
</div>
<div class="r_wrap fr clearfix">
<ul class="detail_tab clearfix">
<li class="active">商品介绍</li>
<li>评论</li>
</ul>
<div class="tab_content">
<dl>
<dt>商品详情:</dt>
<dd>{{ goods.gcontent|safe }}</dd>
</dl>
</div>
</div>
</div>
<div class="add_jump"></div>
<script type="text/javascript" src="/static/js/jquery-1.12.4.min.js"></script>
<script type="text/javascript">
$(document).ready(function(){
$(".buy_btn").click(function () {
num = parseInt($('.num_show').val());
$.get('/cart/add{{ goods.id }}_'+num+'/',function (data) {
$('#show_count').text(data.count);
});
location.href = "/cart/";
});
$('#add_cart').click(function() {
var $add_x = $('#add_cart').offset().top;
var $add_y = $('#add_cart').offset().left;
var $to_x = $('#show_count').offset().top;
var $to_y = $('#show_count').offset().left;
$(".add_jump").css({'left':$add_y+80,'top':$add_x+10,'display':'block'});
$('#add_cart').click(function() {
{# 先判断是否登录#}
if ($('.login_btn').text().indexOf('登录') >= 0) {
alert('请登陆后购买');
location.href('/user/login/');
return;
}
{# 购物车添加动画#}
$(".add_jump").stop().animate({
'left': $to_y + 7,
'top': $to_x + 7
},
"fast", function () {
$(".add_jump").fadeOut('fast', function () {
count = $('.num_show').val();
$('#show_count').html(count);
});
});
num = parseInt($('.num_show').val());
$.get('/cart/add{{ goods.id }}_'+num+'/',function (data) {
$('#show_count').text(data.count);
});
});
});
});
</script>
{% endblock center_content %}
ordinary_search.html:
{% extends 'base.html' %}
{% load staticfiles %}
{% block head %}
{% endblock %}
{% block center_body %}
<div class="navbar_con">
<div class="navbar clearfix">
<div class="subnav_con fl">
<h1>全部商品分类</h1>
<span></span>
<ul class="subnav">
<li><a href="/list1_1_1/" class="fruit">新鲜水果</a></li>
<li><a href="/list2_1_1/" class="seafood">海鲜水产</a></li>
<li><a href="#" class="meet">猪牛羊肉</a></li>
<li><a href="#" class="egg">禽类蛋品</a></li>
<li><a href="#" class="vegetables">新鲜蔬菜</a></li>
<li><a href="#" class="ice">速冻食品</a></li>
</ul>
</div>
<ul class="navlist fl">
<li><a href="{% url "goods:index" %}">首页</a></li>
<li class="interval">|</li>
<li><a href="">手机生鲜</a></li>
<li class="interval">|</li>
<li><a href="">抽奖</a></li>
</ul>
</div>
</div>
<script type="text/javascript">
if({{ search_status }}==0){
alert("您的查询结果为空,为您推荐以下商品");
}
</script>
<div class="breadcrumb">
全部分类
{# {{ title }}#}
{# {% if id|default:' ' != ' ' %}#}
> 商品详情
{# {% endif %}#}
</div>
<div class="main_wrap clearfix">
<ul class="goods_type_list clearfix">
{% for item in page %}
<li>
<a href="/{{ item.id }}/"><img src="{{ MEDIA_URL }}{{ item.gpic }}"></a>
<h4><a href="/{{ item.id }}/">{{ item.gtitle }}</a></h4>
<div class="operate">
<span class="prize">¥{{ item.gprice }}</span>
<span class="unit">{{ item.gunit }}</span>
<a href="/cart/add{{ item.id }}_1/" class="add_goods" title="加入购物车"></a>
{# <a href="javasript:;/" class="add_goods" title="加入购物车"></a>#}
</div>
</li>
{% endfor %}
</ul>
<div class="pagenation">
{# 判断是否是第一页#}
{% if page.has_previous %}
<a href="{% url "user:ordinary_search" %}?q={{ query }}&page={{ page.previous_page_number }}">上一页</a>
{% endif %}
{% for pindex in paginator.page_range %}
{% if pindex == page.number %}
<a href="#" class="active">{{ pindex }}</a>
{% else %}
<a href="{% url "user:ordinary_search" %}?q={{ query }}&page={{ pindex }}">{{ pindex }}</a>
{% endif %}
{% endfor %}
{# 是否又第二页#}
{% if page.has_next %}
<a href="{% url "user:ordinary_search" %}?q={{ query }}&page={{ page.next_page_number }}">下一页></a>
{% endif %}
</div>
</div>
{% endblock center_body %}
(2)创建user的HTML页面文件
login.html: