Django Web项目开发流程总结

1.创建项目
项目架构:
1)前端、后端部分(各五个分类):
1: 用户user 2: 商品goods 3: 购物车cart 4: 订单order 5: 后台admin
2)关系数据库:mysql
3)缓存服务器(session):redis内存型数据库
4)异步任务处理:celery
5)分布式文件存储系统:fastdfs

数据库设计:
(1)用户表:id,用户名,密码,邮箱,激活标识,权限标识
class User(AbstractUser, BaseModel):
    '''用户模型类'''

    class Meta:
        db_table = 'df_user'
        verbose_name = '用户'
        verbose_name_plural = verbose_name

        (2)地址表:id,收件人,收件地址,邮编,联系方式,是否默认,用户id

class Address(BaseModel):
    '''地址模型类'''
    user = models.ForeignKey('User', verbose_name='所属账户')
    receiver = models.CharField(max_length=20, verbose_name='收件人')
    addr = models.CharField(max_length=256, verbose_name='收件地址')
    zip_code = models.CharField(max_length=6, null=True, verbose_name='邮政编码')
    phone = models.CharField(max_length=11, verbose_name='联系电话')
    is_default = models.BooleanField(default=False, verbose_name='是否默认')

	# 自定义一个模型管理器对象,Django 会确保在模型类中至少有一个默认的Manager
	# 若没有添加自己的Manager,Django 将添加一个属性objects,它包含默认的Manager 实例
	# 若添加自己的Manager实例的属性,默认值则不会出现
    objects = AddressManager()

    class Meta:
        db_table = 'df_address'
        verbose_name = '地址'
        verbose_name_plural = verbose_name
        
class AddressManager(models.Manager):
    '''地址模型管理器类'''
    # 1.改变原有查询的结果集:all()
    # 2.封装方法:用户操作模型类对应的数据表(增删改查)
    def get_default_address(self, user):
        '''获取用户默认收货地址'''
        # self.model:获取self对象所在的模型类
        try:
            address = self.get(user=user, is_default=True)  # models.Manager
        except self.model.DoesNotExist:
            # 不存在默认收货地址
            address = None

        return address

        (3)商品SKU表:id,名称,简介,价格,单位,库存,销量,图片,状态,种类ID,SPU ID

class GoodsSKU(BaseModel):
    '''商品SKU模型类'''
    status_choices = (
        (0, '下线'),
        (1, '上线'),
    )

    type = models.ForeignKey('GoodsType', verbose_name='商品种类')
    goods = models.ForeignKey('Goods', verbose_name='商品SPU')
    name = models.CharField(max_length=20, verbose_name='商品名称')
    desc = models.CharField(max_length=256, verbose_name='商品简介')
    price = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='商品价格')
    unite = models.CharField(max_length=20, verbose_name='商品单位')
    image = models.ImageField(upload_to='goods', verbose_name='商品图片')
    stock = models.IntegerField(default=1, verbose_name='商品库存')
    sales = models.IntegerField(default=0, verbose_name='商品销量')
    status = models.SmallIntegerField(default=1, choices=status_choices, verbose_name='商品状态')

    class Meta:
        db_table = 'df_goods_sku'
        verbose_name = '商品'
        verbose_name_plural = verbose_name

        (4)商品种类表:id,种类名称,logo,图片

class GoodsType(BaseModel):
    '''商品类型模型类'''
    name = models.CharField(max_length=20, verbose_name='种类名称')
    logo = models.CharField(max_length=20, verbose_name='标识')
    image = models.ImageField(upload_to='type', verbose_name='商品类型图片')

    class Meta:
        db_table = 'df_goods_type'
        verbose_name = '商品种类'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name

        (5)首页轮播商品表:id,sku_id,图片,index(代码略,同下模型类)
        (6)首页促销活动表:id,图片,活动url,index
        (7)首页SPU表:id,名称,详情
        (8)首页分类商品展示表:id,sku_id,种类id,展示标识,index
        (9)商品图片表:id,图片,sku_id
        (10)订单商品表:id,订单id,sku_id,商品数量,商品价格,评论
        (11)订单信息表:订单id,地址id,用户id,支付方式,总数目,总金额,运费,支付状态,创建时间

2.创建项目
项目开发环境:linux
安装好虚拟环境(virtualenvwrapper)以及相关第三方库
输入指令:
django-admin startproject 项目名称
cd 项目目录

进入项目目录当中进行开发

3.创建应用
一个项目中可包含很多应用,本项目应用进行了模块化处理。
输入命令创建四个主要应用:

python manage.py startapp users
python manage.py startapp goods
python manage.py startapp orders
python manage.py startapp cart

在settings中的INSTALLED_APPS中配置四个应用:
(1)users(2)goods(3)orders(4) cart

Django Web项目开发流程总结_第1张图片
配置应用

由于之前User继承于AbstractUser和BaseModel,只在其模型类的元类中进行部分数据修正。AUTH_USER_MODEL配置参数要在第一次迁移数据库之前配置,否则django认证系统工作不正常。(配置如下图)在配置完AUTH_UESR_MODEL后,django会创建user表,并且之后进行
python manage.py createsuperuser

创建的超级管理员也会在df_user的表中。

配置django认证用户模型

3.配置数据库
Django支持多种数据库,这里演示使用 sqlite,具体数据库配置于项目下的settings.py中进行。

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': os.path.join(BASE_DIR, 'db.mysql'),
    }
}

5.编写models.py文件
MVT框架的M,表示model,负责与数据库交互。
进行各模型类代码编写(部分代码见项目数据库设计部分)
6.迁移模型至数据库
(1)激活模型:
   于settings的INSTALLED_APPS中注册应用(如上图)
(2)生成迁移文件
  进行迁移这一过程,会根据定义的模型类来生成对应的sql语句:
  终端执行如下指令:
  python manage.py makemigrations
  如此mysql数据库部分已搭建好了。
7. 编写模板文件
MVT框架的T,表示template,负责呈现内容到浏览器。 模板是Django项目中用来向用户展示网站具体信息的部分,为html文件,不过在其基础上添加了类python的可执行代码,具有python代码的html文件通过渲染后,可生成普通的html文件。
Django项目中模板的路径为项目根目录下的templates中。

Django Web项目开发流程总结_第2张图片
带有python代码的html文件内容

8.编写视图文件
视图Django当中用来处理用户请求的部分,对应MVT中的V(view),是框架的核心,负责接收请求、获取数据和返回结果。
视图会根据用户所发出的请求向模型获取所需数据,并将数据发送给模板,并对模板进行渲染操作,将渲染好的html文件返回给浏览器进行展示。(鉴于篇幅,本文展示项目当中购物车cart模块的view文件内容)

from django.shortcuts import render
from django.views.generic import View
from django.http import JsonResponse

from goods.models import GoodsSKU
from django_redis import get_redis_connection
from utils.mixin import LoginRequiredMixin

# Create your views here.
# 添加商品到购物车:
# 1)请求方式,采用ajax post
# 如果涉及到数据的修改(新增,更新,删除), 采用post
# 如果只涉及到数据的获取,采用get
# 2) 传递参数: 商品id(sku_id) 商品数量(count)


# ajax发起的请求都在后台,在浏览器中看不到效果
# /cart/add
class CartAddView(View):
    '''购物车记录添加'''
    def post(self, request):
        '''购物车记录添加'''
        user = request.user
        if not user.is_authenticated():
            # 用户未登录
            return JsonResponse({'res':0, 'errmsg':'请先登录'})

        # 接收数据
        sku_id = request.POST.get('sku_id')
        count = request.POST.get('count')

        # 数据校验
        if not all([sku_id, count]):
            return JsonResponse({'res':1, 'errmsg':'数据不完整'})

        # 校验添加的商品数量
        try:
            count = int(count)
        except Exception as e:
            # 数目出错
            return JsonResponse({'res':2, 'errmsg':'商品数目出错'})

        # 校验商品是否存在
        try:
            sku = GoodsSKU.objects.get(id=sku_id)
        except GoodsSKU.DoesNotExist:
            # 商品不存在
            return JsonResponse({'res':3, 'errmsg':'商品不存在'})

        # 业务处理:添加购物车记录
        conn = get_redis_connection('default')
        cart_key = 'cart_%d'%user.id
        # 先尝试获取sku_id的值 -> hget cart_key 属性
        # 如果sku_id在hash中不存在,hget返回None
        cart_count = conn.hget(cart_key, sku_id)
        if cart_count:
            # 累加购物车中商品的数目
            count += int(cart_count)

        # 校验商品的库存
        if count > sku.stock:
            return JsonResponse({'res':4, 'errmsg':'商品库存不足'})

        # 设置hash中sku_id对应的值
        # hset->如果sku_id已经存在,更新数据, 如果sku_id不存在,添加数据
        conn.hset(cart_key, sku_id, count)

        # 计算用户购物车商品的条目数
        total_count = conn.hlen(cart_key)

        # 返回应答
        return JsonResponse({'res':5, 'total_count':total_count, 'message':'添加成功'})


# /cart/
class CartInfoView(LoginRequiredMixin, View):
    '''购物车页面显示'''
    def get(self, request):
        '''显示'''
        # 获取登录的用户
        user = request.user
        # 获取用户购物车中商品的信息
        conn = get_redis_connection('default')
        cart_key = 'cart_%d'%user.id
        # {'商品id':商品数量, ...}
        cart_dict = conn.hgetall(cart_key)

        skus = []
        # 保存用户购物车中商品的总数目和总价格
        total_count = 0
        total_price = 0
        # 遍历获取商品的信息
        for sku_id, count in cart_dict.items():
            # 根据商品的id获取商品的信息
            sku = GoodsSKU.objects.get(id=sku_id)
            # 计算商品的小计
            amount = sku.price*int(count)
            # 动态给sku对象增加一个属性amount, 保存商品的小计
            sku.amount = amount
            # 动态给sku对象增加一个属性count, 保存购物车中对应商品的数量
            sku.count = count
            # 添加
            skus.append(sku)

            # 累加计算商品的总数目和总价格
            total_count += int(count)
            total_price += amount

        # 组织上下文
        context = {'total_count':total_count,
                   'total_price':total_price,
                   'skus':skus}

        # 使用模板
        return render(request, 'cart.html', context)


# 更新购物车记录
# 采用ajax post请求
# 前端需要传递的参数:商品id(sku_id) 更新的商品数量(count)
# /cart/update
class CartUpdateView(View):
    '''购物车记录更新'''
    def post(self, request):
        '''购物车记录更新'''
        user = request.user
        if not user.is_authenticated():
            # 用户未登录
            return JsonResponse({'res': 0, 'errmsg': '请先登录'})

        # 接收数据
        sku_id = request.POST.get('sku_id')
        count = request.POST.get('count')

        # 数据校验
        if not all([sku_id, count]):
            return JsonResponse({'res': 1, 'errmsg': '数据不完整'})

        # 校验添加的商品数量
        try:
            count = int(count)
        except Exception as e:
            # 数目出错
            return JsonResponse({'res': 2, 'errmsg': '商品数目出错'})

        # 校验商品是否存在
        try:
            sku = GoodsSKU.objects.get(id=sku_id)
        except GoodsSKU.DoesNotExist:
            # 商品不存在
            return JsonResponse({'res': 3, 'errmsg': '商品不存在'})

        # 业务处理:更新购物车记录
        conn = get_redis_connection('default')
        cart_key = 'cart_%d'%user.id

        # 校验商品的库存
        if count > sku.stock:
            return JsonResponse({'res':4, 'errmsg':'商品库存不足'})

        # 更新
        conn.hset(cart_key, sku_id, count)

        # 计算用户购物车中商品的总件数 {'1':5, '2':3}
        total_count = 0
        vals = conn.hvals(cart_key)
        for val in vals:
            total_count += int(val)

        # 返回应答
        return JsonResponse({'res':5, 'total_count':total_count, 'message':'更新成功'})


# 删除购物车记录
# 采用ajax post请求
# 前端需要传递的参数:商品的id(sku_id)
# /cart/delete
class CartDeleteView(View):
    '''购物车记录删除'''
    def post(self, request):
        '''购物车记录删除'''
        user = request.user
        if not user.is_authenticated():
            # 用户未登录
            return JsonResponse({'res': 0, 'errmsg': '请先登录'})

        # 接收参数
        sku_id = request.POST.get('sku_id')

        # 数据的校验
        if not sku_id:
            return JsonResponse({'res':1, 'errmsg':'无效的商品id'})

        # 校验商品是否存在
        try:
            sku = GoodsSKU.objects.get(id=sku_id)
        except GoodsSKU.DoesNotExist:
            # 商品不存在
            return JsonResponse({'res':2, 'errmsg':'商品不存在'})

        # 业务处理:删除购物车记录
        conn = get_redis_connection('default')
        cart_key = 'cart_%d'%user.id

        # 删除 hdel
        conn.hdel(cart_key, sku_id)

        # 计算用户购物车中商品的总件数 {'1':5, '2':3}
        total_count = 0
        vals = conn.hvals(cart_key)
        for val in vals:
            total_count += int(val)

        # 返回应答
        return JsonResponse({'res':3, 'total_count':total_count, 'message':'删除成功'})

9.配置url 在完成网站各个功能模块的model、templates、view创建后,接下来需要将这几个部分打通起来,使其组合起来协调工作。此时,需要进行url的配置。

当客户端浏览器一个request请求到服务器的时候,首先要对请求的url信息进行解析,获取当前请求需要的信息是什么,请求会对应一个具体的view视图,视图会将模板和模型组合起来。
10.项目配置
有关项目所需进行的配置:
(1)设置应用所在路径,以便于应用注册可找到相应应用

import os
import sys
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, os.path.join(BASE_DIR, 'apps'))

(2)uwsgi上线部署

DEBUG = False
# 为了让我们的项目可以被远程访问,在设置文件中指定项目运行的主机IP:
# 在uwsgi服务器中可设置为‘*’
ALLOWED_HOSTS = ['*']

(3)uwsgi应用路径设置

WSGI_APPLICATION = 'dailyfresh.wsgi.application'

(4)url全局配置

ROOT_URLCONF = 'dailyfresh.urls'

(5)url全局配置

ROOT_URLCONF = 'dailyfresh.urls'

(6)用户模型配置

# django认证系统使用的用户模型类(由于自行定制了用户模型类)
AUTH_USER_MODEL='user.User' 

(7)url全局配置

# 修改站点语言
# LANGUAGE_CODE = 'en-us'
LANGUAGE_CODE = 'zh-Hans'

# 修改站点时区
# TIME_ZONE = 'UTC'
TIME_ZONE = 'Asia/Shanghai'

(8)静态页面及文件的配置

STATIC_URL = '/static/'		# 静态文件的路径设置
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')]
# 指定收集静态文件的路径
STATIC_ROOT='/var/www/dailyfresh/static'

(9)Tinymce富文本编辑器配置

# 富文本编辑器配置
TINYMCE_DEFAULT_CONFIG = {
    'theme': 'advance',
    'width': 600,
    'height': 400,
}

(10)邮件配置

# 发送邮件配置
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
# smpt服务地址
EMAIL_HOST = 'smtp.163.com'
EMAIL_PORT = 25
# 发送邮件的邮箱
EMAIL_HOST_USER = '[email protected]'
# 在邮箱中设置的客户端授权密码
EMAIL_HOST_PASSWORD = 'smartli123'
# 收件人看到的发件人
EMAIL_FROM = '天天生鲜'

(11)Django缓存配置

CACHES = {
    "default": {
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": "redis://172.16.179.142:6379/9",		# redis对应的服务器ip和端口
        "OPTIONS": {
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
        }
    }
}

(12)配置session存储

SESSION_ENGINE = "django.contrib.sessions.backends.cache"
SESSION_CACHE_ALIAS = "default"

(13)配置登录url地址
登录地址因项目需要而定制url登录地址,故需于settings文件中自行配置

LOGIN_URL='/user/login' # /accounts/login?next=/user

(14)FDFS配置

# 设置Django的文件存储类
DEFAULT_FILE_STORAGE='utils.fdfs.storage.FDFSStorage'
# 设置fdfs使用的client.conf文件路径
FDFS_CLIENT_CONF='./utils/fdfs/client.conf'
# 设置fdfs存储服务器上nginx的IP和端口号
FDFS_URL='http://172.16.179.131:8888/'

(15)全文检索框架的配置

# 全文检索框架HAYSTACK的配置
HAYSTACK_CONNECTIONS = {
    'default': {
        # 使用whoosh引擎
        # 'ENGINE': 'haystack.backends.whoosh_backend.WhooshEngine',
        'ENGINE': 'haystack.backends.whoosh_cn_backend.WhooshEngine',
        # 索引文件路径
        'PATH': os.path.join(BASE_DIR, 'whoosh_index'),
    }
}

# 当添加、修改、删除数据时,自动生成索引
HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor'

# 指定搜索结果每页显示的条数
HAYSTACK_SEARCH_RESULTS_PER_PAGE=1

11.启动服务

# 启用django正常指令
python manage.py runserver ip:port
# 配置uwsgi服务器
启动:uwsgi –-ini 配置文件路径 例如:uwsgi –-ini uwsgi.ini
停止:uwsgi --stop uwsgi.pid路径 例如:uwsgi –-stop uwsgi.pid

12.站点管理
Django自带一套完整可定制的后端站点管理系统,可实现对项目数据库的增删改查操作。
进入方式是在项目网址后面加 /admin
(1)创建超级用户
但在进入站点管理前必须创建一个超级用户,通过超级用户才能登陆到站点管理后台。

# 创建超级用户指令
python manage.py createsuperuser

(2)注册模型
进入网站管理界面主要是为了管理数据库中的内容,但之前的工作中只是定义了模型并完成模型带数据库的迁移操作,这些只是准备操作。
要想在站点中管理数据库对象必须要先在系统管理中进行注册。

注册方法:在所创建的应用目录下的admin.py文件,在该文件中导入对应的模型列,调用admin模块的register模块。

from django.contrib import admin
from django.core.cache import cache
from goods.models import GoodsType,IndexPromotionBanner,IndexGoodsBanner,IndexTypeGoodsBanner

admin.site.register(GoodsType)
admin.site.register(IndexGoodsBanner)
admin.site.register(IndexTypeGoodsBanner)
admin.site.register(IndexPromotionBanner)

对相应的模型类注册后,便可以登录到管理界面进行数据处理了。

你可能感兴趣的:(项目相关)