Django框架电商网站开发流程(Python)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/youzi_yun/article/details/78310425

一、配置

1 创建项目和应用

  • 配置项目setting.py(应用,templates路径,数据库,STATICFILES_DIRS)
  • 配置项目urls.py,namespace起名最好和应用名一样,不容易混淆

2 配置应用

  • 在每个应用中创建urls.py
  • 同时对应该应用的views.py,同步配置视图函数,name和视图函数以及url的名字最好保持一致

3 创建相应的文件夹,将前台文件放入

static

  • images
  • js
  • css

templates

templates下创建每个应用单独的文件夹,将html文件放入

二、拆分模板

  • 创建父模板
    在templates下创建文件夹common;
    该文件夹存储父模板base.html和status.html模板(其他相同代码片模板)
父模板留空给子模板写不同代码片
{% block 模板名 %}
{% endblock 模板名 %}

继承父模板  
{% extends 父模板名 %}

包含相同代码片模板  
{% include 'common/status.html' %}
  • 在html页面中修改,继承父模板
  • 记得更改html页面中static元素
加载静态文件
{% load staticfiles %}

静态文件写入方式:
{% static ‘路径/文件名‘ %}


该路径以static文件为相对路径

三、创建模型

1、创建抽象模型基类

  • 在项目下新建文件夹db,储存AbstractModel.py 在该文件中创建抽象基类
  • 在models.py中
    from db.AbstractModel import *
    创建模型(继承抽象基类)和模型管理器
  • 表迁移

2、模型操作的原则

  • 如果定义的方法是针对表数据操作,需要定义在自定义管理类中

    例如:插入数据、查询表中的数据

  • 如果定义的方法针对是行数据进行操作,需要定义在模型类中

    例如:修改某一行数据的某个字段数据

  • 在模型管理类中写方法可以直接用self;
    在模型类中写方法,需要self.objects;
    两者都可以用 模型类.objects。

  • 表级操作用的是模型管理器对象;
    行级操作用的是那一行数据对象(例如:self.get(user_id = XX)获取到的对象)。

模型管理类
- self.all()
模型类
- self.objects.all()
- user = User()
  user.objects.all()

出错点
模型类要重新写objects = 管理类(),objects记得写s,
提示错误信息,User没有objects

三、注册功能

页面 user/register

1 更改register.html中表单提交方式和表单提交的视图

method=“postaction=“{% url ‘/user/register_handle‘ %}

2 创建视图register_handle,处理表单提交事件

views.py中导入 from .functions import *
functions中导入 from utils.wrapper import *

视图中只写大概的逻辑判断(根据信息匹配成功与否判断是否提交),具体的函数另外同级创建一个文件functions.py处理,使views保持整洁,逻辑易读。

(1) 同级创建 functions.py

该文件主要对该视图内需要里获取的参数进行判断,只对users来使用,并把判断结果返回给视图。

(2) 创建utils文件夹

该文件夹下的模块的函数可以对全局使用

a. 创建 wrapper.py

在functions.py中写函数进行判断后,此时需要用到django的原生函数post获取数据,我们在项目下再创建一个文件夹utils工具,在utils下创建wrapper.py,在该文件内对post等原生函数进行封装,方便调用。

举例:

    def post(request, param):
        <!--去掉取出数据的两边空格-->
        return request.POST.get(param, "").strip()

b. 修改html页面

获取页面用户输入数据,需要表单中的input标签的name属性,去html文件中进行name属性的命名修改。

(3) functions.py处理表单提交的数据

  • 获取所有用户输入数据
  • 建立flag,假设所有数据均为错误
  • 对每个数据进行逐一格式判断,更改flag
  • 判断用户名是否已存在
    需要查询用户表,对数据库进行操作,对数据库进行的所有操作均在models.py中进行,写在uesr管理器中。
models中管理类中写入方法对数据库表进行操

- 注册功能用到了查询和插入数据两项

- 方法的参数为request或者是已经处理过的数据

- 查询该用户是否存在于数据库中(参数为用户名)

  • 若通过校验,获取数据,存入数据库

  • 若没有通过校验:

a. 视图之间通信 from django.contrib import messages

  • messages也是基于cookie和session的封装

  • 从一个页面(视图)跳转到另一个页面(视图)时,如果需要传递参数,可以用get,在URL后面加上?xx=xx,
    但是这里传递错误消息,内容较长,用这种方式不合理,就需要一个可以在视图间进行数据传输的工具。

  • 这个模块是进行视图之间通信,数据传输所用,相当于一个队列,可以放入数据,取出数据,一次性使用。

<!--message.INFO  INFO 代表信息级别,
还有ERROR  WARNING ,
这里仅仅是传递一个错误信息,INFO足够了-->
添加信息
messages.add_message(request, message.INFO, "数据内容")

取出信息
mess = messages.get_messages(request)
这里mess并不是一个队列,但是是 可以迭代的,可通过for循环取出

这里mess并不是一个队列,但是是可以迭代的,可通过for循环取出
值得注意的是,取出的数据是先进先出,取出,并不能确定哪条数据归属于哪个内容下的错误提示,
所以要在wrapper.py中对这两个原生接口进行封装:

  • 添加消息时给每个消息加个消息头,组成类似于字典的字符串“key:value”;
  • 取出数据时,根据:对消息进行切割,组成字典的形式。

3 处理错误提示消息

user/register/当点击注册时在前端页面显示
- 将错误提示消息放在register视图中取出,记为mess;
- 在index.html中显示错误提示消息的地方添加一样的标签,更改class,并写入{% mess.key %},会自动寻找字典中值而添加。
- 修改样式,和前端的提示信息css样式一致,更改display:block为显示;
- 修改js中焦点触发事件,在触发焦点时,后台错误提示消息的标签隐藏。

4 通过ajax请求,异步判断用户名是否存在

js发送ajax请求后台判断用户名是否存在,返回结果给js进行异步判断,注册页面在用户输入用户名时可实时显示用户名是否存在

四、登录功能

不能进行用户是否存在验证,不安全

1 建立处理用户登录时的视图

在该视图中写入主要逻辑:

如果验证通过,回到xx页面;(先返回首页,后面写中间件处理过后,再判断session中是否有pre_url,如果有,返回pre_url,没有则返回主页)

验证不通过,重回登录页面,并提示错误消息

2 在function.py中判断用户名和密码输入的格式是否正确

  1. 如果格式不正确,直接回到登录页面
  2. 如果格式正确,进行用户名和密码验证
    • 验证通过:先跳转到首页
    • 验证不通过:
      通过messages模块,将错误提示消息(用户名或密码错误)放入队列中;

      更改views中的登录视图,取出message中的错误提示消息,更改登录页面login.html和js,使错误提示消息在表单提交后显示。

3 设置cookie和session

(1)思路

  1. 如果用户登录时,选择记住用户名,需要设置用户登录名的cookie,存储在浏览器;
  2. 当用户登录后,需要在每个页面保持用户的登录状态,需要设置用户登录名的session;
    因为用户每次发送请求,request中都带有cookie,cookie中带有sessionid,可以识别用户;
  3. 当未登录用户在商品等页面点击或跳转至登录页面之后,如果登录成功,则直接跳转回上次的商品浏览页面;
  4. 当用户未登录时,不能进入用户中心,地址和订单页面,可使用装饰器对这三个视图进行包装,若点击这个三个链接,直接重定向到登录页面。

(2)实现

先登录

1. 在warpper.py中对cookie和session进行封装
response.set_cookie[key] = value
request.get_cookie[key]
response.delete_cookie[key] 如果key不存在什么也不发生

<!--设置session过期时间:
0为关闭浏览器时过期,
整数为多少秒后过期,
不设置或value为None时使用默认的,
Django默认为两周-->
<!--request.session.set_expiry(value)-->

request.session[key] = value
request.session.get(key,"") 获取session,key不存在默认为空
request.session[key]  获取session,key不存在会报错
del request.session[key]
request.session.flush()

<!--del request.session[key]只是删除value,key还在,所以一般用request.session.flush()全部删除-->
2. 用户登录:
  • 设置session,记录登录状态
  • 若勾选记住用户名,需设置cookie
3. 用户登出,删除session
4. 浏览商品后再登录,需要:中间件–记录上次的浏览页面
  • 在视图处理url前,记录上次浏览的页面,process_request和process_view均可,这里显然process_request更方便(传入参数只需要request);
  • 设置一个列表,存储,不需要保存的URL;

    (1)例如,登录、注册的url,处理表单的URL,用户中心、地址、订单的URL,网络图标favicon.ico等。

    (2)这里也包含了用户中心、地址、订单页面,如果用户在该页面登出,再登录,也返回首页。

    (3)如果需求为再登录时,回到之前的用户中心、地址、订单页面,中间件中这几个url就不加入列表。
  • 获取上次登录页面pre_url=request.get_all_path()的包含带有?的参数等全部url。

    如果url在列表中,则直接返回首页;
    如果不在列表中,则返回上次登录页面,即pre_url。
!!! 中间件修改:
  • 由于process_request会记录一些跳转页面,所以这里更改为process_response
  • 将拦截条件添加response.status_code==200,最后一定要返回response。

4 用户浏览页面的权限

需求

若已登录,可以进入用户中心、订单、地址、页面;

若未登录,点击这些链接,回到登录页面。


这里使用装饰器

def permission_verfy(view_func):
    def wraper(request,*args,**kwargs):
        <!--判断用户是否登录-->
        if get_session(request, 'username'):
            return view_func(request,*args,**keargs)
        else:
            return redirect(首页url)
    return wrapper

五、用户中心

1 用户中心左侧菜单栏拆分

  1. 由于左侧菜单一样,需要拆分模板;
  2. 左侧菜单种当前页面的栏目有特殊样式;
方法一:
模板包含的时候可以通过with传递参数
{% include 'user/left_menu.html' with flag="order" %}

在通用模板left_menu.html中,进行判断
{% if flag="order" %}class="active"{% endif %}

方法二(根据列表自动生成菜单栏):
使用过滤器:
{% with menus=flag|creat_meau %}
(将参数flag传入过滤器函数creat_meau,函数返回结果赋给menus)
在过滤器中设置列表,列表中字典根据键值对存储主要参数,
对于特殊样式,action键可以通过三步运算判断
flag = "order" and "active" or "" 
在left_menu.html中for循环自动生成菜单栏,

2 用户个人中心修改地址

form表单提交,套路:

  1. 前台js验证输入是否合法;
  2. 配制form表单提交方式和提交的url;
  3. views后台获取form表单数据,验证数据是否合法;
  4. 合法数据存入数据库,
  5. 验证到不合法数据,将验证失败的错误提示通过messages加入队列;
  6. 前台html显示。
    • 添加html后台错误提示的标签;
    • 修改后台错误提示的样式,display=block;
    • 修改js,焦点获取时blur(),将后台的错误提示标签隐藏;
    • 后台用户中心页面view取出messages队列中的错误提示,加入html中。

六、商品

1 创建商品分类模型,商品信息模型

(1)商品分类模型

  • 商品类名

(2)商品信息模型

  • 商品名
  • 商品价格
  • 商品单位
  • 商品简介
  • 商品详情(采用富文本编辑器)
  • 商品状态(上架,下架)
  • 商品图片
  • 商品分类(外键关联商品分类模型)
  • 商品浏览量
  • 商品销售量

2 创建测试数据

3 商品首页的数据显示

(1)获取最新商品

(2)获取最热门商品

3 商品详细页面

(1)设计为带?参数的url或者正则匹配的url

这里为/goods/detail/?id=xxx
根据商品id动态生成商品详细页面
在商品详情url的视图中,通过utl中传入的参数,get(request,”id”)获取该商品对象,在html中写入数据.

(2)获取两个最新产品

(3)配制这些图片的链接

带参数的?url
{%  url "goods:detail" %}?id={{ goods.id }}
或 正则提取url
{%  url "goods:detail" goods.id %}

(4)js操作 根据商品价格和数量实时变动总价

js就够了,不需要ajax,让后台来做

(5) 商品浏览记录

a.创建商品浏览记录模型

  • 浏览用户(外键关联用户表)
  • 浏览商品(外键关联商品表)

b.这里需要用户id

我们把user_id,添加到session或者cookie中,可以直接获取
1. 当用户登录成功,设置cookie,user_id
2. 在商品详细页面的视图中,获取user_id判断用户是否登录,如果用户已登录,获取goods_id,将它们存入数据库;
3. 在存入数据库时,进行判断:

如果用户存在:
    获取用户的浏览商品record_goods_list,并按更新时间排序
    1 如果该商品存在:
        直接save,可以更新时间
    2 如果商品不存在:
        判断商品数量:
        如果商品数量<5:直接存入数据库;
        否则:获取更新时间最早的一条数据对象,record_goods_list[0],对其进行更新覆盖。
  1. 去用户中心,在用户中心视图获取浏览记录,在html中显示。

4 商品列表页

(1)需求:

  • 根据分类显示商品
  • 根据销量、人气、默认进行商品排序

(2)设计url

可以正则匹配两个参数,param1为商品分类id,param2为商品排序方式
^"/goods/detail/(\d)/(\w+)"/$
视图获取商品
goods = Goods.objects.filter(分类字段_id=param1).order_by(param2)

(3)商品列表分页

分页器 Paginator

页码用?在url中传入参数

from django.core.paginator import Paginator

<!--创建分页器-->
paginator = Paginator(所有商品对象,每页放置商品的个数)
<!--获取当前页码-->
page_now = get(request,"page","1")  # 给默认页码为1
<!--获取当前页码内商品对象-->
goods_now = paginator.page(page_now)

---常用属性---

paginator属性:
paginator.page_range  页码范围,可以在html中for循环生成页码

goods_now的属性、方法:
goods_now.number 当前页码
has_next() 是否有下一页
has_previous() 是否有上一页
next_page_number() 返回下一页页码
previous_page_number() 返回上一页页码

七、购物车

1 创建购物车模型

  • 用户 (关联用户表用户id)
  • 商品 (关联商品表商品id)
  • 商品数量

2 在商品详细页面做添加购物车点击事件

(1)异步更新购物车数量

  1. ajax向后台传入数据(添加商品数量,商品id),配制添加购物车url和视图,返回json数据(现有购物车数量),异步更新购物车数量标签。

  2. js如何获取商品id?

        在detail页面中添加一个隐藏域,js可以通过标签获取val。

<input type="hidden" value={{ goods.id }} class="xx"> 
  1. 进行判断,并存入数据库
1 如果用户未登录,跳转至登录页面
2 如果已登录,
    判断该用户是否在购物车表中
    (1)存在:获取用户id的所有商品对象
        判断该商品是否存在:
            如果存在,更新数量
            如果不存在,直接存入
    (2)不存在该用户
        直接存入

(2)全局显示购物车商品数量

a.需求:

  • 由于商品首页,列表页,详情页面均由购物车的标签,所以需要全局实时显示购物车数量。

b.实现:

  • 由于每次进行页面请求,均会发出request,所以让购物车商品总数成为request的一个属性,这样每次request请求都会携带这个数据。
  • 不能在每个视图中都对这个属性进行设置,这样代码重复度太高,也同样秉持着原代码最好不要进行修改的原则,所以写一个装饰器,装饰器内设置这个属性。
  • 但是,不是所有的页面均需要该属性,在商品首页、列表页、详情页的视图上添加该装饰器。

3 购物车页面

(1)从数据库获取数据,数据显示

(2)js操作,商品数量、单品总价,选中商品总价格实时变化

  • 这里需要后台先更新数据库的购物车表数据,前台才能更新数据,所以这里的ajax请求需要同步,后台更新数据之后,前台html才显示更新;
  • ajax默认异步async:true,这里需要具体配置;
  • post方式不同于get方式可以被django直接得到,因为django为post加入了csrf保护;
  • 解决方法一:在HTML页面中添加一个隐藏域{% csrf_token %},手动获取name和value,发送给后台;
<input type='hidden' name='csrfmiddlewaretoken' value='MErcUv3Df23t84YsP4skrRbIWCAtVwpe' />
  • 解决方法二(不可取):在 settings.py 中 MIDDLEWARE_CLASSES 中 注释掉’django.middleware.csrf.CsrfViewMiddleware’
<!--get请求-->

$.ajax({
    url:"请求的url",
    data:{json数据},
    dataType:"json",  // 默认为json数据格式
    async:false,  // 设置同步
    type:"get",  //  默认为get请求方式 

    }).done(function(data){
        获得从后台返回的json数据
    }).fail(function(){
        alert("服务器超时,请重试!");
    })

<!--post请求    -->

$.ajax({
    url:"请求的url",
    data:{"csrfmiddlewaretoken":xxxxxxxx},
    dataType:"json",  // 默认为json数据格式
    async:false,  // 设置同步
    type:"post",  //  默认为get请求方式 

    }).done(function(data){
        获得从后台返回的json数据
    }).fail(function(){
        alert("服务器超时,请重试!");
    })
  • 将实时更新页面单品总价,商品总数量,购物车总价等内容,写一个通用的函数,方便调用,将点击事件的标签当做参数传给这个函数即可。这些标签可以通过$(this)父级标签往下找。
  • 注意:在ajax请求内部,不能直接操作$(this),可以在外部设置一个旗子flag=false,在ajax内部操作flag;在外部通过对flag值的判断来继续执行。

(3) 提交订单

a. 为购物车HTML页面添加form,提交地址为提交订单页面,这时就要换到order应用下操作了。
b. js写入表单提交事件,判断是否选中商品,若选中,则提交表单,未选中,提示用户。

4 提交订单页面

  • 获取商品id列表
request.POST.getlist("标签name属性")
  • 通过商品id列表获取商品对象列表,HTML渲染

猜你喜欢

转载自blog.csdn.net/youzi_yun/article/details/78310425