IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Python知识库 -> django项目梳理 -- 天天生鲜项目之User模块 -> 正文阅读

[Python知识库]django项目梳理 -- 天天生鲜项目之User模块

  1. django项目流程
    在这里插入图片描述

  2. 需求分析

     1. 用户模块
     	1) 注册页
     		1. 完成用户信息注册
     		2. 注册时校验用户名是否已被注册
     		3. 给用户的注册邮箱发送邮件,用户点击邮件中的激活链接完成账户的激活
    
     	2) 登录页
     		1. 实现登录功能
    
     	3) 用户中心
     		1. 用户中心信息页: 显示登陆用户信息,包括用户名、电话和地址,
     		   同时页面下方显示出用户最近浏览的商品信息
     		2. 用户中心地址页: 显示登陆用户的默认收件地址
     		   页面下方表单可以新增用户的收货地址
     		3. 用户中心订单页: 显示用户的订单信息
    
     	4) 其他
     		1. 如果用户已登录,页面顶部显示登录用户的信息
     2. 商品模块
     	1) 首页
     		1. 动态指定首页幻灯片商品信息
     		2. 动态指定首页活动信息
     		3. 动态获取商品的种类信息并显示
     		4. 动态指定首页显示的每个种类的商品(包括图片商品和文字商品)
     		5. 点击某个商品,跳转到该商品的详情页
    
     	2) 商品详情页
     		1. 显示出该商品的详情信息
     		2. 页面左下方显示出该种类商品的2个新品信息
    
     	3) 商品列表页
     		1. 显示出某一个种类商品的列表数据,分页显示并支持按默认、价格、人气进行排序
     		2. 页面左下方显示出该种类商品的2个新品信息
    
     	4) 其他
     		1. 通过页面搜索框搜索商品信息
     		
     3. 购物车模块
     	1. 列表页和详情页将商品添加到购物车
     	2. 用户登录后,首页,详情页,列表页显示用户购物车中的商品数目
     	3. 购物车页面: 对用户购物车中商品的操作
     	   如果选择某件商品,增加或减少购物车中商品的数目
     
     4. 订单模块
     	1. 提交订单页面: 显示用户准备购买的商品信息
     	2. 点击提交订单完成订单的创建
     	3. 用户中心订单页: 显示用户的订单信息
     	4. 点击支付,完成订单的支付
    

页面图
功能图
3. 架构设计

4. 数据库表结构设计
在这里插入图片描述
5. 模块代码实现

	**用户模块**
	1. 用户模块代码实现
		1. 用户模块有5个页面,注册页,登录页,用户中心信息/订单/地址页
		2. 注册页功能 -- 注册,发送激活邮件
		3. 登录页功能 -- 登录
		4. 用户中心信息页 -- 显示个人信息,浏览记录 -- 浏览记录需要和商品模块配合,这部分写不了
		5. 用户中心地址页 -- 显示,添加收货地址
		6. 用户中心订单页 -- 显示订单信息 -- 需要和订单模块配合使用,暂时写不了
	
	2. models.py 知识点
		1. 用户表,可以使用django自带的用户表基类,是组成django认证用户的一部分
			from django.contrib.auth.models import AbstractUser
			
		2. 继承了AbstractModel类,需要对表名以及后台管理界面的字段显示作出修改
			class Meta:
		        db_table = 'df_user'  # db_table 重新命名表名
		        verbose_name = '用户'  # 重新定义models在后台管理页面中的名字
		        verbose_name_plural = verbose_name  # 重新定义models在后台管理页面中的名字的复数

		3. 所有的表都有创建时间,修改时间,是否删除标识,所以要封装成模型抽象基类。
		   通过以下代码可以说明该类是模型抽象基类:
			class Meta:
				abstract = True
		
		4. 要多次获取默认的收货地址可以自定义管理器类,继承Models.manager类,此处使用的是自定义管理器功能1;
			1、什么是管理器				
				管理器是Django的模型进行数据库操作的接口,Django应用的每个模型类都拥有至少一个管理器。Django支持自定义管理器类,继承自models.Manager
				objects是Django帮我自动生成的管理器对象,通过这个管理器可以实现对数据的查询
				objects是models.Manger类的一个对象。自定义管理器之后Django不再帮我们生成默认的objects管理器

			2、自定义管理器步骤
				1、自定义一个管理器类,这个类继承models.Manger类。
				2、再在具体的模型类里定义一个自定义管理器类的对象
		    3、自定义管理器类有两个功能(两个应用场景):
		   		1. 封装方法:用户操作模型类对应的数据表(增删改查)
# 自定义管理器类
class BookInfoManager(models.Manager):
	...
	def create_book(self, title, pub_date):
		#创建模型类对象self.model可以获得模型类
		book = self.model()
		book.btitle = title
		book.bpub_date = pub_date
		book.bread=0
		book.bcommet=0
		book.isDelete = False
		# 将数据插入进数据表
		book.save()
		return book

# 模型类
class BookInfo(models.Model):
	...
	books = BookInfoManager()
		    	  	  
#	调用:book=BookInfo.books.create_book("abc",date(1980,1,1))
#   说明:self指向实例对象 --> BookInfoManager(),books指向实例对象 --> BookInfoManager()
#         self.model --> self所在的模型类,即BookInfoManager()所在的模型类,即books所在的模型类,即BookInfo
#         self.model() 等价于 BookInfo()
		   		2. 改变查询集结果
class BookInfoManager(models.Manager):
	def all(self):
		#默认查询未删除的图书信息
		#调用父类的成员语法为:super().方法名
		return super().all().filter(isDelete=False)
	
class BookInfo(models.Model):
	 ...
	 objects = BookInfoManager()

# 调用:BookInfo.objects.all()
# 说明:super().all() --> 单继承时,即父类.all() --> 即models.Manger.all()
# user.models.py
from django.db import models
from django.contrib.auth.models import AbstractUser
from db.base_model import BaseModel

class User(AbstractUser, BaseModel):
    '''用户模型类'''
    # 继承AbstractUser类,需要重写部分

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

class AdressManager(models.Manager):
    '''地址模型管理类,封装方法'''
    # 1.改变原有查询的结果集:all()
    # 2.封装方法:用户操作模型类对应的数据表(增删改查)
    def get_default_address(self, user):
        # Address.objects.get_default_address()
        # addr = Address().objects.get(user=user, is_default=True)
        # self.model() 等价于 Address()
        # self.model().objects 等价于 AdressManager() 等价于self
        try:
            addr = self.get(user=user, is_default=True)
            print(addr.address)
            print('---------------------------------')
        except:
            addr = None
        return addr

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

     # 自定义一个模型管理器对象
    objects = AdressManager()

    class Meta:
        db_table = 'df_address'
        verbose_name = '地址'
        verbose_name_plural = verbose_name
        

# db.base_model_BaseModel  地址
from django.db import models

class BaseModel(models.Model):
    '''模型抽象基类'''
    create_time = models.DateTimeField(auto_now_add=True, verbose_name= '创建时间')
    update_time = models.DateTimeField(auto_now=True, verbose_name= '更新时间')
    is_delete = models.BooleanField(default=False, verbose_name= '删除标记')

    class Meta:
        # 说明是抽象模型类
        abstract = True
	3. views.py 知识点
		1. 类视图
			通用类视图基类: 
			django.views.generic.View  ( 与django.views.generic.base.View 是同一个)
			urls.py中配置路由使用类视图的as_view()方法
			由dispatch()方法具体将请求request分发至对应请求方式的处理方法中(get、post等)
			get方法是显示,
			post方法是验证信息并修改数据库,处理信息步骤如下
				1. 接收信息,request.POST.get
				2. 校验数据
					1. 校验数据完整性:if not all([username, password, cpassword, email]):
					2. 其余的校验视数据特性设计
				3. 业务处理,修改数据库
				4. 返回应答
		
		2. 修改数据表
			1. 增
			 	b = BookInfo()
				b.btitle="射雕英雄传"
				from datetime import date
				b.bpub_date=date(1991,1,31)
				b.save()
				补充: 每增加一条记录需要创建一个实例对象
				
				# 使用 create()
				from datetime import date
				BookInfo.objects.create(btitle= '射雕英雄传', bpub_data= data(1991,1,31))
				Address.objects.create(
		            user= user,
		            receiver= receiver,
		            address= address,
		            zip_code= zip_code,
		            phone_number= phone_number,
		            is_default= is_default,
		        )
				
				# 继承django.contrib.suth.models.AbstractUser类,
				# 可以使用create_user(username,email=None,password=None)方法
				# 该方法创建保存一个is_active=True的User对象并返回。
				# username不能够为空,否则抛出ValueError异常。
				# email和password都是可选的。email的domain部分会被自动转变为小写。password如果没有提供,则User对象的set_unusable_password()方法将会被调用。		
				# 3. 进行业务处理,注册信息
		        user = User.objects.create_user(username=username, password=password, email=email)
		        # 用户未激活,user对象的is_active是1
		        user.is_active = 0
		        user.save()	
				
				2. 查
				  b1 = BookInfo.objects.get(id=1)  # 返回对象
				  b1.btitle  # 就可以使用 对象.属性 进行查询值
				  BookInfo.objects.all()  # 返回QuerySet对象,返回所有信息
				  b1.heroinfo_set.all()  # 关联操作,查找id为1的图书中所有英雄人物的信息
				  
				3. 删
				  b1 = BookInfo.objects.get(id=1)
				  b1.delete()
				  
				4. 改
				  b1 = BookInfo.objects.get(id=1)
				  b1.bpub_date=date(2017,1,1)
				  b1.save()
		
		3. 发送电子邮件 -- 使用celery 异步发送
			# 发送激活邮件,包含激活链接: http://127.0.0.1:8000/user/active/3(user_id)
    		# 激活链接中需要包含用户的身份信息, 并且要把身份信息(user_id)进行加密
    		
			1. 数据加密 -- itsdangerous模块
				from itsdangerous import TimedJSONWebSignatureSerializer as Serializer	
				serializer = Serializer(secret_key, 过期时间)
				# info需要加密的信息,可以是字典也可以是元组
				token = serializer.dumps(info)  # 加密,byte类型
				token = token.decode()  # 转换为str类型
				info = serializer.loads(token) # 解密
				
				# 加密用户的身份信息,生成激活token,使用的secret_key是django settings中自带的秘钥
		        serializer = Serializer(settings.SECRET_KEY, 7200)
		        info = {'confirm': user.id}  # 加密信息
		        token = serializer.dumps(info)  # 生成加密文字,是byte类型
		        token = token.decode()

			2. 发邮件 -- django内置模块django.core.mail.send_mail
				语法:send_mail(subject, message, sender, receiver, html_message=html_message)
				from django.core.mail import send_mail
				celery任务发布,在views.py中调用任务函数,任务函数.delay(*args, **kwargs),即为发布任务
			   
			   需要在settings.py里面配置
			   163邮箱显示的授权码: *********
			    # 邮箱配置
				# django内置模块
				EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
				# smpt服务地址与端口
				EMAIL_HOST = 'smtp.163.com'
				EMAIL_PORT = 25
				# 发送邮件的邮箱
				EMAIL_HOST_USER = '**********@163.com'
				# 在邮箱中设置的客户端授权密码
				EMAIL_HOST_PASSWORD = '**************'
				# 收件人看到的发件人
				EMAIL_FROM = '天天生鲜<**********@163.com>'

				邮箱需要和celery搭配使用
				创建celery_tasks模块,在模块捏有tasks.py文件
				在tasks.py文件中定义的任务函数
				# 定义任务函数
				def send_register_active_email(to_addr, username, token):
				    '''发送激活邮件'''
				    # 组织邮件信息
				    subject = '天天生鲜欢迎您'  # 邮件标题
				    message = ''  # 邮件正文,HTML内容会进行转义,就是你写啥,网页显示啥
				    sender = settings.EMAIL_FROM  # 发件人
				    receiver = [to_addr]  # 收件人
				    html_message = '''<h1>%s,欢迎成为天天生鲜注册会员</h1>
				                      <br /><br/>
				                      请点击下面的链接激活您的账户<br/>
				                      <a href = 'http://127.0.0.1:8000/user/active/%s'>http://127.0.0.1:8000/user/active/%s</a>'''%(username, token, token)  # 需要显示html内容
				    send_mail(subject, message, sender, receiver, html_message=html_message)

				在views.py中使用时,from celery_tasks.tasks import send_register_active_email
				需要 send_register_active_email.delay()

			3. celery模块	
				celery: 三部分组成,任务发出者,经纪人(broker),任务处理者(worker)
				broker这部分需要借助RabbitMQ,redis,此处使用redis
				任务发出者是 send_register_active_email.delay(email, username, token)
				broker是:app = Celery('celery_tasks.tasks', broker='redis://127.0.0.1:6379/2')
				worker:celery -A <路径> worker -l info -P eventlet
			
				创建Celery实例对象,书写任务函数,将任务函数状态改为发布(用Celery实例对象的task函数包装任务函数)
				from celery import Celery
				app = Celery('celery_tasks.tasks', broker='redis://127.0.0.1:6379/2')  # 第一个参数是Celery实例对象的名称,第二个是broker

				发布任务函数
				@app.task
				# 任务函数
				def send_register_active_email(to_addr, username, token):
					pass

				启动celery worker,worker所在电脑也要有项目代码
				# 在任务处理者一端加这几句,因为celery启动也需要django环境
					import os
					import django
					os.environ.setdefault("DJANGO_SETTINGS_MODULE", "dailyfresh.settings")
					django.setup()
				celery -A <路径> worker -l info -P eventlet
				
		4. 用户登录相关函数
			1. user = authenticate(username= username, password= password)  # 验证用户名,密码与数据表中是否一致
			2. login(request, user)  # 将用户id保存在session中
			3. logout(request)  # 清除session信息
			4. user.is_authenticated  # 登录,返回True,未登录,返回False
			5. user = request.user
			6. login_required装饰器,已登录可以正常跳转,未登录,返回127.0.0.1:8000/user/login?next=/user
			   所以重新登陆后要跳转到之前想登录的页面,地址即是next后面的值
	
		5. 添加/删除session
			response.set_cookie('username', username, max_age=7*24*3600)
         	response.delete_cookie('username')							

Django认证系统方法
celery工作示意图

# user.views.py
from django.shortcuts import render,redirect
from django.core.urlresolvers import reverse
from django.views.generic import View
from django.http import HttpResponse
from django.conf import settings
from django.contrib.auth import authenticate, login, logout

from user.models import User, Address
from itsdangerous import TimedJSONWebSignatureSerializer as Serializer
from itsdangerous import SignatureExpired
from celery_tasks.tasks import send_register_active_email
import re


class RegisterView(View):
    '''注册页面显示及注册信息处理'''
    def get(self, request):
        '''显示注册页面'''
        return render(request, 'user/register.html')

    def post(self,request):
        '''处理注册信息'''
        # 1. 接收注册信息
        username = request.POST.get('user_name')  # 用户名
        password = request.POST.get('pwd')  # 密码
        cpassword = request.POST.get('cpwd')  # 重复密码
        email = request.POST.get('email')  # 邮箱
        allow = request.POST.get('allow')  # 同意标识

        # 2. 校验数据
        # 校验数据完整性,如果不完整,重新输入
        if not all([username, password, cpassword, email]):
            return render(request, 'user/register.html', {'errmsg': '数据不完整'} )

        # 校验重复密码与密码是否一致
        if cpassword != password:
            return  render(request, 'user/register.html', {'errmsg': '两次密码不一致'})

        # 校验邮箱,使用正则表达式
        if not re.match(r'^[a-z0-9][\w.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
            return render(request, 'register.html', {'errmsg': '邮箱格式不正确'})

        # 协议必须同意后才能生效
        if allow != 'on':
            return render(request, 'register.html', {'errmsg': '请同意协议'})

        # 校验用户名是否重复
        try:
            user = User.objects.get(username= username)
        except User.DoesNotExist:
            # 用户名不重复
            user = None

        if user:
            return render(request, 'user/register.html', {'errmsg': '用户名重复'})

        # 3. 进行业务处理,注册信息
        user = User.objects.create_user(username=username, password=password, email=email)
        # 用户未激活
        user.is_active = 0
        user.save()

        # 发送激活邮件,包含激活链接: http://127.0.0.1:8000/user/active/3
        # 激活链接中需要包含用户的身份信息, 并且要把身份信息进行加密

        # 加密用户的身份信息,生成激活token
        serializer = Serializer(settings.SECRET_KEY, 7200)
        info = {'confirm': user.id}  # 加密信息
        token = serializer.dumps(info)  # 生成加密文字,是byte类型
        token = token.decode()

        # 发邮件
        send_register_active_email.delay(email, username, token)

        # 返回应答,登录页面
        return redirect(reverse('user:login'))


class ActiveView(View):
    '''用户激活'''
    # 点击链接,访问方式是get
    def get(self, request, token):
        serializer = Serializer(settings.SECRET_KEY, 7200)
        try:
            info = serializer.loads(token)  # 解密
            user_id = info['confirm']  # 获取user_id
            # 修改is_active状态为1
            user = User.objects.get(id= user_id)
            user.is_active = 1
            user.save()

            # 跳转到登录页面
            return redirect(reverse('user:login'))

        # 激活链接过期
        except SignatureExpired as e:
            # 此处为模拟,应该是过期后,跳转到新的页面,继续发出一封激活链接邮件
            return HttpResponse('激活链接已过期')


class LoginView(View):
    '''用户登录'''
    def get(self, request):
        '''显示登录页面'''
        # 判断是否记住了用户名,记住了则是cookies中有username,还有记住用户名复选框被选中
        if 'username' in request.COOKIES:
            username = request.COOKIES.get('username')
            checked = 'checked'
        else:
            checked = ''
            username = ''
        context = {'username': username, 'checked': checked}
        return render(request, 'user/login.html', context)

    def post(self, request):
        '''处理登录信息'''
        # 1. 接收信息
        username = request.POST.get('username')
        password = request.POST.get('pwd')
        print(username)
        print(password)

        # 2. 校验数据
        # 数据完整性
        if not all([username, password]):
            return render(request, 'user/login.html', {'errmsg': '数据不完整'})

        # 业务处理,登录校验
        user = authenticate(username= username, password= password)
        print('*'*50)
        print(user)
        print('*'*50)
        # 用户名,密码正确,校验通过
        if user is not None:
            # 用户已激活
            if user.is_active:
                # 记录用户的登录状态
                login(request, user)
                # 默认跳转到首页
                # 获取登录后所要跳转的地址
                next_url = request.GET.get('next', reverse('goods:index'))
                response = redirect(next_url)

                # 记住用户名如果勾选
                remember = request.POST.get('remember')
                if remember == 'on':
                    # 保存到cookies中去
                    response.set_cookie('username', username, max_age=7*24*3600)
                else:
                    # 清除cookies
                    response.delete_cookie('username')

                # 返回应答
                return response
            else:
                return render(request, 'user/login.html', {'errmsg': '账户未激活'})
        else:
            return render(request, 'user/login.html', {'errmsg': '用户名或密码错误'})


class LogoutView(View):
    '''用户退出'''
    def get(self, request):
        # 清除用户的session信息
        logout(request)
        # 用户退出后,重定向到首页
        return redirect(reverse('goods:index'))
from django.core.mail import send_mail
from django.conf import settings
from django.template import loader
from celery import Celery
import time

# 在任务处理者一端加这几句
import os
import django
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "dailyfresh.settings")
django.setup()

from goods.models import GoodsType, IndexGoodsBanner, IndexPromotionBanner, IndexTypeGoodsBanner, GoodsSKU


# 使用celery,创建一个Celery实例对象
app = Celery('celery_tasks.tasks', broker='redis://127.0.0.1:6379/2')

# 定义任务函数,需要在Celery实例对象中发布
@app.task
def send_register_active_email(to_addr, username, token):
    '''发送激活邮件'''
    # 组织邮件信息
    subject = '天天生鲜欢迎您'  # 邮件标题
    message = ''  # 邮件正文,HTML内容会进行转义,就是你写啥,网页显示啥
    sender = settings.EMAIL_FROM  # 发件人
    receiver = [to_addr]  # 收件人
    html_message = '<h1>%s, 欢迎您成为天天生鲜注册会员</h1>请点击下面链接激活您的账户<br/><a href="http://127.0.0.1:8000/user/active/%s">http://127.0.0.1:8000/user/active/%s</a>' % (username, token, token)  # html内容
    send_mail(subject, message, sender, receiver, html_message=html_message)
    time.sleep(5)
	6. 用户中心需要登录才能跳转,使用login_required装饰器
		1. 登录装饰器 -- @login_required == login-required(函数)
			功能:装饰view函数,只有登陆之后,(view函数才能工作)才能访问,未登录访问,返回settings.login_url
			使用:login_required(View.as_view()),封装函数
			说明:url配置中 UserInfoView.as_view(),执行LoginRequiredMinxin的as_view()方法;
				 返回 login_required(view),其中view使用的是super(LoginRequiredMinxin, cls).as_view(**initkwargs);
				 在多重继承中UserInfoView在LoginRequiredMinxin类的下一个继承是View类,所以执行的是View中的as_view方法
				 
			from django.contrib.auth.decorators import login_required
			
			class LoginRequiredMinxin(object):
			    @classmethod
			    def as_view(cls, **initkwargs):
			        # 调用父类的as_view()
			        view = super(LoginRequiredMinxin, cls).as_view(**initkwargs)
			        return login_required(view)

			sttings.py里面
			# 配置登录url地址
			LOGIN_URL='/user/login' # /accounts/login
	
	7. redis充当缓存,浏览历史记录的实现

redis历史浏览记录的实现思路

# user.views.py -- 用户中心
from django.shortcuts import render,redirect
from django.core.urlresolvers import reverse
from django.views.generic import View
from django.http import HttpResponse
from django.contrib.auth import authenticate, login, logout

from django_redis import get_redis_connection
from user.models import User, Address
from utils.mixin import LoginRequiredMinxin

import re

class UserInfoView(LoginRequiredMinxin, View):
    '''用户中心--信息页'''
    def get(self, request):
        '''显示'''
        # 处理欢迎信息,需要判断用户是否登录,使用request.user
        # 可以直接在模板文件中修改,
        # 除了 你给模板文件传递的模板变量之外,django框架会吧request.user也传给模板变量
        # 如果用户未登录->user是AnonymousUser类的一个实例对象
        # 如果用户登录->user是User类的一个实例对象
        # request.user.is_authenticated()

        # 获取用户的个人信息
        user = request.user
        addr = Address.objects.get_default_address(user)
        # print('联系方式:%s'%(addr.phone_number))

        # 获取用户的浏览记录,使用交互时所需要用到的语法,StrictRedis类
        # from redis import StrictRedis
        # sr = StrictRedis(host='172.16.179.130', port='6379', db=3)
        # 简便方法
        con = get_redis_connection('default')

        # redis中保存的形式是 history_userid: [3,1,2,..., 商品id]
        # 获取用户最新浏览的5个商品id
        history_key = 'history_%d'%user.id
        sku_ids = con.lrange(history_key, 0, 4)

        # 根据sku_ids, 获取到商品信息
        goods_li = []
        for sku_id in sku_ids:
            good = GoodsSKU.objects.get(id=sku_id)
            goods_li.append(good)

        context = {
            'page': 'user',
            'addr': addr,
            'goods_li': goods_li
        }
        return render(request, 'user/user_center_info.html', context)


class UserOrderView(LoginRequiredMinxin, View):
    '''用户中心--订单页'''
	pass


class UserAddressView(LoginRequiredMinxin, View):
    '''用户中心--地址页'''
    def get(self, request):
        '''显示'''
        # 从address数据表中获取收件人,收件地址,联系电话的信息
        # 获取用户
        user = request.user
        addrs = Address.objects.filter(user=user)
        ADDR = ''
        print('addr是%s'%addrs)

        HtmlStrList = []
        for addr in addrs:
            if not addr.is_default:
                HtmlStr = "<dd>%s (%s 收) %s</dd>" % (addr.address, addr.receiver, addr.phone_number)
                HtmlStrList.append(HtmlStr)
            else:
                ADDR = addr

        # if not ADDR:
        #     context = {
        #         'page': 'address',
        #         'HtmlStrList': HtmlStrList,
        #     }
        # else:
        #     context = {
        #         'page': 'address',
        #         'addr': ADDR,
        #         'HtmlStrList': HtmlStrList,
        #     }
        context = {
            'page': 'address',
            'addr': ADDR,
            'HtmlStrList': HtmlStrList,
        }



        return render(request, 'user/user_center_site.html', context)

    def post(self, request):
        '''添加地址'''
        # 1. 接受信息
        receiver = request.POST.get('receiver')
        address = request.POST.get('address')
        phone_number = request.POST.get('phone_number')
        zip_code = request.POST.get('zip_code')

        # 2. 校验
        # 数据完整性
        if not all([receiver, address, phone_number]):
            return render(request, 'user/user_center_site.html', {'errmsg': '数据不完整'})

        # 校验手机号
        if not re.match(r'^1[3|4|5|7|8]\d{9}$', phone_number):
            return render(request, 'user/user_center_site.html', {'errmsg': '手机号码不正确'})

        # 3. 业务处理:添加地址
        # 如果用户已存在默认地址,添加的地址就不做为默认地址
        # 获取登录用户对应的User对象
        user = request.user
        print('user的值是:%s'%user)

        # 获取用户默认收货地址
        # try:
        #     addr = Address.objects.get(user=user.id, is_default=True)
        #     print(addr.address)
        #     print('---------------------------------')
        # except:
        #     addr = None
        # print(addr)

        addr = Address.objects.get_default_address(user)
        print(addr)

        # 如果能查询出默认地址,即目前添加的就不是默认地址
        if addr:
            is_default = False
        else:
            is_default = True

        # 添加地址
        Address.objects.create(
            user= user,
            receiver= receiver,
            address= address,
            zip_code= zip_code,
            phone_number= phone_number,
            is_default= is_default,
        )

        return redirect(reverse('user:address'))

# utils.mixin
from django.contrib.auth.decorators import login_required

class LoginRequiredMinxin(object):
    @classmethod
    def as_view(cls, **initkwargs):
        # 调用父类的as_view()
        view = super(LoginRequiredMinxin, cls).as_view(**initkwargs)
        return login_required(view)
  Python知识库 最新文章
Python中String模块
【Python】 14-CVS文件操作
python的panda库读写文件
使用Nordic的nrf52840实现蓝牙DFU过程
【Python学习记录】numpy数组用法整理
Python学习笔记
python字符串和列表
python如何从txt文件中解析出有效的数据
Python编程从入门到实践自学/3.1-3.2
python变量
上一篇文章      下一篇文章      查看所有文章
加:2021-09-26 10:07:25  更:2021-09-26 10:07:42 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/15 16:26:04-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码