天天生鲜 - App设计
天天生鲜-思路数据库设计
天天生鲜-各个App
全文检索
天天生鲜-静态文件
一、项目目录
daily_fresh_demo - daily_fresh_demo - df_cart # 购物车功能 - df_goods # 商品功能 - df_order # 订单功能 - df_user # 用户功能(包括登录验证等相关功能) - static # 静态文件 - templates # 前段模板- whoosh_index # 全局索引文件 db.sqlite3 manage.py
注:这个电商网站是博主在接触Django之后做的第一个项目,还有很多地方需要改进。如果有需要项目相关视频资源的朋友可以博客园私信,或者评论区留言,博主会在看到的第一时间分享。
附github源码地址(包含静态文件):https://github.com/weilanhanf/daily_fresh_demo
daily_fresh_demo- daily_fresh_demo- settings.py- urls.py- wsgi.py- __init__.py # 这里使用Django自带的小型sqlite数据库,如果使用mysql就需要在这里添加相应的驱动
1、全局配置文件settings.py
![](/assets/blank.gif)
![](/assets/blank.gif)
1 import os 2 3 # Build paths inside the project like this: os.path.join(BASE_DIR, ...) 4 BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 5 6 7 # Quick-start development settings - unsuitable for production 8 # See https://docs.djangoproject.com/en/2.0/howto/deployment/checklist/ 9 10 # SECURITY WARNING: keep the secret key used in production secret! 11 SECRET_KEY = 'uey!i4x26n!$d-73cs%blri)09#xfud_e361ne2h(#s27)l!' 12 13 # SECURITY WARNING: don't run with debug turned on in production! 14 DEBUG = True 15 16 ALLOWED_HOSTS = [] 17 18 19 # Application definition 20 21 INSTALLED_APPS = [ 22 'django.contrib.admin', 23 'django.contrib.auth', 24 'django.contrib.contenttypes', 25 'django.contrib.sessions', 26 'django.contrib.messages', 27 'django.contrib.staticfiles', 28 'df_user', 29 'df_goods', 30 'df_cart', 31 'df_order', 32 'tinymce',#使用富文本编辑框要在settings文件中安装 33 'haystack',#全文检索 34 ] 35 36 MIDDLEWARE = [ 37 'django.middleware.security.SecurityMiddleware', 38 'django.contrib.sessions.middleware.SessionMiddleware', 39 'django.middleware.common.CommonMiddleware', 40 'django.middleware.csrf.CsrfViewMiddleware', 41 'django.contrib.auth.middleware.AuthenticationMiddleware', 42 'django.contrib.messages.middleware.MessageMiddleware', 43 'django.middleware.clickjacking.XFrameOptionsMiddleware', 44 ] 45 46 ROOT_URLCONF = 'daily_fresh_demo.urls' 47 48 TEMPLATES = [ 49 { 50 'BACKEND': 'django.template.backends.django.DjangoTemplates', 51 'DIRS': [os.path.join(BASE_DIR, 'templates')] 52 , 53 'APP_DIRS': True, 54 'OPTIONS': { 55 'context_processors': [ 56 'django.template.context_processors.debug', 57 'django.template.context_processors.request', 58 'django.contrib.auth.context_processors.auth', 59 'django.contrib.messages.context_processors.messages', 60 ], 61 }, 62 }, 63 ] 64 65 WSGI_APPLICATION = 'daily_fresh_demo.wsgi.application' 66 67 68 # Database 69 # https://docs.djangoproject.com/en/2.0/ref/settings/#databases 70 71 DATABASES = { 72 'default': { 73 'ENGINE': 'django.db.backends.sqlite3', 74 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 75 }, 76 'OPTIONS':{ 77 'TIMEOUT': 20, 78 } 79 } 80 81 82 # Password validation 83 # https://docs.djangoproject.com/en/2.0/ref/settings/#auth-password-validators 84 85 AUTH_PASSWORD_VALIDATORS = [ 86 { 87 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 88 }, 89 { 90 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 91 }, 92 { 93 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 94 }, 95 { 96 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 97 }, 98 ] 99 100 101 # Internationalization 102 # https://docs.djangoproject.com/en/2.0/topics/i18n/ 103 104 LANGUAGE_CODE = 'en-us' 105 106 TIME_ZONE = 'UTC' 107 108 USE_I18N = True 109 110 USE_L10N = True 111 112 USE_TZ = True 113 114 115 # Static files (CSS, JavaScript, Images) 116 # https://docs.djangoproject.com/en/2.0/howto/static-files/ 117 118 STATIC_URL = '/static/' 119 STATICFILES_DIRS = [ 120 os.path.join(BASE_DIR, 'static'), 121 ] 122 123 #开发阶段上传文件目录 124 MEDIA_ROOT = os.path.join(BASE_DIR, 'static') 125 #部署后的上传文件目录 126 # MEDIA_ROOT = 'var/www/daily_fresh_demo/static' 127 128 129 #富文本编辑框的使用配置 130 TINYMCE_DEFAULT_CONFIG = { 131 'theme': 'advanced', 132 'width': 600, 133 'height': 400, 134 } 135 136 HAYSTACK_CONNECTIONS = { 137 'default':{ 138 #使用whoosh引擎 139 'ENGINE':'haystack.backends.whoosh_cn_backend.WhooshEngine', 140 #添加索引文件路径 141 'PATH':os.path.join(BASE_DIR, 'whoosh_index'), 142 } 143 } 144 #当修改删除数据时,自动生成索引 145 HAYSTACK_SIGNAL_PROCESSOR ='haystack.signals.RealtimeSignalProcessor' 146 # HAYSTACK_DEFAULT_OPERATOR = 'OR' 147 HAYSTACK_SEARCH_RESULTS_PER_PAGE = 18#每一页显示多少数据
View Code
2、路由分发urls.py
![](/assets/blank.gif)
![](/assets/blank.gif)
from django.contrib import admin from django.urls import path from django.conf.urls import url, includeurlpatterns = [path('admin/', admin.site.urls),url(r'^', include('df_goods.urls',namespace='goods')),url(r'^user/', include('df_user.urls', namespace='user')),url(r'^goods/', include('df_goods.urls')),url(r'^cart/',include('df_cart.urls', namespace='cart')),url(r'^order/',include('df_order.urls', namespace='order')),url(r'^search/', include('haystack.urls')),#全文检索url(r'^tinymce/', include('tinymce.urls')),#使用富文本编辑框配置confurl ]
View Code
二、用户相关功能模块
app目录如下
df_user- migrations # 迁移文件目录- admin.py- apps.py- models.py- test.py- urls.py- user_docorator.py # 这里使用装饰器做用户身份认证- views.py- __init__.py
1、apps.py
![](/assets/blank.gif)
![](/assets/blank.gif)
from django.apps import AppConfigclass DfUserConfig(AppConfig):name = 'df_user'
View Code
2、models.py
![](/assets/blank.gif)
![](/assets/blank.gif)
from django.db import models # Create your models here.class UserInfo(models.Model):uname=models.CharField(max_length=20)upwd=models.CharField(max_length=40)uemail=models.CharField(max_length=30)ushou=models.CharField(max_length=20,default="")uaddress=models.CharField(max_length=100,default="")uyoubian=models.CharField(max_length=6,default="")uphone=models.CharField(max_length=11,default="")# default,blank是python层面的约束,不影响数据库表结构,修改时不需要迁移 python manage.py makemigrationsclass GoodsBrowser(models.Model):user=models.ForeignKey('UserInfo', on_delete=models.CASCADE)good=models.ForeignKey('df_goods.GoodsInfo', on_delete=models.CASCADE)
View Code
3、urls.py
![](/assets/blank.gif)
![](/assets/blank.gif)
#!/user/bin/env python # -*- coding: utf-8 -*- from django.conf.urls import url from . import viewsapp_name = 'df_user'urlpatterns = [url(r'^register/$', views.register),url(r'^register_handle/$', views.register_handle),url(r'^register_exist/$', views.register_exist),url(r'^login/$', views.login),url(r'^login_handle/$', views.login_handle),url(r'^info/$', views.info),url(r'^order/(\d+)$', views.order),url(r'^site/$', views.site),# url(r'^place_order/$', views.place_order),url(r'^logout/$', views.logout) ]
View Code
4、view.py
![](/assets/blank.gif)
![](/assets/blank.gif)
from django.shortcuts import render, redirect, HttpResponseRedirect, HttpResponse from django.http import JsonResponse from .models import UserInfo from df_goods.models import GoodsInfo from df_user.models import GoodsBrowser from df_order.models import * from hashlib import sha1 from . import user_decorator from django.core.paginator import Paginator,Pagedef register(request):context={'title':'用户注册',}return render(request, 'df_user/register.html', context)def register_handle(request):#接受用户输入post = request.POSTprint(request.method)uname=post.get('user_name')upwd=post.get('pwd')upwd2=post.get('cpwd')uemail=post.get('email')#判断两次密码一致性if upwd != upwd2:return redirect('/user/register/')#密码加密s1=sha1()s1.update(upwd.encode('utf8'))upwd3=s1.hexdigest()# sha = hashlib.sha1(upwd.encode('utf8'))# sha.hexdigest()#创建对象user=UserInfo()user.uname=unameuser.upwd=upwd3user.uemail=uemailuser.save()print(uname, upwd3,uemail)#注册成功context = {'title': '用户登陆','uname': uname,}# return redirect('/user/login/')return render(request, 'df_user/login.html', context)def register_exist(request):uname=request.GET.get('uname')count=UserInfo.objects.filter(uname=uname).count()if count == 0:print('当前用户名可用')return JsonResponse({'count':count})# @user_decorator.request_detail def login(request):print(request.get_full_path(), 'request.get_full_path')uname=request.COOKIES.get('uname', '')context={'title': '用户登陆','error_name':0,'error_pwd':0,'uname':uname,}return render(request, 'df_user/login.html', context)def login_handle(request):#没有利用ajax提交表单#接受请求信息post = request.POSTuname = post.get('username')upwd = post.get('pwd')jizhu = post.get('jizhu', 0)#根据用户名查询对象# print(uname, upwd, jizhu, request.method)users = UserInfo.objects.filter(uname=uname)#[]print(uname,len(users), users)#判断如果未查到则用户名错误,如果查到则判断密码是否正确,正确则转到用户中心if len(users)==1:s1 = sha1()s1.update(upwd.encode('utf8'))if s1.hexdigest()==users[0].upwd:print("验证成功")# request.COOKIES['url'] = '/8/'url = request.COOKIES.get('url','/')print(url)red = HttpResponseRedirect(url)#继承与HttpResponse 在跳转的同时 设置一个cookie值#是否勾选记住用户名,设置cookieif jizhu!=0:red.set_cookie('uname', uname)# print('设置cookie', request.COOKIES['uname'])else:red.set_cookie('uname', '',max_age=-1)#设置过期cookie时间,立刻过期request.session['user_id'] = users[0].idrequest.session['user_name'] = unamereturn redelse:context = {'title':'用户名登陆','error_name': 0,'error_pwd':1,'uname':uname,'upwd':upwd,}# print('密码错误')return render(request, 'df_user/login.html', context)else:context = {'title': '用户名登陆','error_name': 1,'error_pwd': 0,'uname': uname,'upwd': upwd,}print('不存在当前用户')return render(request, 'df_user/login.html', context)def logout(request):request.session.flush()#清空当前用户所有sessionreturn redirect('/')@user_decorator.login def info(request):username =request.session.get('user_name')# print(username)user = UserInfo.objects.filter(uname = username).first()# user = UserInfo.objects.get(id=request.session['user_id'])# print(request.session['user_name'])#列表形式最近浏览# goods_ids = request.COOKIES.get('goods_ids', '')# print('cookies', goods_ids)#在cookie中goods_id以{ 'gooids':'1,5,6,7,8,9'}形式存入# goods_ids1 = goods_ids.split(',')#拆分为列表# print('最近浏览商品序号',goods_ids1)# goods_list1 = GoodsInfo.objects.filter(id__in=goods_ids1)#会破坏浏览商品的先后顺序# if goods_ids1[0] != '' :# goods_list = [GoodsInfo.objects.get(id=int(goods_id)) for goods_id in goods_ids1]# # for goods_id in goods_ids1:# # goods_list.append(GoodsInfo.objects.get(id=int(goods_id)))#pk与id区别# # 每次只查询一个商品并放入列表的最后,保证了浏览商品的顺序# explain = '最近浏览'# else:# goods_list = []# explain = '无最近浏览'# 最近浏览计入第三张那个表goods_ids = GoodsBrowser.objects.filter(user_id=request.session['user_id'])# print(goods_ids)goods_ids1 = [good_browser.good_id for good_browser in goods_ids]# print(goods_ids1)# goods_ids2 = []# for good_id in goods_ids1:# if good_id not in goods_ids2:# goods_ids2.append(good_id)# print(goods_ids2)if len(goods_ids1) != 0:goods_list = [GoodsInfo.objects.get(id=goods_id) for goods_id in goods_ids1]goods_list.reverse()# print(goods_list)explain = '最近浏览'else:goods_list = []explain = '无最近浏览'context={'title':'用户中心','page_name': 1,'user_phone':user.uphone,'user_address':user.uaddress,'user_name':request.session['user_name'],'goods_list': goods_list,'explain': explain,}# print(user.uname, user.uaddress, user.uphone)return render(request, 'df_user/user_center_info.html', context)@user_decorator.login def order(request, index):user_id = request.session['user_id']orders_list = OrderInfo.objects.filter(user_id=int(user_id)).order_by('-odate')# print(len(orders_list))# print(orders_list)paginator = Paginator(orders_list,2)page = paginator.page(int(index))context={'paginator': paginator,'page':page,# 'orders_list':orders_list,'title':"用户中心",'page_name':1,}return render(request, 'df_user/user_center_order.html', context)@user_decorator.login def site(request):user = UserInfo.objects.get(id=request.session['user_id'])# print(user, type(user), user.uphone,user.uaddress)if request.method=="POST":post = request.POSTuser.ushou = post.get('ushou')user.uaddress = post.get('uaddress')user.uyoubian = post.get('uyoubian')user.uphone = post.get('uphone')user.save()context = {'page_name': 1,'title': '用户中心','user':user,}return render(request, 'df_user/user_center_site.html', context)
View Code
5、user_decorator.py
对用户进行身份认证,如用户进入个人中心的时候需要验证,购买商品也需要身份验证
![](/assets/blank.gif)
![](/assets/blank.gif)
#!/user/bin/env python # -*- coding: utf-8 -*- from django.http import HttpResponseRedirect import re#如果未登录则转到登陆页面 def login(func):def login_fun(request, *args, **kwargs):if 'user_id' in request.session:return func(request, *args, **kwargs)else:red = HttpResponseRedirect('/user/login/')red.set_cookie('url', request.get_full_path())print(request.get_full_path(), 'user_decorator')#保证用户再登陆验证之后仍点击到希望的页面return redreturn login_fun""" http://127.0.0.1:8000/200/?type=10 request.path :表示当前路径,为/200/ request.get_full_path():表示完整路径,为/200/?type=10 """
View Code
三、商品相关功能模块
app目录如下
df_goods- migrations- admin.py- apps.py- models.py- search_indexes.py # 搜索商品功能- tests.py- urls.py- views.py- __init__.py
1、app.py
![](/assets/blank.gif)
![](/assets/blank.gif)
from django.apps import AppConfigclass DfGoodsConfig(AppConfig):name = 'df_goods'
View Code
2、models.py
![](/assets/blank.gif)
![](/assets/blank.gif)
from django.db import models from tinymce.models import HTMLField#使用富文本编辑框要在settings文件中安装 #将一对多的关系维护在GoodsInfo中维护,另外商品信息与分类信息都属于重要信息需要使用逻辑删除# Create your models here. class TypeInfo(models.Model):#商品分类信息 水果 海鲜等isDelete = models.BooleanField(default=False)#逻辑删除ttitle = models.CharField(max_length=20)def __str__(self):#这里定义在admin中要显示的内容# return self.ttitle.encode('utf-8')return self.ttitleclass GoodsInfo(models.Model):#具体商品信息isDelete = models.BooleanField(default=False)#逻辑删除gtitle = models.CharField(max_length=20)#商品的名称gpic = models.ImageField(upload_to='df_goods')#关联图片目录gprice = models.DecimalField(max_digits=5, decimal_places=2)#商品价格小数位为两位,整数位为3位gunit = models.CharField(max_length=20, default='500g')#商品单位kg或者个数gclick = models.IntegerField()#商品点击量gjianjie = models.CharField(max_length=200)#商品简介gkucun = models.IntegerField()#商品库存gcontent = HTMLField()#商品介绍gtype = models.ForeignKey(TypeInfo, on_delete=models.CASCADE)#外键关联TypeInfo表# gadv = models.BooleanField(default=False)#商品是否推荐def __str__(self):# return self.gtitle.encode('utf-8')return self.gtitle# python3中 __str__ 不能接收bytes类型的数据,这和python2/3的编解码方式是有关系的。
View Code
3、urls.py
![](/assets/blank.gif)
![](/assets/blank.gif)
#!/user/bin/env python # -*- coding: utf-8 -*-from django.conf.urls import url from . import views from .views import *app_name = 'df_goods'urlpatterns = [url('^$', views.index),url('^list(\d+)_(\d+)_(\d+)/$', views.list),url('^(\d+)/$', views.detail),url(r'^search/', MySearchView()),#全文检索url(r'^cookieTest/', views.cookieTest)]
View Code
4、view.py
![](/assets/blank.gif)
![](/assets/blank.gif)
from django.shortcuts import render, HttpResponse from .models import * from django.core.paginator import Page, Paginator from df_cart.models import CartInfo from df_user.models import GoodsBrowser from haystack.views import SearchView# Create your views here. def index(request):#查询各个分类的最新4条,最热4条数据typelist = TypeInfo.objects.all()print(len(typelist), 'asdf')# 连表操作(了不起的双下划线)利用双下划线和 _set将表之间的操作连接起来type0 = typelist[0].goodsinfo_set.order_by('-id')[0:4]#按照最新上传的水果显示type01 = typelist[0].goodsinfo_set.order_by('-gclick')[0:4]#按照用户点击量上传type1 = typelist[1].goodsinfo_set.order_by('-id')[0:4]type11 = typelist[1].goodsinfo_set.order_by('-gclick')[0:4]type2 = typelist[2].goodsinfo_set.order_by('-id')[0:4]type21 = typelist[2].goodsinfo_set.order_by('-gclick')[0:4]type3 = typelist[3].goodsinfo_set.order_by('-id')[0:4]type31 = typelist[3].goodsinfo_set.order_by('-gclick')[0:4]type4 = typelist[4].goodsinfo_set.order_by('-id')[0:4]type41 = typelist[4].goodsinfo_set.order_by('-gclick')[0:4]type5 = typelist[5].goodsinfo_set.order_by('-id')[0:4]type51 = typelist[5].goodsinfo_set.order_by('-gclick')[0:4]#判断是否存在登录状态try:user_id = request.session['user_id']cart_count = CartInfo.objects.filter(user_id=int(user_id)).countexcept:cart_count = 0context = {'title': '首页','cart_count': cart_count,'guest_cart':1,'type0':type0, 'type01':type01,'type1':type1, 'type11':type11,'type2':type2, 'type21':type21,'type3':type3, 'type31':type31,'type4':type4, 'type41':type41,'type5':type5, 'type51':type51,}"""context = {'guest_cart':1,'title': '首页'}#获取最新的4个商品hot = GoodsInfo.objects.all().order_by('-gclick')[0:4]context.setdefault('hot', hot)#*******获取各分类下的点击商品*******#首先获取分类typelist = TypeInfo.objects.all()for i in range(len(typelist)):#获取type对象type = typelist[i]#根据type对象获取商品列表#通过外键关联获取商品#获取对应列表中的通过id倒序排列的前四个goods1 = type.goodinfo_set.order_by('-id')[0:4]goods2 = type.goodinfo_set.order_by('-gclick')[0:4]key1 = 'type' + str(i) # 根据id 倒叙排列key2 = 'type' + str(i) + str(i) # 根据点击量倒序排列context.setdefault(key1, goods1)context.setdefault(key2, goods2)print(context)"""# print(type0, type01)# for i in type0:# print(i.gpic)return render(request, 'df_goods/index.html', context)def list(request, tid, pindex, sort):#tid:商品种类信息 pindex:商品页码 sort:商品显示分类方式typeinfo = TypeInfo.objects.get(pk=int(tid))#根据主键查找当前的商品分类 海鲜或者水果news = typeinfo.goodsinfo_set.order_by('-id')[0:2]#list.html左侧最新商品推荐goods_list = []# list中间栏商品显示方式if sort == '1':#默认最新goods_list = GoodsInfo.objects.filter(gtype_id=int(tid)).order_by('-id')elif sort == '2':#按照价格goods_list = GoodsInfo.objects.filter(gtype_id=int(tid)).order_by('-gprice')elif sort == '3':#按照人气点击量goods_list = GoodsInfo.objects.filter(gtype_id=int(tid)).order_by('-gclick')#创建Paginator一个分页对象paginator = Paginator(goods_list, 4)#返回Page对象,包含商品信息page = paginator.page(int(pindex))context = {'title': '商品列表','guest_cart': 1,'page': page,'paginator': paginator,'typeinfo': typeinfo,'sort': sort, # 排序方式'news': news,}return render(request,'df_goods/list.html',context)def detail(request, id):goods = GoodsInfo.objects.get(pk=int(id))goods.gclick = goods.gclick+1#商品点击量 goods.save()news = goods.gtype.goodsinfo_set.order_by('-id')[0:2]context = {'title': goods.gtype.ttitle,'guest_cart': 1,'goods': goods,'news': news,'id':id,}response=render(request, 'df_goods/detail.html', context)#使用列表 记录最近浏览, 在用户中心使用# goods_ids = request.COOKIES.get('goods_ids', '')#在cookie中建立一个商品id的对应最近浏览的商品# goods_id = '%d' %goods.id#将url转化为整型# if goods_ids != '':#判断是否存在浏览记录,如果存在则继续判断,# goods_ids1 = goods_ids.split(',')#拆分为列表# if goods_ids1.count(goods_id)>=1:#如果商品已经存在记录则删除旧纪录# goods_ids1.remove(goods_id)# goods_ids1.insert(0, goods_id)#将商品插入到第一页# if len(goods_ids1)>=6:#每页只显示五个最近浏览的商品# del goods_ids1[5]# goods_ids = ','.join(goods_ids1)#将商品id拼接为字符串# else:# goods_ids = goods_id#显然第一次查看detail页面时为空,则直接添加# response.set_cookie('goods_ids', goods_ids)#写入cookie# 将用户最近浏览商品记录进第三张表'''1,判断是否有用户登录, 如果没有直接结束2,判断在当前浏览表中是否存在这个用户,不存在则创建一个用户浏览记录,并且不用判断是否浏览过若存在则判断当前用户是否存在一个浏览过当前商品3,不管有没有浏览过当前商品都要先创建一个商品记录放入表中如果浏览过则删除前期浏览的商品若没有则不用删除4,如果商品记录为五条,则将最后的一条删除'''try:user_id = request.session['user_id']# user_list = GoodsBrowser.objects.filter(user_id=int(user_id))goods_browser = GoodsBrowser()goods_browser.user_id = int(user_id)goods_browser.good_id = int(id)goods_browser.save()old_user_list = GoodsBrowser.objects.filter(user_id=int(user_id), good_id=int(id))if len(old_user_list) > 1:GoodsBrowser.objects.filter(good_id=int(id)).first().delete()if len(GoodsBrowser.objects.filter(user_id=int(user_id))) > 5:GoodsBrowser.objects.filter(user_id=int(user_id)).first().delete()except:passreturn responsedef cart_count(request):if request.session.has_key('user_id'):return CartInfo.objects.filter(user_id=request.session['user_id']).countelse:return 0class MySearchView(SearchView):def extra_context(self):context = super(MySearchView, self).extra_context()context['title'] = '搜索'context['guest_cart'] = 1context['cart_count'] = cart_count(self.request)return contextdef cookieTest(request):response = HttpResponse()if request.COOKIES.get('binggan'):#判断是否有此cookiecookie = request.COOKIESresponse.write(cookie['binggan'])#如果有则写入return response
View Code
5、admin.py
![](/assets/blank.gif)
![](/assets/blank.gif)
from django.contrib import admin from .models import TypeInfo,GoodsInfo# Register your models here. #注册模型类 普通方法 class TypeInfoAdmin(admin.ModelAdmin):list_display = ['id', 'ttitle']# class GoodsInfoAdmin(admin.ModelAdmin): # list_per_page = 15 # list_display = ['id', 'gtitle', 'gunit','gclick', 'gprice','gpic','gjianjie','gkucun','gcontent','gjianjie'] admin.site.register(TypeInfo, TypeInfoAdmin) # admin.site.register(GoodsInfo, GoodsInfoAdmin)# 装饰器方法 @admin.register(GoodsInfo) class GoodsInfoAdmin(admin.ModelAdmin):list_per_page = 15list_display = ['id', 'gtitle', 'gunit','gclick', 'gprice','gpic','gjianjie','gkucun','gcontent','gjianjie']
View Code
6、search_indexes.py
![](/assets/blank.gif)
![](/assets/blank.gif)
#!/user/bin/env python # -*- coding: utf-8 -*- from haystack import indexes from .models import *#制定对于某个类的某些数据建立索引 class GoodsInfoIndex(indexes.SearchIndex, indexes.Indexable):text = indexes.CharField(document=True, use_template=True)def get_model(self):#对GoodsInfo模型类进行索引return GoodsInfodef index_queryset(self, using=None):return self.get_model().objects.all()
View Code
全局索引提供一个大的全局搜索功能,也可以通过Django 中的ORM的Q查询实现
这里请参考全局索引:https://www.cnblogs.com/welan/p/9231430.html
四、订单相关功能
app目录如下
df_order- migrations- admin.py- apps.py- models.py- tests.py- urls.py- views.py- __init__.py
1、app.py
![](/assets/blank.gif)
![](/assets/blank.gif)
from django.apps import AppConfigclass DfOrderConfig(AppConfig):name = 'df_order'
View Code
2、models.py
![](/assets/blank.gif)
![](/assets/blank.gif)
from django.db import models# Create your models here. class OrderInfo(models.Model):#大订单oid = models.CharField(max_length=20, primary_key=True)#订单号user = models.ForeignKey('df_user.UserInfo', on_delete=models.CASCADE)#确定哪个用户的订单odate = models.DateTimeField(auto_now=True)oIsPay = models.BooleanField(default=False)#当前订单是否支付,默认为否ototal = models.DecimalField(max_digits=8, decimal_places=2)oaddress = models.CharField(max_length=150)#虽然订单总价可以由多个商品的单价以及数量求得,但是由于用户订单的总价的大量使用,忽略total的冗余度#无法实现:真实支付,物流信息class OrderDetailInfo(models.Model):#大订单中的具体某一商品订单goods = models.ForeignKey('df_goods.GoodsInfo',on_delete=models.CASCADE)#关联商品信息order = models.ForeignKey('OrderInfo', on_delete=models.CASCADE)#关联大订单,确定属于某一个大订单中price = models.DecimalField(max_digits=6, decimal_places=2)#某一类商品订单的价格最高达9999.99count = models.IntegerField()
View Code
3、urls.py
![](/assets/blank.gif)
![](/assets/blank.gif)
#!/user/bin/env python # -*- coding: utf-8 -*- from django.conf.urls import url from . import viewsapp_name = 'df_order'urlpatterns = [url(r'^$', views.order),url(r'^push/$', views.order_handle), ]
View Code
4、view.py
![](/assets/blank.gif)
![](/assets/blank.gif)
from django.shortcuts import render,HttpResponse,redirect from df_user import user_decorator from django.db import transaction from django.http import JsonResponse from datetime import datetime from decimal import Decimal from .models import * from df_cart.models import CartInfo from df_user.models import UserInfo # Create your views here. @user_decorator.login def order(request):uid = request.session['user_id']user = UserInfo.objects.get(id=uid)cart_ids = request.GET.getlist('cart_id')carts = []total_price = 0for goods_id in cart_ids:cart = CartInfo.objects.get(id = goods_id)carts.append(cart)total_price = total_price + float(cart.count) * float(cart.goods.gprice)total_price = float('%0.2f'%total_price)trans_cost = 10#运费total_trans_price = trans_cost + total_price# print(total_trans_price)# import datetime订单提交时间# value = datetime.datetime.now()# print(value)context = {'title': '提交订单','page_name': 1,'user':user,'carts': carts,'total_price':float('%0.2f'%total_price),'trans_cost': trans_cost,'total_trans_price': total_trans_price,# 'value':value }return render(request, 'df_order/place_order.html', context)''' 事务提交: 这些步骤中,任何一环节一旦出错则全部退回1 1. 创建订单对象 2. 判断商品库存是否充足 3. 创建 订单 详情 ,多个 4,修改商品库存 5. 删除购物车 '''@user_decorator.login @transaction.atomic()#事务 def order_handle(request):tran_id = transaction.savepoint()#保存事务发生点cart_ids = request.POST.get('cart_ids')#用户提交的订单购物车,此时cart_ids为字符串,例如'1,2,3,'# print('订单购物车', cart_ids)user_id = request.session['user_id']#获取当前用户的id# print('当前用户', user_id)try:order_info = OrderInfo()#创建一个订单对象now = datetime.now()order_info.oid = '%s%d'%(now.strftime('%Y%m%d%H%M%S'), user_id)#订单号为订单提交时间和用户id的拼接order_info.odate = now#订单时间# print('订单时间', now)order_info.user_id = int(user_id)#订单的用户idorder_info.ototal = Decimal(request.POST.get('total'))#从前端获取的订单总价# print('总价', order_info.ototal)order_info.save()#保存订单for cart_id in cart_ids.split(','):#逐个对用户提交订单中的每类商品即每一个小购物车cart = CartInfo.objects.get(pk = cart_id)#从CartInfo表中获取小购物车对象order_detail = OrderDetailInfo()#大订单中的每一个小商品订单order_detail.order = order_info#外键关联,小订单与大订单绑定goods = cart.goods#具体商品if cart.count <= goods.gkucun:#判断库存是否满足订单,如果满足,修改数据库goods.gkucun = goods.gkucun - cart.countgoods.save()# print(goods.gtitle,'库存', goods.gkucun)order_detail.goods = goodsorder_detail.price = goods.gprice# print('小订单价格',order_detail.price)order_detail.count = cart.count# print('小订单商品数量', order_detail.count) order_detail.save()cart.delete()#并删除当前购物车else:#否则,则事务回滚,订单取消 transaction.savepoint_rollback(tran_id)return HttpResponse('库存不足')# return redirect('/cart/')data = {'ok': 1,}transaction.savepoint_commit(tran_id)except Exception as e:print("%s"%e)print('未完成订单提交')transaction.savepoint_rollback(tran_id)#事务任何一个环节出错,则事务全部取消# return HttpResponse('订单提交成功')return JsonResponse(data)@user_decorator.login def pay(request):pass
View Code
五、购物车相关模块功能
app目录如下
df_cart- migrations- admin.py- apps.py- models.py- test.py- urls.py- views.py- __init__.py
1、app.py
![](/assets/blank.gif)
![](/assets/blank.gif)
from django.apps import AppConfigclass DfCartConfig(AppConfig):name = 'df_cart'
View Code
2、models.py
![](/assets/blank.gif)
![](/assets/blank.gif)
from django.db import models# Create your models here. #当一对多关系时例如生鲜分类对生鲜具体商品, 将关系维护在多的那张表中,即在具体商品表中维护 #当多对多关系,则新建一张表,在再第三张表中维护表关系 #用户表与商品表则将关系维护在购物车表中#在购物车的逻辑删除与物理删除 选择物理删除, #购物车中的商品不属于重要的信息,可以直接删除class CartInfo(models.Model):user = models.ForeignKey('df_user.UserInfo', on_delete=models.CASCADE)goods = models.ForeignKey('df_goods.GoodsInfo', on_delete=models.CASCADE)#在同级工程目录下引用外键count = models.IntegerField()#记录用户买个多少单位的商品
View Code
3、urls.py
![](/assets/blank.gif)
![](/assets/blank.gif)
#!/user/bin/env python # -*- coding: utf-8 -*- from django.conf.urls import url from . import viewsapp_name = 'df_cart'urlpatterns = [url(r'^$', views.cart),url(r'^add(\d+)_(\d+)/$', views.add),url(r'^edit(\d+)_(\d+)/$', views.edit),url(r'^delete(\d+)/$', views.delete), ]
View Code
4、view.py
![](/assets/blank.gif)
![](/assets/blank.gif)
from django.shortcuts import render,redirect from django.http import JsonResponse from df_user import user_decorator from .models import * # Create your views here. @user_decorator.login def cart(request):uid = request.session['user_id']carts = CartInfo.objects.filter(user_id=uid)context = {'title':'购物车','page_name':1,'carts':carts}if request.is_ajax():count = CartInfo.objects.filter(user_id=request.session['user_id']).count()#求当前用户购买了几件商品return JsonResponse({'count': count})else:return render(request, 'df_cart/cart.html', context)@user_decorator.login def add(request, gid, count):uid = request.session['user_id']gid = int(gid)count = int(count)print(gid, count)#查询购物车中是否已经有此商品,如果有则数量增加,如果没有则新增carts = CartInfo.objects.filter(user_id=uid, goods_id=gid)if len(carts)>=1:cart = carts[0]cart.count = cart.count + countelse:cart = CartInfo()cart.user_id = uidcart.goods_id = gidcart.count = countcart.save()#如果是ajax提交则直接返回json,否则转向购物车if request.is_ajax():count = CartInfo.objects.filter(user_id=request.session['user_id']).count()#求当前用户购买了几件商品return JsonResponse({'count': count})else:return redirect('/cart/')@user_decorator.login def edit(request, cart_id, count):try:cart = CartInfo.objects.get(pk=int(cart_id))cart.count=int(count)cart.save()data = {'count':0}except Exception as e:data = {'count':count}return JsonResponse(data)@user_decorator.login def delete(request,cart_id):print(cart_id)try:cart = CartInfo.objects.get(pk=int(cart_id))cart.delete()data={'ok':1}print('数据库修改成功')except Exception as e:data = {'ok':0}return JsonResponse(data)
View Code
转载于:https://www.cnblogs.com/welan/p/9900944.html
天天生鲜 - App设计相关推荐
- HTML5期末大作业:生鲜水果蔬菜商城网站设计——天天生鲜水果蔬菜商城(10页) web前端设计与开发期末作品/期末大作业
HTML5期末大作业:生鲜水果蔬菜商城网站设计--天天生鲜水果蔬菜商城(10页) web前端设计与开发期末作品/期末大作业 常见网页设计作业题材有 个人. 美食. 公司. 学校. 旅游. 电商. 宠物 ...
- HTML+CSS+JS 生鲜水果蔬菜商城网站设计——天天生鲜水果蔬菜商城(10页) web前端设计与开发期末作品_期末大作业
HTML5期末大作业:生鲜水果蔬菜商城网站设计--天天生鲜水果蔬菜商城(10页) web前端设计与开发期末作品/期末大作业 常见网页设计作业题材有 个人. 美食. 公司. 学校. 旅游. 电商. 宠物 ...
- HTML5期末大作业:生鲜水果蔬菜商城网站设计——天天生鲜水果蔬菜商城(10页) html网页设计期末大作业_网页设计平时作业
HTML5期末大作业:生鲜水果蔬菜商城网站设计--天天生鲜水果蔬菜商城(10页) web前端设计与开发期末作品/期末大作业 常见网页设计作业题材有 个人. 美食. 公司. 学校. 旅游. 电商. 宠物 ...
- 天天生鲜Django项目①
文章目录 1.需求分析 1.1 用户模块 1.2 商品模块 1.3 购物车模块 1.4 订单相关 2. 项目架构概览 2.1 页面图 2.2 功能图 3. 数据库设计 生成迁移文件 3. 用户注册 3 ...
- 天天生鲜项目开发笔记
天天生鲜项目开发笔记 说在前面的话 大学四年,忙忙碌碌,什么都学了,又好像什么都没学,总之要毕业了,毕设题目是"生鲜配送系统",B站上找到了一个天天生鲜的项目开发教程,之后文章记录 ...
- 网站框架搭建——基于Django框架的天天生鲜电商网站项目系列博客(二)
系列文章目录 需求分析--基于Django框架的天天生鲜电商网站项目系列博客(一) 网站框架搭建--基于Django框架的天天生鲜电商网站项目系列博客(二) 用户注册模块--基于Django框架的天天 ...
- GO语言开发天天生鲜项目第三天 用户模块开发
项目分析 一.项目架构 二.数据库表设计 用户模块 ##一.用户注册 用户通过我们的网站购买商品前,必须要登录.如果,该用户在我们的网站上没有账号,那么必须进行注册.下面我们看一下注册的具体实现过程( ...
- 【Django 天天生鲜项目05】订单(Mysql事务、并发处理、支付宝支付、评论)
本部分涉及订单的生成.并发处理.支付.评论等 关键:MySQL事务.并发处理的悲观锁/乐观锁.支付宝SDK 的使用...... 仅作为个人笔记! 目录 2.创建订单 3.订单生成 3.1. MySQL ...
- Vue+nodejs+express天天生鲜超市购物商城平台
系统由两个大模块组成:前台用户界面的实现,后台管理员对网站销售系统的管理.前台用户界面主要是对天天生鲜超市销售系统功能与信息的展示,所以将内容细分为:生鲜产品展示方面,生鲜产品分类方面,生鲜产品的详细 ...
最新文章
- 10285 - Longest Run on a Snowboard
- matplotlb.finance导包报错——ModuleNotFoundError No module named mpl finance
- C#中关于静态与非静态的一个疑问
- kubernetes 中 label的作用_Kubernetes生产环境的16条建议
- 通过 GitExtensions 来使用 Git 子模块功能
- linux 嵌入式 快照_Linux 系统之Systemd
- qtabwidget放大_Qt自定义弹窗屏蔽父窗口(QWidget设置setWindowModality(Qt::ApplicationModal);以后再show)...
- 面试官爱问的10大经典排序算法,20+张图来搞定
- 采用Spring管理Bean和依赖注入
- vs2019怎么调整字体大小_每年至少十万考生涂错答题卡,是时候讨论一下最新版答题卡怎么用了...
- Oracle设置主键自增
- 代码该怎么写——设计原则
- 国产单路AHDRX芯片XS9950,替代TP9950
- 服务器 网站 未备案,域名解析到未备案服务器
- html span 字体位置,span内文字居中css布局方法_让span内容居中
- 期末GIS人的《计量地理学》突击复习有救了
- 用editplus删除csv文件中的软回车
- Linux搭建泰拉瑞亚(原版/模组/插件)服务器之1.4模组服务器
- AI Gossip | 八卦人工智能的前世今生
- MBA中国网关注:打造最佳团队的5大秘诀