1)注册页
2)登录页
3)用户中心
4)其他
1)首页
2)商品详情页
3)商品列表页
4)其他
SKU和SPU概念
SPU = Standard Product Unit (标准产品单位)
SPU 是商品信息聚合的最小单位,是一组可复用、易检索的标准化信息的集合,该集合描述 了一个产品的特性。通俗点讲,属性值、特性相同的商品就可以称为一个 SPU。
例如:iphone7 就是一个 SPU,与商家,与颜色、款式、套餐都无关。
SKU=stock keeping unit(库存量单位)
SKU 即库存进出计量的单位, 可以是以件、盒、托盘等为单位。
SKU 是物理上不可分割的最小存货单元。在使用时要根据不同业态,不同管理模式来处理。 在服装、鞋类商品中使用最多最普遍。
例如:纺织品中一个 SKU 通常表示:规格、颜色、款式。
django-admin startproject dailyfresh
修改DATABASES配置
__init__.py
import pymysql
pymysql.install_as_MySQLdb()
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': "fruit",
'USER':'root',
'PASSWORD':'123',
'HOST':'localhost',
'PORT':3306,
}
}
mysql> create database fruit
创建应用:执行< python manage.py startapp goods>
执行manage.py这个文件 startapp 表示创建应用 goods表示应用名
激活应用:在settings.py文件中,将goods应用加入 到INSTALLED_APPS选项中
模板:在目录下创建templates文件夹,在setting.py进行路径设置
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR,'templates')],
...
}
...
]
LANGUAGE_CODE = 'en-zh-hans'
TIME_ZONE = 'Asia/Shanghai'
两个url
project的urls.py
from django.contrib import admin
from django.urls import path
urlpatterns = [
path('admin/', admin.site.urls),
url('', include('goods.urls')),
]
goods的urls.py
在数据库中生成数据表:
生成迁移文件
python manage.py makemigrations
执行迁移文件
python manage.py migrate
1)安装
pip install django-tinymce==2.6.0
2)在test/settings.py为INSTALLED_APPS添加编辑器应用。
INSTALLED_APPS = (
...
'tinymce'
)
3)富文本编辑器配置在test/settings.py
TINYMCE_DEFAULT_CONFIG = {
'theme':'advanced',
'width':600,
'height':400,
}
4)在test/urls.py中配置编辑器url
urlpatterns = [
url('index/', views.index),
url(r'^tinymce/', include('tinymce.urls')), # 富文本编辑器
url(r'^', include('goods.urls')),
]
1)在goods/models.py中,定义模型的属性为HTMLField()类型。
from django.db import models
from tinymce.models import HTMLField
class GoodsInfo(models.Model):
gcontent=HTMLField()
2)在goods/admin.py
from django.contrib import admin
from goods.models import GoodsInfo
# Register your models here.
admin.site.register(GoodsInfo)
3)创建超级管理员用户
C:\Users\acer\Desktop\Fruit>python manage.py createsuperuser
Username (leave blank to use 'acer'): admin
Email address: admin@qq.com
Password:
Password (again):
Superuser created successfully.
4)运行
C:\Users\acer\Desktop\Fruit>python manage.py runserver
url访问:127.0.0.1:8000/admin/
settings.py 指定相对路径
import sys
sys.path.insert(0,os.path.join(BASE_DIR,'apps'))
创建
django-admin startproject dailyfresh
python manage.py startapp user
python manage.py startapp goods
python manage.py startapp cart
python manage.py startapp order
dailyfresh/settings.py,这里不用apps.user,因为指定了path
INSTALLED_APPS = (
'user', # 用户模块
'goods', # 商品模块
'cart', # 购物车模块
'order', # 订单模块
)
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR,'templates')],
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'dailyfresh',
'USER': 'root',
'PASSWORD': '123',
'HOST': 'localhost',
'PORT': 3306,
}
}
LANGUAGE_CODE = 'zh-hans'
TIME_ZONE = 'Asia/Shanghai'
STATIC_URL = '/static/'
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')]
dailyfresh/__init__.py
import pymysql
pymysql.install_as_MySQLdb()
dailyfresh/urls.py
urlpatterns = [
url(r'^admin/', include(admin.site.urls)),
url(r'^user/', include('user.urls', namespace='user')), # 用户模块
url(r'^cart/', include('cart.urls', namespace='cart')), # 购物车模块
url(r'^order/', include('order.urls', namespace='order')), # 订单模块
url(r'^', include('goods.urls', namespace='goods')), # 商品模块
]
namespace反向解析,动态生成路径
把这个urls.py拷贝到各个模块
from django.conf.urls import url
urlpatterns = [
]
建立db文件夹,base_model.py
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
dailyfresh/settings.py,富文本编辑器
INSTALLED_APPS = (
'tinymce', # 富文本编辑器
)
# 富文本编辑器配置
TINYMCE_DEFAULT_CONFIG = {
'theme': 'advanced',
'width':600,
'height':400,
}
dailyfresh/urls.py,富文本编辑器
urlpatterns = [
url(r'^tinymce/',include('tinymce.urls')), # 富文本编辑器
apps/goods/models.py
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
dailyfresh/settings.py
# django认证系统使用的模型类,替换默认的auth_user。
AUTH_USER_MODEL = 'user.User'
后面如果进行 python manage.py createsuperuser 则创建在user.User
创建数据库
create database dailyfresh;
生成迁移文件
python manage.py makemigrations
执行迁移
python manage.py migrate
auth_user已经没有了,变成了df_user
启动
python rmanage.py runserver
把register.html复制到templates目录下,然后将该目录下的路径改为{% load staticfiles %}
user/views.py
# /user/register
def register(request):
'''显示注册页面'''
return render(request, 'register.html')
user/urls.py
from django.conf.urls import url
from user import views
urlpatterns = [
url(r'^register$', views.register, name='register'), # 注册
]
register.html 点击注册跳转到/user/register_handl
<form method="post" action="/user/register_handle">
{% csrf_token %}
user/urls.py
urlpatterns = [
url(r'^register$', views.register, name='register'), # 注册
url(r'^register_handle$', views.register_handle, name='register_handle'), # 注册处理
]
user/views.py
from django.shortcuts import render,redirect
from django.core.urlresolvers import reverse
import re
from user.models import User
# Create your views here.
# /user/register
def register(request):
'''显示注册页面'''
return render(request, 'register.html')
def register_handle(request):
'''进行注册处理'''
# 接收数据
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: # get抛出的异常
# 用户名不存在
user = None
if user:
# 用户名已存在
return render(request,'register.html',{'errmsg':'用户名已存在'})
# 进行业务处理:进行用户注册,保存到数据库
user = User()
# user.username = username
# user.password = password
# user.save()
# 不用上面这么繁杂,可以使用Django的认证系统,语法
user = User.objects.create_user(username, email, password)
user.is_active = 0 # 用户未激活
user.save()
# 返回应答,跳转到首页
# reverse是反向解析函数
return redirect(reverse('goods:index')) # /goods/urls.py的name=index
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.
def index(request):
'''首页'''
return render(request,'index.html')
如何让显示注册页面和注册处理使用同一个url地址又区分?
普通点击是get请求
表单提交是post请求
通过判断请求方式
templates/register.html
<div class="reg_form clearfix">
<form method="post" action="/user/register">
{% csrf_token %}
user/views.py
from django.shortcuts import render,redirect
from django.core.urlresolvers import reverse
import re
from user.models import User
# Create your views here.
# /user/register
def register(request):
'''注册'''
if request.method == 'GET':
# 显示注册页面
return render(request, 'register.html')
else:
# 进行注册处理
# 接收数据
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: # get抛出的异常
# 用户名不存在
user = None
if user:
# 用户名已存在
return render(request, 'register.html', {'errmsg': '用户名已存在'})
# 进行业务处理:进行用户注册,保存到数据库
user = User()
# user.username = username
# user.password = password
# user.save()
# 不用上面这么繁杂,可以使用Django的认证系统,语法
user = User.objects.create_user(username, email, password)
user.is_active = 0 # 用户未激活
user.save()
# 返回应答,跳转到首页
# reverse是反向解析函数
return redirect(reverse('goods:index')) # /goods/urls.py的name=index
类视图 class
可以有效的提高代码复用,因为类是可以被继承的,假如我们已经写好了一个基于类的通用视图,要对其拓展功能,只需继承原本这个类视图即可。基于类的视图使用Python对象实现视图,它提供除函数视图之外的另一种方式。它们不替换基于函数的视图,但与基于函数的视图相比具有一定的区别和优势
user/views.py
from django.views.generic import View
class RegisterView(View):
'''注册'''
def get(self, request):
'''显示注册页面'''
return render(request,'register.html')
def post(self, request):
'''进行注册处理'''
# 进行注册处理
# 接收数据
username = request.POST.get('user_name')
....
user/urls.py
from user.views import RegisterView
urlpatterns = [
url(r'^register$',RegisterView.as_view(), name='register')
]
生成激活用户token,给注册邮箱发邮件,用户点击链接激活
pip install itsdangerous
user/views.py
from itsdangerous import TimedJSONWebSignatureSerializer as Serializer
from django.conf import settings
from django.core.mail import send_mail
SECRET_KEY 是 settings.py中django内部的,直接借用这个。 也可以自己设置的
# 发送激活邮件,包含激活链接:http://127.0.0.1:8000/user/active/user.id
# 激活链接中需要包含用户的身份信息,根据用户身份信息加密,id + token 加密
# itsdangerous,基于Django签名模块,还可以设置过期时间
# 加密用户的身份信息,生成激活token
serializer = Serializer(settings.SECRET_KEY, 600)
info = {'confirm':user.id}
token = serializer.dumps(info) # 返回的信息是Bytes字节流数据,要解码
token = token.decode('utf8')
# 发邮件,内置 django.core.mail
subject = '天天生鲜欢迎━(*`∀´*)ノ亻!'
message = ''
sender = settings.EMAIL_FROM
receiver = [email]
html_message = '%s, 欢迎您成为天天生鲜注册会员
请点击下面链接激活您的账户
http://127.0.0.1:8000/user/active/%s' %(username, token, token)
send_mail(subject, message, sender, receiver, html_message=html_message) # 第五个参数是html_message 已经指定了。
# 返回应答,跳转到首页 reverse是反向解析函数
return redirect(reverse('goods:index')) # /goods/urls.py的name=index
邮件在settings.py中的配置
# 发送邮件配置
# 发送邮件配置
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
# 发邮件的smpt服务地址
EMAIL_HOST = 'smtp.qq.com'
EMAIL_PORT = 25
# 发送邮件的邮箱
EMAIL_HOST_USER = '[email protected]'
# 在邮箱中设置的客户端授权密码
EMAIL_HOST_PASSWORD = 'ffffffffxxxasdasdasda'
# 收件人看到的发件人
EMAIL_FROM = '天天生鲜<[email protected]>'
用户激活注册
user/urls.py
from user.views import ActiveView
urlpatterns = [
url(r'^active/(?P.*)$' , ActiveView.as_view(), name='acitve'), # 用户激活
# 用<>包裹视图函数中的参数
url(r'^login$', LoginView.as_view(), name='login'), # 登录
]
user/views.py
from django.http import HttpResponse
from itsdangerous import TimedJSONWebSignatureSerializer as Serializer
from itsdangerous import SignatureExpired
# 用户注册激活
class ActiveView(View):
'''用户激活'''
def get(self, request, token):
'''进行用户激活'''
# 进行解密,获取要激活的用户信息
serializer = Serializer(settings.SECRET_KEY, 600)
try:
info = serializer.loads(token)
# 获取待激活用户的id
user_id = info['confirm']
# 根据id获取用户信息
user = User.objects.get(id=user_id)
user.is_active = 1
user.save()
# 跳转到登录页面 login.html
return redirect(reverse('user:login'))
except SignatureExpired as e:
# 激活链接已过期
return HttpResponse('激活链接已过期,再次点击发送激活链接')
用户注册流程小结
用户点击注册——》调用RegisterView,接收数据,校验——》校验通过,写入到数据库——》发送用户激活邮件(用户id进行加密),加密后的数据是字节流,先进行解码再发邮件链接,如果邮件内容含有HTML参数的话就要放在send_mail()的第五个参数那传参——》urls.py中active/(?P
获取token信息,调用ActiveView,修改数据库is_active=1代表激活 ——》激活成功跳转到登录页
优化:使用celery异步发邮件
Python Celery介绍
Celery是一个功能完备即插即用的任务队列。它使得我们不需要考虑复杂的问题,使用非常简单。
celery看起来似乎很庞大,本章节我们先对其进行简单的了解,然后再去学习其他一些高级特性。
celery适用异步处理问题,当发送邮件、或者文件上传,图像处理等等一些比较耗时的操作,我们可将其异步执行,这样用户不需要等待很久,提高用户体验。celery的特点是:
celery非常易于集成到一些web开发框架中。
任务队列(Broker),使用RabbitMQ或Redis。
Windows安装redis:https://www.runoob.com/redis/redis-install.html
celery_task\task.py
# 使用celery
from celery import Celery
from django.conf import settings
from django.core.mail import send_mail
import time
# 创建一个Celery类的实例对象
app = Celery('celery_task.tasks', broker='redis://127.0.0.1:6379/8')
# 定义任务函数,使用task方法进行装饰
@app.task
def send_register_active_mail(to_email, username, token):
'''发送激活邮件'''
# 组织邮件信息
subject = '天天生鲜欢迎━(*`∀´*)ノ亻!'
message = ''
sender = settings.EMAIL_FROM
receiver = [to_email]
html_message = '%s, 欢迎您成为天天生鲜注册会员
请点击下面链接激活您的账户
http://127.0.0.1:8000/user/active/%s' % (
username, token, token)
send_mail(subject, message, sender, receiver, html_message=html_message) # 第五个参数是html_message 已经指定了。
user\views.py
任务发出者
from celery_task.tasks import send_register_active_mail
class RegisterView(View):
def post(self, request):
......
# 发邮件,经过celery.task装饰后,就可以直接使用delay函数把任务放到任务队列
send_register_active_mail.delay(email, username, token)
任务队列 broker
app = Celery('celery_task.tasks', broker='redis://127.0.0.1:6379/8')
任务处理者 worker
\dailyfresh\celery_task\task.py
Windows 下 Pycharm django启动的话是不用加下面这几句的,因为已经在wsgi.py初始化了
针对的是放在Linux下,表示django环境初始化
# django环境的初始化
import os
import django
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "dailyfresh.settings")
django.setup()
Windows终端界面在这个project下的celery_task开启celery的worker作为后台接受任务:
\dailyfresh\celery_task>celery -A tasks worker -l info
单独启动celery,并没有启动django项目。加上面的初始化后就会启动了
Linux的话要把项目拉过去,然后pip install celery
——————————————————————————————————————
Windows下,启动worker,broker
borker
worker
——————————————————————————————————————
celery4不再支持windows,所以在Windows环境下使用请选择celery==3.1.18
报keyerror错误,搞了半天都没弄出来,卸载重装
重新安装pip install celery==3.1.18,启动项目,启动worker
from kombu.async.timer import Entry, Timer as Schedule, to_timestamp, logger
^
SyntaxError: invalid syntax
报错。太难了
https://blog.csdn.net/lelemom/article/details/87810038
celery使用流程
任务发出者发出任务——》任务放到任务队列——《任务处理器监听,收到任务,执行处理者也需要任务的代码
步骤:
celery_tasks文件夹下tasks.py
user文件夹下views.py
执行任务初始化tasks.py
import os
import django
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "dailyfresh.settings")
django.setup()
部署在Linux上
安装redis
https://www.cnblogs.com/autohome7390/p/6433956.html
安装python3
python虚拟环境
https://blog.csdn.net/bailiangcn/article/details/104644258 安装Python3后,默认python指2,python3指3
简单介绍python虚拟环境 virtualenv的使用 | 《Linux就该这么学》
https://www.linuxprobe.com/python-virtualenv-linux.html
python指python3,python2指python2
https://blog.csdn.net/haifeng10001/article/details/105170727
Linux启动
[root@aliyun dailyfresh]# celery -A celery_task.tasks worker -l info
https://blog.csdn.net/lpw_cn/article/details/103978909
彻底解决django 2.2与mysql兼容性问题(不用改源码)
————————————分割————————————————
继续往下走吧
user\views.py
class LoginView(View):
'''登录'''
def get(self, request):
'''显示登录页面'''
return render(request, 'login.html')
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.objects.get(username=username, password=password)
# 自动密码加密对比
user = authenticate(username=username, password=password)
if user is not None:
# 用户名已激活
if user.is_active:
# 用户已激活
# 保存记录用户的登陆状态
login(request, user) # login()使用Django的session框架来讲用户的ID保存在session中
①使用Redis存储Session
1)安装包
pip install django-redis-sessions==0.5.6
pip install django-redis-sessions
2)修改settings文件
SESSION_ENGINE ='redis_sessions.session' #配置作为redis存储
SESSION_REDIS_HOST = 'localhost' #配置主机地址
SESSION_REDIS_PORT = 6379 # 端口
SESSION_REDIS_DB = 0 # 数据库
SESSION_REDIS_PASSWORD = '' # 密码 没有可以为空
SESSION_REDIS_PREFIX = 'session' #唯一的标识码
②django-redis,pip install django-redis
settings.py
使Django支持Redis cache/session 后端的全功能组件
django-redis 中文文档
为了使用 django-redis , 你应该将你的 django cache setting 改成这样:
# django缓存配置
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://127.0.0.1:6379/9",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
}
}
}
# 配置session存储
SESSION_ENGINE = "django.contrib.sessions.backends.cache"
SESSION_CACHE_ALIAS = "default"
我用②方法,将session信息存到redis数据库中。配置Redis作为缓存和session存储。
login.html
<input type="text" name="username" class="name_input" value="{{ username }}" placeholder="请输入用户名">
<div class="user_error">输入错误</div>
<input type="checkbox" name="remember" {{ checked }}>
views.py
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.objects.get(username=username, password=password)
# 自动密码加密对比
user = authenticate(username=username, password=password)
if user is not None:
# 用户名已激活
if user.is_active:
# 用户已激活
# 保存记录用户的登陆状态
login(request, user) # login()使用Django的session框架来讲用户的ID保存在session中
# 获取登录后所要跳转到的地址
# 默认跳转到首页
next_url = request.GET.get('next', reverse('goods:index')) # None
# 跳转到首页
response = redirect(next_url)
# 判断是否需要记录用户名
remember = request.POST.get('remember')
if remember == 'on':
# 记住用户名
response.set_cookie('username', username, max_age=7 * 24 * 3600)
else:
response.delete_cookie('username')
return response
else:
# 用户未激活
return render(request, 'login.html', {'errmsg': '账户未激活'})
else:
# 用户名或密码错误
return render(request, 'login.html', {'errmsg': '用户名或密码错误'})
# 返回应答
不同的地方预留个块 {% block xxx %}{% endblock xxx %},有些有,有些无的也预留一个块。
可以重写继承后的
base.html、base_detail_list.html、base_no_cart.html、base_user_center.html
base.html
{# 首页 注册 登录 #}
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
{% load staticfiles %}
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
{# 网页标题内容块 #}
<title>{% block title %}{% endblock title %}title>
<link rel="stylesheet" type="text/css" href="{% static 'css/reset.css' %}">
<link rel="stylesheet" type="text/css" href="{% static 'css/main.css' %}">
{# 网页顶部引入文件块 #}
{% block topfiles %}{% endblock topfiles %}
head>
<body>
{# 网页顶部欢迎信息块 #}
{% block header_con %}
<div class="header_con">
<div class="header">
<div class="welcome fl">欢迎来到天天生鲜!div>
<div class="fr">
<div class="login_info fl">
欢迎您:<em>彬 Godem>
div>
<div class="login_btn fl">
<a href="login.html">登录a>
<span>|span>
<a href="register.html">注册a>
div>
<div class="user_link fl">
<span>|span>
<a href="user_center_info.html">用户中心a>
<span>|span>
<a href="cart.html">我的购物车a>
<span>|span>
<a href="user_center_order.html">我的订单a>
div>
div>
div>
div>
{% endblock header_con %}
{# 网页顶部搜索框块 #}
{% block search_bar %}
<div class="search_bar clearfix">
<a href="index.html" class="logo fl"><img src="{% static 'images/logo.png' %}">a>
<div class="search_con fl">
<input type="text" class="input_text fl" name="" placeholder="搜索商品">
<input type="button" class="input_btn fr" name="" value="搜索">
div>
<div class="guest_cart fr">
<a href="#" class="cart_name fl">我的购物车a>
<div class="goods_count fl" id="show_count">1div>
div>
div>
{% endblock search_bar %}
{# 网站主题内容块 #}
{% block body %}{% endblock body %}
<div class="footer">
<div class="foot_link">
<a href="#">关于我们a>
<span>|span>
<a href="#">联系我们a>
<span>|span>
<a href="#">招聘人才a>
<span>|span>
<a href="#">友情链接a>
div>
<p>CopyRight © 2020 CN理工水果铺 All Rights Reservedp>
<p>电话:1xxxxxxx 粤ICP备号-1p>
div>
{# 网页底部HTML元素块 #}
{% block bottom %}{% endblock bottom %}
{# 网页底部引入文件块 #}
{% block bottomfiles %}{% endblock bottomfiles %}
body>
html>
login.html
{% extends 'base.html' %}
{% load staticfiles %}
{% block title %}天天生鲜-登录{% endblock title %}
{% block header_con %}{% endblock header_con %}
{% block search_bar %}{% endblock search_bar %}
{% block body %}
<div class="login_top clearfix">
<a href="index.html" class="login_logo"><img src="{% static 'images/logo02.png' %}">a>
div>
<div class="login_form_bg">
<div class="login_form_wrap clearfix">
<div class="login_banner fl">div>
<div class="slogan fl">日夜兼程 · 急速送达div>
<div class="login_form fr">
<div class="login_title clearfix">
<h1>用户登录h1>
<a href="user/register">立即注册a>
div>
<div class="form_input">
<form method="post">
{% csrf_token %}
<input type="text" name="username" class="name_input" value="{{ username }}" placeholder="请输入用户名">
<div class="user_error">输入错误div>
<input type="password" name="pwd" class="pass_input" placeholder="请输入密码">
<div class="pwd_error">输入错误div>
<div class="more_input clearfix">
<input type="checkbox" name="remember" {{ checked }}>
<label>记住用户名label>
<a href="#">忘记密码a>
div>
<input type="submit" name="" value="登录" class="input_submit">
form>
div>
div>
div>
div>
{{ errmsg }}
{% endblock body %}
register.html
{% extends 'base.html' %}
{% load staticfiles %}
{% block title %}天天生鲜-注册{% endblock title %}
{% block topfiles %}
<script type="text/javascript" src="{% static 'js/jquery-1.12.4.min.js' %}">script>
<script type="text/javascript" src="{% static 'js/register.js' %}">script>
{% endblock topfiles %}
{% block header_con %}{% endblock header_con %}
{% block search_bar %}{% endblock search_bar %}
{% block body %}
<div class="register_con">
<div class="l_con fl">
<a class="reg_logo"><img src="{% static 'images/logo02.png' %}">a>
<div class="reg_slogan">足不出户 · 新鲜每一天div>
<div class="reg_banner">div>
div>
<div class="r_con fr">
<div class="reg_title clearfix">
<h1>用户注册h1>
<a href="login">登录a>
div>
<div class="reg_form clearfix">
<form method="post" action="/user/register">
{% csrf_token %}
<ul>
<li>
<label>用户名:label>
<input type="text" name="user_name" id="user_name">
<span class="error_tip">提示信息span>
li>
<li>
<label>密码:label>
<input type="password" name="pwd" id="pwd">
<span class="error_tip">提示信息span>
li>
<li>
<label>确认密码:label>
<input type="password" name="cpwd" id="cpwd">
<span class="error_tip">提示信息span>
li>
<li>
<label>邮箱:label>
<input type="text" name="email" id="email">
<span class="error_tip">提示信息span>
li>
<li class="agreement">
<input type="checkbox" name="allow" id="allow" checked="checked">
<label>同意”天天生鲜用户使用协议“label>
<span class="error_tip2">提示信息span>
li>
<li class="reg_sub">
<input type="submit" value="注 册" name="">
li>
ul>
form>
div>
div>
div>
{% endblock body %}
template\base_user_center.html
反向解析,动态生成
先写dailyfress\urls.py的namespace
再冒号
再写对应配置项user\urls.py的name
如:user:user
{# 用户中心3页面 #}
{% extends 'base_no_cart' %}
{% block title %}天天生鲜-用户中心{% endblock title %}
{% block page_title %}用户中心{% endblock page_title %}
{% block body %}
<div class="main_con clearfix">
<div class="left_menu_con clearfix">
<h3>用户中心h3>
<ul>
<li><a href="{% url 'user:user' %}" class="active">· 个人信息a>li>
<li><a href="{% url 'user:order' %}">· 全部订单a>li>
<li><a href="{% url 'user:address' %}">· 收货地址a>li>
ul>
div>
{# 用户中心右侧内容块 #}
{% block right_content %}{% endblock right_content %}
div>>
{% endblock body %}
template\user_center_info.html
{% extends 'base_user_center.html' %}
{% block right_content %}
{% endblock right_content %}
user\views.py
# /user
class UserInfoView(View):
'''用户中心-信息页'''
def get(self, request):
'''显示'''
return render(request, 'user_center_info.html')
# /user/order
class UserOrderView(View):...
# /user/address
class AddressView(View):...
user\urls.py
from user.views import UserInfoView, UserOrderView, AddressView
urlpatterns = [
url(r'^$', UserInfoView.as_view(), name='user'), # 用户中心-信息页
url(r'^order$', UserOrderView.as_view(), name='order'), # 用户中心-订单页
url(r'^address$', AddressView.as_view(), name='address'), # 用户中心-地址页
]
user\views.py
class UserInfoView(View):
'''用户中心-信息页'''
def get(self, request):
'''显示'''
# page='user'
return render(request, 'user_center_info.html', {'page':'user'})
base_user_center.html
<div class="left_menu_con clearfix">
<h3>用户中心h3>
<ul>
<li>· 个人信息a>li>
<li>· 全部订单a>li>
<li>· 收货地址a>li>
ul>
div>
6.4 登录后页面跳转
登录装饰器和登录后页面跳转
用户登录后才能访问用户中心,先进行登录判断
user\urls.py
from django.contrib.auth.decorators import login_required
urlpatterns = [
url(r'^$', login_required(UserInfoView.as_view()), name='user'), # 用户中心-信息页
]
login_required(UserInfoView.as_view())
调用login_required的返回值
如果用户没有登录是不会调用这个函数,会直接重定向到settings.LOGIN_URL
如果用户登录,则会调用这个函数,执行视图
浏览器访问测试:127.0.0.1:8000/user
但默认跳转的页面accounts/login不符合预期,需要自定义项目地址
settings.py。
# 配置登录url地址
LOGIN_URL = '/user/login'
还有后面的?next=/user/,因为login.html