天天生鲜 - 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

  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#每一页显示多少数据

2、路由分发urls.py

from django.contrib import admin
from django.urls import path
from django.conf.urls import url, include

urlpatterns = [
    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
]

二、用户相关功能模块

app目录如下

df_user
    - migrations # 迁移文件目录
    - admin.py
    - apps.py
    - models.py
    - test.py
    - urls.py
    - user_docorator.py  # 这里使用装饰器做用户身份认证
    - views.py
    - __init__.py

1、apps.py

from django.apps import AppConfig

class DfUserConfig(AppConfig):
    name = ‘df_user‘

2、models.py

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 makemigrations

class GoodsBrowser(models.Model):
    user=models.ForeignKey(‘UserInfo‘, on_delete=models.CASCADE)
    good=models.ForeignKey(‘df_goods.GoodsInfo‘, on_delete=models.CASCADE)

3、urls.py

#!/user/bin/env python
# -*- coding: utf-8 -*-
from django.conf.urls import url
from . import views

app_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)
]

4、view.py

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,Page

def register(request):
    context={
        ‘title‘:‘用户注册‘,
    }
    return render(request, ‘df_user/register.html‘, context)

def register_handle(request):
    #接受用户输入
    post = request.POST
    print(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=uname
    user.upwd=upwd3
    user.uemail=uemail
    user.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.POST
    uname = 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值
            #是否勾选记住用户名,设置cookie
            if 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].id
            request.session[‘user_name‘] = uname
            return red
        else:
            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()#清空当前用户所有session
    return 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.POST
        user.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)

5、user_decorator.py

对用户进行身份认证,如用户进入个人中心的时候需要验证,购买商品也需要身份验证

#!/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 red
    return login_fun

"""
http://127.0.0.1:8000/200/?type=10
request.path :表示当前路径,为/200/
request.get_full_path():表示完整路径,为/200/?type=10
"""

三、商品相关功能模块

app目录如下

df_goods
    - migrations
    - admin.py
    - apps.py
    - models.py
    - search_indexes.py  # 搜索商品功能
    - tests.py
    - urls.py
    - views.py
    - __init__.py

1、app.py

from django.apps import AppConfig

class DfGoodsConfig(AppConfig):
    name = ‘df_goods‘

2、models.py

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.ttitle

class 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的编解码方式是有关系的。

3、urls.py

#!/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)

]

4、view.py

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)).count
    except:
        cart_count = 0
    context = {
        ‘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:
        pass
    return response

def cart_count(request):
    if request.session.has_key(‘user_id‘):
        return CartInfo.objects.filter(user_id=request.session[‘user_id‘]).count
    else:
        return 0

class MySearchView(SearchView):
    def extra_context(self):
        context = super(MySearchView, self).extra_context()
        context[‘title‘] = ‘搜索‘
        context[‘guest_cart‘] = 1
        context[‘cart_count‘] = cart_count(self.request)
        return context

def cookieTest(request):
    response = HttpResponse()
    if request.COOKIES.get(‘binggan‘):#判断是否有此cookie
        cookie = request.COOKIES
        response.write(cookie[‘binggan‘])#如果有则写入
    return response

5、admin.py

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 = 15
    list_display = [‘id‘, ‘gtitle‘, ‘gunit‘,‘gclick‘, ‘gprice‘,‘gpic‘,‘gjianjie‘,‘gkucun‘,‘gcontent‘,‘gjianjie‘]

6、search_indexes.py

#!/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 GoodsInfo

    def index_queryset(self, using=None):
        return self.get_model().objects.all()

全局索引提供一个大的全局搜索功能,也可以通过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

from django.apps import AppConfig

class DfOrderConfig(AppConfig):
    name = ‘df_order‘

2、models.py

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.99
    count = models.IntegerField()

3、urls.py

#!/user/bin/env python
# -*- coding: utf-8 -*-
from django.conf.urls import url
from . import views

app_name = ‘df_order‘

urlpatterns = [
    url(r‘^$‘, views.order),
    url(r‘^push/$‘, views.order_handle),
]

4、view.py

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 = 0
    for 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)#订单的用户id
        order_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.count
                goods.save()
                # print(goods.gtitle,‘库存‘, goods.gkucun)
                order_detail.goods = goods
                order_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

五、购物车相关模块功能

app目录如下

df_cart
    - migrations
    - admin.py
    - apps.py
    - models.py
    - test.py
    - urls.py
    - views.py
    - __init__.py

1、app.py

from django.apps import AppConfig

class DfCartConfig(AppConfig):
    name = ‘df_cart‘

2、models.py

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()#记录用户买个多少单位的商品

3、urls.py

#!/user/bin/env python
# -*- coding: utf-8 -*-
from django.conf.urls import url
from . import views

app_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),
]

4、view.py

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 + count
    else:
        cart = CartInfo()
        cart.user_id = uid
        cart.goods_id = gid
        cart.count = count
    cart.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)

原文地址:https://www.cnblogs.com/welan/p/9900944.html

时间: 2024-11-05 13:55:52

天天生鲜 - App设计的相关文章

天天生鲜项目

1.天天生鲜商业模式 认识电商 1.1 B2B--企业对企业 B2B ( Business to Business)是指进行电子商务交易的供需双方都是商家(或企业. 公司),她(他)们使用了互联网的技术或各种商务网络平台,完成商务交易的过程.电子 商务是现代 B2B marketing 的一种具体主要的表现形式 案例:阿里巴巴.慧聪网 1.2 C2C--个人对个人 C2C 即 Customer(Consumer) to Customer(Consumer),意思就是消费者个人 间的电子商务行为.

移动APP设计国外资源总汇

目前,对于刚入行移动APP视觉或者交互设计的学习的你来说,一些好的设计辅助工具,一些素材下载,优秀网站设计网站,数据抓取和分析的小助手都是必不可少的.今天主要介绍的都是国外上的一些设计工具的下载,素材框架下载,作品欣赏等等移动ui设计的资源. 第一部分:移动APP设计 Canva 惊艳的轻量级图像设计软件. Fluid UI: 快捷.友好的移动端原型 工具. InVision:用来制作web.移动端原型.UI效果工具,免费. Ink:响应式邮件框架,ZURB出品. Pixlr:在线照片编辑工具.

Livecoding.tv 现正举行iOS及Android App设计比赛

近日,Livecoding.tv, 一个为世界各地的程序员提供在线实时交流的平台,在其网站上发布了一篇通知, 宣布从4月15日至5月15日,会为iOS和Android的开发者举办一场本地移动app设计比赛.据介绍,此次比赛旨在鼓励广大编程爱好者积极参与程序开发,亦让大家可以有机会大展所长.通过比赛,让大家发现更多编程的乐趣.比赛将对所有人开放,不论是不是livecoding.tv上的注册用户,均可报名参加.届时,Livecoding.tv将在其博客空间上进行投票,选出得奖的App.比赛共设三个奖

UI设计师必须了解:2015年十大移动端APP设计主流趋势

从移动端兴起,主流设计风格定型,再到Uber.Vine等现象级APP的崛起,移动端的APP设计直到现在才渐入佳境.促成这一切的影响因素很多,比如社会发展趋势的变化.共享经济的大热.新技术的积累,等等等等.这些事物的出现需要时间积累,这也是为什么这些应用到现在才火起来. 同样的,今年我们要关注的是定型了的巨屏手机和逐渐沉淀下来的可穿戴设备. 随着日常生活中所涉及到的移动端应用的增加,用户在这些东西上的所耗费的精神和脑力也越来越多.查看邮件.预订酒店.叫外卖都有赖于各种应用,而诸如Airbnb和Gr

APP设计中最容易忽视的4个问题

作者分享了在App设计过程中容易忽视的几个问题,总结出来与大家分享.不知道在你在进行产品设计的时候,是否也入坑过? 低版本强制更新问题 这个问题是在产品不断迭代中容易忽视的问题,因为只有当开发人员不能做到低版本兼容的时候才会去想到"哦,应该提醒低版本的用户需要强制了". 为什么不能继续兼容低版本呢?总结了如下原因: · 一是老版本不支持现有的业务,出于公司业务上的强制推广: · 二是业务线的接口的更新不兼容老版本,导致老版本部分需求无法正常使用: · 三是从公司研发资源的考虑,老版过多

安卓app设计规范整理和Android APP设计篇(转)

随着安卓智能手机不停的更新换代.安卓手机系统越来越完美,屏幕尺寸也越来越大啦!比如最近小米的miui 6的发布和魅族手机系统的更新等等. 以小米MIUI6的安卓手机来说,MIUI6进行了全新设计,坚持“内容才是本质”的设计哲学,重新提炼内容,简化图标设计. 所以,我们在进行安卓APP设计时,需要好好调整之前的设计规范和设计细节.根据目前流行的安卓手机的系统体验来完成我们的安卓APP设计规范.应该说这是整理出最全面的安卓app设计规范. 25学堂站在不断更新和完善安卓app设计规范为宗旨!利用周末

APP设计细节总结-摘录

视觉表现型问题 1. 统一的图标设计风格 2. 图标大小的视觉平衡(根据图标的体量对其大小做出相应的调整) 3. 优化你的分割线(通常我们会选择浅色而否定深色) 4. 合理的运用投影的颜色与透明度 5. 不要过度装饰,让界面更简洁 6. 图片比例&视平线的统一性(调整并列图片的大小比例) 7. 控制好界面中的配色数量(在选择配色组合时,使用相似色的配色方案可以使颜色更加协调和交融:如果希望更鲜明地突出某些元素,对比色是不错的选择) 8. 合理的进行设计对比 9. 提高配图的质量(对图片进行美化后

APP设计当中不容忽视的20个小细节

1.一致,一致,还是一致你能做的最重要的事情就是保证用户界面运作的一致性.对于列表框来说,如果双击其中的项,使得某些事件发生,那么双击任何其它列表框中的项,都应该有同样的事件发生.所有窗口按钮的位置要一致,标签和讯息的措辞要一致,颜色方案要一致.用户界面的—致性使得在用户对于界面运作建立起精确的心理模型,从而降低培训和支持成本.提炼:一致性体现在 色彩搭配和运用.字体的运用.相同的交互效果等.一般我们使用的色彩不超过3种.交互效果也不超过3种.2.建立标准并遵循之在应用软件中保持一致的唯一途径就

极客48小时APP设计大赛

为期三天的极客APP设计大赛,完美结束.下面我们来介绍这个大赛的整个过程. 一 极客APP设计大赛性质 由铂涛孵化器主办,百思一刻承办的铂涛创新体验极客挑战赛.主要由在校大学生.社会工作人士.创业者等组成的.期间有国家发改委主任等领导人莅临现场. 二 参赛的规模 整个过程总共有300个团队及个人报名参加报名,最终由举办方精选了16个团队80人参赛.里面有酷狗音乐第一队,小跑科技的第16对等等. 我们是代表公司参赛的,公司总共有两个队:第12队和第8队. 三 比赛时间 48小时激烈角逐和一下午的路