十二、用户中心(用户部分)

1、用户信息展示

<1>用户模型类添加email_active字段,邮箱校验状态

email_active = models.BooleanField(default=True, verbose_name='邮箱验证状态')

在这里插入图片描述
<2>执行迁移命令

python manage.py makemigrations
pythn mange.py migrate

<3>apps/users/views下创建用户信息详情视图

from rest_framework.generics import RetrieveAPIView

class UserDetailView(RetrieveAPIView):
    serializer_class = UserDetailSerializer
    # 权限指定,只有被认证后的用户才可以访问
    permission_classes = [IsAuthenticated]

    # 重写get_object方法,返回用户指定信息
    def get_object(self):
        return self.request.user

<4>apps/users/serializers下创建序列化器

class UserDetailSerializer(serializers.ModelSerializer):

    class Meta:
        model = User
        exclude =('password',)

在这里插入图片描述
<5>apps/users/urls下添加子路由

urlpatterns = [
    url(r"^user/$", views.UserDetailView.as_view()),
]

在这里插入图片描述


2、使用Django发送邮件,实现用户邮箱验证

Django中内置了邮件发送功能,被定义在django.core.mail模块中。发送邮件需要使用SMTP服务器,常用的免费服务器有:163、126、QQ,下面以163邮件为例。

<1>注册163邮箱itcast88,登录后设置。
在这里插入图片描述
<2>在新页面中点击“客户端授权密码”,勾选“开启”,弹出新窗口填写手机验证码。
在这里插入图片描述
<3>填写授权码。
在这里插入图片描述
<4>提示开启成功。
在这里插入图片描述
<5>在Django配置文件settings/dev.py中,设置邮箱的配置信息

EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.163.com'
EMAIL_PORT = 25
#发送邮件的邮箱
EMAIL_HOST_USER = 'itcast88@163.com'
#在邮箱中设置的客户端授权密码
EMAIL_HOST_PASSWORD = 'python808'
#收件人看到的发件人
EMAIL_FROM = 'python<itcast88@163.com>'

<6>注册异步发送邮件任务完成业务逻辑代码

  • 异步任务业务逻辑代码
from django.conf import settings
from django.core.mail import send_mail
from celery_tasks.main import app

@app.task(name='send_email')
def send_email(subject, to_email, html_message):
    send_mail(subject, '', settings.EMAIL_FROM,
              [to_email], html_message=html_message)
  • celery_tasks/main/注册异步任务(如下图所示:)

在这里插入图片描述

<7>添加邮箱账号并向用户发送验证邮件

  • 创建用户信息更新视图类
class UserUpdateView(UpdateAPIView):
    """
    绑定邮箱账号并发送邮件
    """
    serializer_class = UserUpdateSerializer
    def get_object(self):
        return self.request.user
  • 创建用户信息序列化器

class UserUpdateSerializer(serializers.ModelSerializer):
    """
      绑定邮箱账号并发送邮件
    """
    class Meta:
        model = User
        fields = ("email",)

    def update(self, instance, validated_data):
        instance.email = validated_data["email"]
        instance.save()
        tjss = TJSS(settings.SECRET_KEY, 300)
        token = tjss.dumps({'username':instance.username}).decode()
        # send_mail(subject, message, from_email, recipient_list, html_message=None)
        # subject 邮件标题/message 普通邮件正文, 普通字符串/from_email 发件人/ recipient_list 收件人列表/html_message 多媒体邮件正文,可以是html字符串
        verify_url = 'http://www.meiduo.site:8080/success_verify_email.html?token=' + token
        subject = "美多商城用户邮箱验证"
        html_message = '<p>尊敬的用户您好!</p>' \
                   '<p>感谢您使用美多商城。</p>' \
                   '<p>您的邮箱为:%s 。请点击此链接激活您的邮箱:</p>' \
                   '<p><a href="%s">%s<a></p>' % (validated_data['email'], verify_url, verify_url)
        # 异步发送邮件
        send_email(subject, validated_data['email'], html_message)

        # 往用户邮箱中发送验证信息
        return instance
  • apps/users/urls下添加子路由
urlpatterns = [
    url(r"^email/$", views.UserUpdateView.as_view()),
]

在这里插入图片描述<7>实现邮箱验证

  • 在apps/users/views/下添加EmailVerifyView视图类
from rest_framework.views import APIView
from itsdangerous import TimedJSONWebSignatureSerializer as TJSS

class EmailVerifyView(APIView):
	"""
	用户邮箱信息验证
	"""

    def get(self,request):
        # 1、从前端获取token
        token = request.query_params.get('token')
        # 2、检查数据
        tjss = TJSS(settings.SECRET_KEY, 300)
        try:
            data = tjss.loads(token)
        except:
            return Response({'error':'token无效'})
        # 3、查询用户数据
        username = data.get('username')
        user = User.objects.get(username=username)
        # 4、修改用户邮箱状态
        user.email_activate = True
        user.save()
        # 5返回结果
        return Response({'message':True})
  • 添加子路由
urlpatterns = [
    url(r"^emails/verification/$", views.EmailVerifyView.as_view()),
]

3、管理收货地址

<1>创建注册应用,创建模型类
  • 在meiduo_mall/apps创建areas应用
python ../../manage.py startapp areas
  • 注册应用,创建模型类
from django.db import models

# Create your models here.
class Area(models.Model):
    """
    行政区划
    """
    name = models.CharField(max_length=20, verbose_name='名称')
    parent = models.ForeignKey('self', on_delete=models.SET_NULL, related_name='subs', null=True, blank=True, verbose_name='上级行政区划')

    class Meta:
        db_table = 'tb_areas'
        verbose_name = '行政区划'
        verbose_name_plural = '行政区划'

    def __str__(self):
        return self.name

在这里插入图片描述

  • 进行数据库迁移
python manage.py makemigrations 
python manage.py migrate
  • 导入地区信息数据
mysql -u root -p meiduo32 < /home/python/Desktop/temp/美商城资料/省市区数据/areas.sql
  • 缓存使用配置(settings/dev)
# DRF扩展
REST_FRAMEWORK_EXTENSIONS = {
    # 缓存时间
    'DEFAULT_CACHE_RESPONSE_TIMEOUT': 60 * 60,
    # 缓存存储
    'DEFAULT_USE_CACHE': 'default',
}
<2>省市区地址联动功能
  • 在areas/views实现省市区地址联动视图类的实现
from rest_framework.generics import ListAPIView
from rest_framework_extensions.cache.decorators import cache_response
from rest_framework_extensions.cache.mixins import CacheResponseMixin
from areas.models import Area
from areas.serializers import AreaSerializer

# 通过继承扩展类实现使用缓存,推荐使用
class AreaView(CacheResponseMixin,ListAPIView):
    """
    获取省份信息
    """
    queryset = Area.objects.filter(parent=None)
    serializer_class = AreaSerializer


class Area1View(ListAPIView):
    """
    获取市/区信息
    """    
    serializer_class = AreaSerializer
    # 缓存的使用需要装饰器装饰在定义的方法上
    # @cache_response(timeout=60*60, cache='default')
    def get_queryset(self):
        pk = self.kwargs['pk']
        return Area.objects.filter(parent_id=pk)
  • AreaSerializer序列化器实现
from rest_framework import serializers
from areas.models import Area


class AreaSerializer(serializers.ModelSerializer):

    class Meta:
        model = Area
        fields = '__all__'

  • 注册路由
# 注册子路由 areas/urls
from django.conf.urls import url
from areas import views

urlpatterns = [
    url(r'^areas/$', views.AreaView.as_view()),
    url(r'^areas/(?P<pk>\d+)/$', views.Area1View.as_view()),
]
# 注册主路由 meiduo_mall/urls
from areas.urls

urlpatterns = [
    url(r'^', include(areas.urls)),
]
<3>用户地址管理功能实现
  • 创建收货地址管理表,apps/users/models
# 创建地址管理表
class Address(BaseModel):
    """
    用户地址
    """
    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='addresses', verbose_name='用户')
    title = models.CharField(max_length=20, verbose_name='地址名称')
    receiver = models.CharField(max_length=20, verbose_name='收货人')
    province = models.ForeignKey('areas.Area', on_delete=models.PROTECT, related_name='province_addresses', verbose_name='省')
    city = models.ForeignKey('areas.Area', on_delete=models.PROTECT, related_name='city_addresses', verbose_name='市')
    district = models.ForeignKey('areas.Area', on_delete=models.PROTECT, related_name='district_addresses', verbose_name='区')
    place = models.CharField(max_length=50, verbose_name='地址')
    mobile = models.CharField(max_length=11, verbose_name='手机')
    tel = models.CharField(max_length=20, null=True, blank=True, default='', verbose_name='固定电话')
    email = models.CharField(max_length=30, null=True, blank=True, default='', verbose_name='电子邮箱')
    is_deleted = models.BooleanField(default=False, verbose_name='逻辑删除')

    class Meta:
        db_table = 'tb_address'
        verbose_name = '用户地址'
        verbose_name_plural = verbose_name
        ordering = ['-update_time']

# 给用户表添加默认地址字段
class User(AbstractUser):
	...
    default_address = models.ForeignKey('Address', related_name='users', null=True, blank=True,on_delete=models.SET_NULL, verbose_name='默认地址')
	...
  • 数据库迁移
python manage.py makemigrations
python manage.py migrate

  • 创建AddressesView视图类完成新增地址的保存(apps/areas/views)
class AddressesView(CreateAPIView, ListAPIView):
    """
    保存新增地址
    """
    serializer_class = AddressesSerializer
  • 定义AddressesSerializer序列化器
class AddressesSerializer(serializers.ModelSerializer):

    # 显示指定字段
    city_id = serializers.IntegerField(min_value=1, write_only=True)
    district_id = serializers.IntegerField(min_value=1, write_only=True)
    province_id = serializers.IntegerField(min_value=1, write_only=True)
    district = serializers.StringRelatedField(read_only=True)
    province = serializers.StringRelatedField(read_only=True)
    city = serializers.StringRelatedField(read_only=True)

    class Meta:
        model = Address
        exclude = ('user',)

    # 验证手机号格式
    def validate_mobile(self,value):
        if not re.match(r'^1[3-9]\d{9}$', value):
            raise serializers.ValidationError('手机号格式不正确')
        return value

    # 保存新增地址
    def create(self,validated_data):

        user = self.context['request'].user
        # 需要在验证后数据中添加user
        validated_data['user'] = user
        # 使用父类保存方法
        address = super().create(validated_data)

        return address
  • 注册子路由(apps/areas/urls)
urlpatterns = [
    url(r'^addresses/$', views.AddressesView.as_view()),
]

  • 修改AddressesView视图类完成地址的查询
class AddressesView(CreateAPIView, ListAPIView):
    """
    保存新增地址
    """
    serializer_class = AddressesSerializer
    # queryset = Address.objects.filter(user=request.user)

    # 重写get_queryset获取指定内容
    def get_queryset(self):

        return Address.objects.filter(user=self.request.user, is_deleted=False)

    def list(self, request, *args, **kwargs):

        queryset = self.filter_queryset(self.get_queryset())
        serializer = self.get_serializer(queryset, many=True)

        return Response({"addresses":serializer.data})

  • 修改AddressesView视图类完成地址的更新
class AddressesView(CreateAPIView, ListAPIView, UpdateAPIView):
	...
  • 注册子路由
urlpatterns = [
    url(r'^addresses/(?P<pk>\d+)/$', views.AddressesView.as_view()),
]

在这里插入图片描述

---------python

  • 修改AddressesView视图类完成地址的删除
class AddressesView(CreateAPIView, ListAPIView, UpdateAPIView, DestroyAPIView):
    """
    保存新增地址
    """
    serializer_class = AddressesSerializer
    # queryset = Address.objects.filter(user=request.user)

    # 重写get_queryset获取指定内容
    def get_queryset(self):

        return Address.objects.filter(user=self.request.user, is_deleted=False)

    # 地址查询操作
    def list(self, request, *args, **kwargs):

        queryset = self.filter_queryset(self.get_queryset())
        serializer = self.get_serializer(queryset, many=True)

        return Response({"addresses":serializer.data})
	# 地址删除操作
    def destroy(self, request, *args, **kwargs):

        instance = self.get_object()
        instance.is_deleted = True
        instance.save()

        return Response(status=status.HTTP_204_NO_CONTENT)
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值