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)