主路由模块添加功能
安装tinymce:
``'
sudo pip3 install django-tinymce==2.6.0
因为要使用到富文本编辑器所以在settings中注册应用’tinymce’,并且在settings中添加tinymce相关属性
这是富文本编辑器在settins.py中的应用
# 富文本编辑器配置
TINYMCE_DEFAULT_CONFIG = {
'theme': 'advance',
'width': 600,
'height': 400,
}
还需要在主路由中添加一个新的请求地址:
url(r'^tinymce/', include('tinymce.urls')), # 富文本编辑器
USER APP
注意在使用模型类之前要注意,在项目配置包的init中
如果没有pymysql可以使用
sudo pip3 install pymysql
然后在init中
import pymysql
pymysql.install_as_MySQLdb()
首先在models模块中创建模型类:
from django.db import models
# 导入django自带的用户模型类
# 减少代码量
from django.contrib.auth.models import AbstractUser
from db.base_model import BaseModel
# Create your models here.
class User(AbstractUser, BaseModel):
"""
用户模型类
"""
class Meta:
"""
元数据类
:var:db_table:模型类在数据库中的表名
:var:verbose_name:定义模型类在后端管理时显示的名字
"""
db_table = 'df_user'
verbose_name = '用户'
verbose_name_plural = verbose_name
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='是否默认')
class Meta:
db_table = 'df_address'
verbose_name = '地址'
verbose_name_plural = verbose_name
user.urls相关
from django.conf.urls import url
from user.views import RegisterView, ActiveView, LoginView
# 从views视图模块中导入请求处理类,要注意当你在定义请求处理类时,可以定义多种方法get, post
urlpatterns = [
# url(r'^register$', views.register, name='register'), # 注册
# url(r'^register_handle$', views.register_handle, name='register_handle'), # 注册处理
url(r'^register$', RegisterView.as_view(), name='register'), # 注册
url(r'^active/(?P.*)$', ActiveView.as_view(), name='active'), # 用户激活
url(r'^login$', LoginView.as_view(), name='login'), # 登录
]
在user.views中创建处理RegisterView类来处理注册请求
要处理的请求:
url(r'^register$', RegisterView.as_view(), name='register'), # 注册
处理的代码:
from django.shortcuts import render,redirect
from django.core.urlresolvers import reverse
# 方向解析模块,reverse()函数传入'appname.urlname'进行反响解析
from django.core.mail import send_mail
# 发送email模块
from django.contrib.auth import authenticate, login
# 自动登录验证与保存登录信息模块
from django.views.generic import View
# 在定义视图类的时候需要集成View
from django.http import HttpResponse
from django.conf import settings
# 当你想使用settins中的一些属性时,你可以尝试这样导入settins
from user.models import User
# 导入models模块中的模型类
from celery_tasks.tasks import send_register_active_email
# 导入email发送处理模块
from itsdangerous import TimedJSONWebSignatureSerializer as Serializer
# 加密模块
from itsdangerous import SignatureExpired
# 加密模块的错误信息类当加密时间过期后在进行解密会报错
import re
import time
# /user/register
class RegisterView(View):
"""
注册
用处理类来处理请求,需要集成自View,在其中可以定义实力方法get,post等需要注意方法名必须为小写
"""
def get(self, request):
"""
显示注册页面
:param request:
:return:
"""
return render(request, 'register.html')
def post(self, request):
"""
进行注册处理
:param request:
:return:
"""
# 接收数据
username = request.POST.get('user_name')
password = request.POST.get('pwd')
email = request.POST.get('email')
allow = request.POST.get('allow')
# 进行数据校验
if not all([username, password, email]):
# 数据不完整
return render(request, '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, 'register.html', {'errmsg': '用户名已存在'})
# 进行业务处理: 进行用户注册
user = User.objects.create_user(username, email, password)
user.is_active = 0
user.save()
# 发送激活邮件,包含激活链接: http://127.0.0.1:8000/user/active/3
# 激活链接中需要包含用户的身份信息, 并且要把身份信息进行加密
# 加密用户的身份信息,生成激活token
serializer = Serializer(settings.SECRET_KEY, 3600)
info = {'confirm':user.id}
token = serializer.dumps(info) # bytes
token = token.decode()
# 发邮件
send_register_active_email.delay(email, username, token)
# 返回应答, 跳转到首页
return redirect(reverse('goods:index'))
因为发送email为了提高性能所以使用celery分布式处理任务
需要在本地安装celery
sudo pip3 install celery==3.1.25
sudo pip3 install django-celery==3.1.17
首先在项目主目录下创建celery_tasks python package
在celery_tasks包下创建tasks.py
在tasks中创建函数send_register_active_email()用来进行email的发送
在settins.py中添加如下配置
# 发送邮件配置
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 = 'hxx258456'
# 收件人看到的发件人
EMAIL_FROM = '天天生鲜<[email protected]>'
在tasks.py中添加如下代码
# 使用celery
from django.core.mail import send_mail
from django.conf import settings
from celery import Celery
import time
# 在任务处理者一端加这几句
# import os
# import django
# os.environ.setdefault("DJANGO_SETTINGS_MODULE", "dailyfresh.settings")
# django.setup()
# 创建一个Celery类的实例对象
# 使用redis处理任务队列
app = Celery('celery_tasks.tasks', broker='redis://172.16.179.130:6379/8')
# 定义任务函数
@app.task
def send_register_active_email(to_email, username, token):
'''发送激活邮件'''
# 组织邮件信息
subject = '天天生鲜欢迎信息'
message = ''
sender = settings.EMAIL_FROM
receiver = [to_email]
html_message = '%s, 欢迎您成为天天生鲜注册会员
请点击下面链接激活您的账户
http://192.168.0.129:8000/user/active/%s' % (username, token, token)
# html_message中的host:port要改为你项目启动时监听的地址和端口
send_mail(subject, message, sender, receiver, html_message=html_message)
time.sleep(5)
在user.views中创建处理 ActiveView类来处理注册请求
要处理的请求:
url(r'^active/(?P.*)$', ActiveView.as_view(), name='active'), # 用户激活
处理的代码:
from django.shortcuts import render,redirect
from django.core.urlresolvers import reverse
# 方向解析模块,reverse()函数传入'appname.urlname'进行反响解析
from django.core.mail import send_mail
# 发送email模块
from django.contrib.auth import authenticate, login
# 自动登录验证与保存登录信息模块
from django.views.generic import View
# 在定义视图类的时候需要集成View
from django.http import HttpResponse
from django.conf import settings
# 当你想使用settins中的一些属性时,你可以尝试这样导入settins
from user.models import User
# 导入models模块中的模型类
from celery_tasks.tasks import send_register_active_email
# 导入email发送处理模块
from itsdangerous import TimedJSONWebSignatureSerializer as Serializer
# 加密模块
from itsdangerous import SignatureExpired
# 加密模块的错误信息类当加密时间过期后在进行解密会报错
import re
import time
class ActiveView(View):
"""用户激活"""
def get(self, request, token):
"""进行用户激活"""
# 进行解密,获取要激活的用户信息
serializer = Serializer(settings.SECRET_KEY, 3600)
try:
info = serializer.loads(token)
# 获取待激活用户的id
user_id = info['confirm']
# 根据id获取用户信息
user = User.objects.get(id=user_id)
user.is_active = 1
user.save()
# 跳转到登录页面
return redirect(reverse('user:login'))
except SignatureExpired as e:
# 激活链接已过期
return HttpResponse('激活链接已过期')
启动celery异步式任务处理
拷贝一份项目代码,在tasks.py中对项目django项目进行初始化初始化代码如下
# 在任务处理者一端加这几句
import os
import django
# 进行项目初始化
# worker在接收到处理任务时,需要对django项目环境变量进行初始化,启动项目
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mydailyfresh.settings")
django.setup()
注意处理者一定要连接网络不然没有办法使用smtp发送邮件
进入到拷贝好的项目主目录下
celery -A celery_tasks.tasks worker -l info
启动celery -A 后添加你的任务处理转发者所在的目录
因为在register处理类的post方法中最后重定向到了goods.index视图所以需要对goodsapp进行配置
在goods下的models中配置相关模型类,来连接数据库
from django.db import models
from db.base_model import BaseModel
from tinymce.models import HTMLField
# Create your models here.
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
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
class Goods(BaseModel):
'''商品SPU模型类'''
name = models.CharField(max_length=20, verbose_name='商品SPU名称')
# 富文本类型:带有格式的文本
detail = HTMLField(blank=True, verbose_name='商品详情')
class Meta:
db_table = 'df_goods'
verbose_name = '商品SPU'
verbose_name_plural = verbose_name
class GoodsImage(BaseModel):
'''商品图片模型类'''
sku = models.ForeignKey('GoodsSKU', verbose_name='商品')
image = models.ImageField(upload_to='goods', verbose_name='图片路径')
class Meta:
db_table = 'df_goods_image'
verbose_name = '商品图片'
verbose_name_plural = verbose_name
class IndexGoodsBanner(BaseModel):
'''首页轮播商品展示模型类'''
sku = models.ForeignKey('GoodsSKU', verbose_name='商品')
image = models.ImageField(upload_to='banner', verbose_name='图片')
index = models.SmallIntegerField(default=0, verbose_name='展示顺序')
class Meta:
db_table = 'df_index_banner'
verbose_name = '首页轮播商品'
verbose_name_plural = verbose_name
class IndexTypeGoodsBanner(BaseModel):
'''首页分类商品展示模型类'''
DISPLAY_TYPE_CHOICES = (
(0, "标题"),
(1, "图片")
)
type = models.ForeignKey('GoodsType', verbose_name='商品类型')
sku = models.ForeignKey('GoodsSKU', verbose_name='商品SKU')
display_type = models.SmallIntegerField(default=1, choices=DISPLAY_TYPE_CHOICES, verbose_name='展示类型')
index = models.SmallIntegerField(default=0, verbose_name='展示顺序')
class Meta:
db_table = 'df_index_type_goods'
verbose_name = "主页分类展示商品"
verbose_name_plural = verbose_name
class IndexPromotionBanner(BaseModel):
'''首页促销活动模型类'''
name = models.CharField(max_length=20, verbose_name='活动名称')
url = models.URLField(verbose_name='活动链接')
image = models.ImageField(upload_to='banner', verbose_name='活动图片')
index = models.SmallIntegerField(default=0, verbose_name='展示顺序')
class Meta:
db_table = 'df_index_promotion'
verbose_name = "主页促销活动"
verbose_name_plural = verbose_name
在goods下的urls.py中
from django.conf.urls import url
from goods import views
urlpatterns = [
url(r'^$', views.index, name='index'), # 首页
]
在goods下的views.py中
from django.shortcuts import render
# Create your views here.
# http://127.0.0.1:8000
def index(request):
'''首页'''
return render(request, 'index.html')
因为在用户激活后会重定向到user.login视图中所以要在user.views中创建LoginView处理类
# /user/login
class LoginView(View):
'''登录'''
def get(self, request):
'''显示登录页面'''
# 判断是否记住了用户名
if 'username' in request.COOKIES:
username = request.COOKIES.get('username')
checked = 'checked'
else:
username = ''
checked = ''
# 使用模板
return render(request, 'login.html', {'username':username, 'checked':checked})
def post(self, request):
'''登录校验'''
# 接收数据
username = request.POST.get('username')
password = request.POST.get('pwd')
# 校验数据
if not all([username, password]):
return render(request, 'login.html', {'errmsg':'数据不完整'})
# 业务处理:登录校验
user = authenticate(username=username, password=password)
# 使用django官方登录函数认证传入用户名和密码如果认证成会返回一个user对象,否则返回一个None
if user is not None:
# 用户名密码正确
if user.is_active:
# 用户已激活
# 记录用户的登录状态
login(request, user)
# 跳转到首页
response = redirect(reverse('goods:index')) # HttpResponseRedirect
# 判断是否需要记住用户名
remember = request.POST.get('remember')
if remember == 'on':
# 记住用户名
response.set_cookie('username', username, max_age=7*24*3600)
else:
response.delete_cookie('username')
# 返回response
return response
else:
# 用户未激活
return render(request, 'login.html', {'errmsg':'账户未激活'})
else:
# 用户名或密码错误
return render(request, 'login.html', {'errmsg':'用户名或密码错误'})
使用redis保存django项目的缓存与session
首先要安装django-redis-sessions==0.5.6
pip3 install django-redis
安装完成后需要在settings中配置如下
# Django的缓存配置
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://127.0.0.1:6379/2",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
}
}
}
# 配置session存储
SESSION_ENGINE = "django.contrib.sessions.backends.cache"
SESSION_CACHE_ALIAS = "default"