目的:知道每天生鮮項目屬於那種商業模式css
B2B2C 是一種電子商務類型的網絡購物商業模式,B 是 BUSINESS 的簡稱,C 是 CUSTOMER 的簡稱,第一個 B 指的是商品或服務的供應商,第二個 B 指的是從事電子商務的企業,C 則是表示消費者。第一個 BUSINESS,並不只僅侷限於品牌供應商、影視製做公司和圖書出版商,任何的商品供應商或服務供應商都能能夠成爲第一個 BUSINESS;第二 B 是 B2B2C 模式的電子商務企業,經過統一的經營管理對商品和服務、消費者終端同時進行整合,是廣大供應商和消費 者之間的橋樑,爲供應商和消費者提供優質的服務,是互聯網電子商務服務供應商。C 表示 消費者,在第二個 B 構建的統一電子商務平臺購物的消費者。B2B2C 的來源於目前的 B2B、B2C 模式的演變和完善,把 B2C 和 C2C 完美地結合起來,經過 B2B2C 模式的電子商務企業構建本身的物流供應鏈系統,提供統一的服務。html
案例:京東商城、天貓商城前端
register.html
login.html
user_center_info.html
user_center_order.html
user_center_site.html
index.html
list.html
detail.html
cart.html
place_order.html
字段名 | 字段類型 | 字段選項 | 字段說明 |
---|---|---|---|
create_time | DateTimeField | auto_now_add=True | 建立時間 |
update_time | DateTimeField | auto_now=True | 更新時間 |
User
;表名:df_users
AbstractUser
,導包 from django.contrib.auth.models import AbstractUser
遷移前,須要在settings.py
文件中設置:AUTH_USER_MODEL = '應用.用戶模型類'
python
Address
;表名:df_address
User
模型類做爲外鍵約束地址信息屬於哪一個用戶字段名 | 字段類型 | 字段選項 | 字段說明 |
---|---|---|---|
id | IntegerField | primary_key=True | 主鍵字段 |
user | ForeignKey | 外鍵爲User模型 | 約束地址屬於哪一個用戶 |
receiver_name | CharField | max_length=20 | 收件人 |
receiver_mobile | CharField | max_length=11 | 聯繫電話 |
detail_addr | CharField | max_length=256 | 詳細地址 |
zip_code | CharField | max_length=6 | 郵政編碼 |
GoodsCategory
;表名:df_goods_category
字段名 | 字段類型 | 字段選項 | 字段說明 |
---|---|---|---|
id | IntegerField | primary_key=True | 主鍵字段 |
name | CharField | max_length=20 | 商品類別名稱 |
logo | CharField | max_length=100 | 商品類別標識 |
image | ImageField | upload_to="category" | 商品類別圖片 |
Goods
;表名:df_goods
字段名 | 字段類型 | 字段選項 | 字段說明 |
---|---|---|---|
id | IntegerField | primary_key=True | 主鍵字段 |
name | CharField | max_length=100 | 商品名稱 |
desc | HTMLField | blank=True | 商品詳細介紹 |
GoodsSKU
;表名:df_goods_sku
字段名 | 字段類型 | 字段選項 | 字段說明 |
---|---|---|---|
id | IntegerField | primary_key=True | 主鍵字段 |
category | ForeignKey | 外鍵爲GoodsCategory模型 | 約束該商品的類別 |
goods | ForeignKey | 外鍵爲Goods模型 | 約束該商品的SPU |
name | CharField | max_length=100 | 商品名稱 |
title | CharField | max_length=200 | 商品簡介 |
unit | CharField | max_length=10 | 銷售單位 |
price | DecimalField | max_digits=10, decimal_places=2 | 商品價格 |
stock | IntegerField | default=0 | 商品庫存 |
sales | IntegerField | default=0 | 商品銷量 |
default_image | ImageField | upload_to="goods" | 商品默認圖片 |
status | BooleanField | default=True | 是否上線 |
GoodsImage
;表名:df_goods_image
字段名 | 字段類型 | 字段選項 | 字段說明 |
---|---|---|---|
id | IntegerField | primary_key=True | 主鍵字段 |
sku | ForeignKey | 外鍵爲GoodsSKU模型 | 約束圖片屬於哪一個商品的 |
image | ImageField | upload_to="goods" | 商品圖片 |
IndexGoodsBanner
;表名:df_index_goods
字段名 | 字段類型 | 字段選項 | 字段說明 |
---|---|---|---|
id | IntegerField | primary_key=True | 主鍵字段 |
sku | ForeignKey | 外鍵爲GoodsSKU模型 | 約束該商品的sku |
image | ImageField | upload_to="banner" | 商品圖片 |
index | SmallIntegerField | default=0 | 輪播順序 |
IndexCategoryGoodsBanner
;表名:df_index_category_goods
字段名 | 字段類型 | 字段選項 | 字段說明 |
---|---|---|---|
id | IntegerField | primary_key=True | 主鍵字段 |
category | ForeignKey | 外鍵爲GoodsCategory模型 | 約束該商品類型 |
sku | ForeignKey | 外鍵爲GoodsSKU模型 | 約束該商品的sku |
display_type | SmallIntegerField | choices=DISPLAY_TYPE_CHOICES | 展現類型:圖片或標題 |
index | SmallIntegerField | default=0 | 展現順序 |
IndexCategoryGoodsBanner
;表名:df_index_category_goods
字段名 | 字段類型 | 字段選項 | 字段說明 |
---|---|---|---|
id | IntegerField | primary_key=True | 主鍵字段 |
name | CharField | max_length=50 | 活動名稱 |
url | URLField | 活動連接 | |
image | ImageField | upload_to="banner" | 活動商品圖片 |
index | SmallIntegerField | default=0 | 活動商品順序 |
OrderInfo
;表名:df_order_info
字段名 | 字段類型 | 字段選項 | 字段說明 |
---|---|---|---|
order_id | IntegerField | primary_key=True | 主鍵字段 |
user | ForeignKey | 外鍵爲User模型 | 下單用戶 |
address | ForeignKey | 外鍵爲Address模型 | 下單地址 |
total_count | IntegerField | default=1 | 商品總數 |
total_amount | DecimalField | max_digits=10, decimal_places=2 | 商品總金額 |
trans_cost | DecimalField | max_digits=10, decimal_places=2 | 運費 |
pay_method | SmallIntegerField | choices=PAY_METHOD_CHOICES | 支付方式,定義支付選項 |
status | SmallIntegerField | choices=ORDER_STATUS_CHOICES | 訂單狀態,自定義狀態 |
trade_id | CharField | max_length=100, unique=True | 訂單編號 |
OrderGoods
;表名:df_order_goods
字段名 | 字段類型 | 字段選項 | 字段說明 |
---|---|---|---|
id | IntegerField | primary_key=True | 主鍵字段 |
order | ForeignKey | 外鍵爲OrderInfo模型 | 約束是哪一個商品訂單 |
sku | ForeignKey | 外鍵爲GoodsSKU模型 | 約束訂單商品的sku |
count | IntegerField | default=1 | 訂單商品數量 |
price | DecimalField | max_digits=10, decimal_places=2 | 商品單價 |
comment | TextField | default="" | 評價信息 |
User
;表名:df_users
AbstractUser
,導包 from django.contrib.auth.models import AbstractUser
settings.py
文件中設置:AUTH_USER_MODEL = '應用.用戶模型類'
from django.db import models from django.contrib.auth.models import AbstractUser from utils.models import BaseModel from django.conf import settings from goods.models import GoodsSKU from itsdangerous import TimedJSONWebSignatureSerializer as Serializer class User(AbstractUser, BaseModel): """用戶""" class Meta: db_table = "df_users" def generate_active_token(self): """生成激活令牌""" serializer = Serializer(settings.SECRET_KEY, 3600) token = serializer.dumps({"confirm": self.id}) # 返回bytes類型 return token.decode() class Address(BaseModel): """地址""" user = models.ForeignKey(User, verbose_name="所屬用戶") receiver_name = models.CharField(max_length=20, verbose_name="收件人") receiver_mobile = models.CharField(max_length=11, verbose_name="聯繫電話") detail_addr = models.CharField(max_length=256, verbose_name="詳細地址") zip_code = models.CharField(max_length=6, verbose_name="郵政編碼") class Meta: db_table = "df_address"
from django.db import models from utils.models import BaseModel from tinymce.models import HTMLField class GoodsCategory(BaseModel): """商品類別表""" name = models.CharField(max_length=20, verbose_name="名稱") logo = models.CharField(max_length=100, verbose_name="標識") image = models.ImageField(upload_to="category", verbose_name="圖片") class Meta: db_table = "df_goods_category" verbose_name = "商品類別" # admin站點使用 verbose_name_plural = verbose_name def __str__(self): return self.name class Goods(BaseModel): """商品SPU表""" name = models.CharField(max_length=100, verbose_name="名稱") desc = HTMLField(verbose_name="詳細介紹", default="", blank=True) class Meta: db_table = "df_goods" verbose_name = "商品" verbose_name_plural = verbose_name def __str__(self): return self.name class GoodsSKU(BaseModel): """商品SKU表""" category = models.ForeignKey(GoodsCategory, verbose_name="類別") goods = models.ForeignKey(Goods, verbose_name="商品") name = models.CharField(max_length=100, verbose_name="名稱") title = models.CharField(max_length=200, verbose_name="簡介") unit = models.CharField(max_length=10, verbose_name="銷售單位") price = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="價格") stock = models.IntegerField(default=0, verbose_name="庫存") sales = models.IntegerField(default=0, verbose_name="銷量") default_image = models.ImageField(upload_to="goods", verbose_name="圖片") status = models.BooleanField(default=True, verbose_name="是否上線") class Meta: db_table = "df_goods_sku" verbose_name = "商品SKU" verbose_name_plural = verbose_name def __str__(self): return self.name class GoodsImage(BaseModel): """商品圖片""" sku = models.ForeignKey(GoodsSKU, verbose_name="商品SKU") image = models.ImageField(upload_to="goods", verbose_name="圖片") class Meta: db_table = "df_goods_image" verbose_name = "商品圖片" verbose_name_plural = verbose_name def __str__(self): return str(self.sku) class IndexGoodsBanner(BaseModel): """主頁輪播商品展現""" sku = models.ForeignKey(GoodsSKU, verbose_name="商品SKU") image = models.ImageField(upload_to="banner", verbose_name="圖片") index = models.SmallIntegerField(default=0, verbose_name="順序") class Meta: db_table = "df_index_goods" verbose_name = "主頁輪播商品" verbose_name_plural = verbose_name def __str__(self): return str(self.sku) class IndexCategoryGoodsBanner(BaseModel): """主頁分類商品展現""" DISPLAY_TYPE_CHOICES = ( (0, "標題"), (1, "圖片") ) category = models.ForeignKey(GoodsCategory, verbose_name="商品類別") sku = models.ForeignKey(GoodsSKU, verbose_name="商品SKU") display_type = models.SmallIntegerField(choices=DISPLAY_TYPE_CHOICES, verbose_name="展現類型") index = models.SmallIntegerField(default=0, verbose_name="順序") class Meta: db_table = "df_index_category_goods" verbose_name = "主頁分類展現商品" verbose_name_plural = verbose_name def __str__(self): return str(self.sku) class IndexPromotionBanner(BaseModel): """主頁促銷活動展現""" name = models.CharField(max_length=50, 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 def __str__(self): return self.name
from django.db import models from utils.models import BaseModel from users.models import User, Address from goods.models import GoodsSKU class OrderInfo(BaseModel): """訂單信息""" PAY_METHODS = { 1: "貨到付款", 2: "支付寶", } PAY_METHODS_ENUM = { "CASH": 1, "ALIPAY": 2 } PAY_METHOD_CHOICES = ( (1, "貨到付款"), (2, "支付寶"), ) ORDER_STATUS = { 1: "待支付", 2: "待發貨", 3: "待收貨", 4: "待評價", 5: "已完成", } ORDER_STATUS_ENUM = { "UNPAID": 1, "UNSEND": 2, "UNRECEIVED": 3, "UNCOMMENT": 4, "FINISHED": 5 } ORDER_STATUS_CHOICES = ( (1, "待支付"), (2, "待發貨"), (3, "待收貨"), (4, "待評價"), (5, "已完成"), ) order_id = models.CharField(max_length=64, primary_key=True, verbose_name="訂單號") user = models.ForeignKey(User, verbose_name="下單用戶") address = models.ForeignKey(Address, verbose_name="收穫地址") total_count = models.IntegerField(default=1, verbose_name="商品總數") total_amount = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="商品總金額") trans_cost = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="運費") pay_method = models.SmallIntegerField(choices=PAY_METHOD_CHOICES, default=1, verbose_name="支付方式") status = models.SmallIntegerField(choices=ORDER_STATUS_CHOICES, default=1, verbose_name="訂單狀態") trade_id = models.CharField(max_length=100, unique=True, null=True, blank=True, verbose_name="支付編號") class Meta: db_table = "df_order_info" class OrderGoods(BaseModel): """訂單商品""" order = models.ForeignKey(OrderInfo, verbose_name="訂單") sku = models.ForeignKey(GoodsSKU, verbose_name="訂單商品") count = models.IntegerField(default=1, verbose_name="數量") price = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="單價") comment = models.TextField(default="", verbose_name="評價信息") class Meta: db_table = "df_order_goods"
apps
:應用目錄,包含用戶、商品、訂單、購物車四個應用dailyfresh
:項目同名目錄static
:靜態文件目錄,包含images、css、js、html ...templates
:模板文件目錄utils
:實用用工具類,包含模型基類 ...注意:該項目的應用在apps文件目錄下,不是在項目根目錄下mysql
# 以用戶模塊爲例 cd Desktop/dailyfresh/apps/ python ../manage.py startapp users
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'dailyfresh', 'HOST': '192.168.24.136', # MySQL數據庫地址 'PORT': '3306', 'USER': 'root', 'PASSWORD': 'mysql', } }
users
、goods
、orders
應用中定義好對應的模型類
cart
應用中暫時不定義模型類,其中的數據是使用redis數據庫維護的users
應用中的模型類User
是使用Django自帶的用戶認證系統維護的nginx
遷移前,須要在settings.py
文件中設置:AUTH_USER_MODEL = '應用.用戶模型類'
git
settings.py
中設置AUTH_USER_MODEL
時,編碼規則爲'應用.用戶模型類'
apps/
文件目錄下,爲了保證正確的編碼,咱們須要增長導包路徑同時,爲了配合AUTH_USER_MODEL
的配置,應用的安裝直接使用users
,不要使用apps.users
web
import sys sys.path.insert(1, os.path.join(BASE_DIR, 'apps'))
STATIC_URL = '/static/' STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')]
users
中
def register(request): """返回註冊頁面""" return render(request, 'register.html')
項目中的urls.pyredis
urlpatterns = [ url(r'^admin/', include(admin.site.urls)), # 訪問用戶模塊的路由配置 url(r'^users/', include('apps.users.urls',namespace='users')), ]
users應用中的urls.pysql
urlpatterns = [from django.conf.urls import url from apps.users import views urlpatterns = [ # 註冊 url(r'^register$', views.register, name='register'), ]
register
後面是否加/
,根據公司需求而定
思考:一個register視圖,是否能夠處理兩種邏輯?好比get和post請求邏輯。
def register(request): """處理註冊""" # 獲取請求方法,判斷是GET/POST請求 if request.method == 'GET': # 處理GET請求,返回註冊頁面 return render(request, 'register.html') else: # 處理POST請求,實現註冊邏輯 return HttpResponse('這裏實現註冊邏輯')
View
from django.views.generic import View
或 from django.views.generic.base import View
應用/urls.py
中配置路由時,使用類視圖的as_view()
方法 ,將類視圖轉成視圖函數dispatch()
方法將具體的request分發至對應請求方式的處理方法中,好比get、post ...class RegisterView(View): """類視圖:處理註冊""" def get(self, request): """處理GET請求,返回註冊頁面""" return render(request, 'register.html') def post(self, request): """處理POST請求,實現註冊邏輯""" return HttpResponse('這裏實現註冊邏輯')
urlpatterns = [ # 視圖函數:註冊 # url(r'^register$', views.register, name='register'), # 類視圖:註冊 url(r'^register$', views.RegisterView.as_view(), name='register'), ]
若是發現模板中,靜態文件是之前端的方式處理的,Django程序猿在使用時,須要修改爲Django的處理方式
提示:用戶註冊邏輯中,包含了用戶郵件激活邏輯
class RegisterView(View): """類視圖:處理註冊""" def get(self, request): """處理GET請求,返回註冊頁面""" return render(request, 'register.html') def post(self, request): """處理POST請求,實現註冊邏輯""" return HttpResponse('這裏實現註冊邏輯')
class RegisterView(View): """類視圖:處理註冊""" def get(self, request): """處理GET請求,返回註冊頁面""" return render(request, 'register.html') def post(self, request): """處理POST請求,實現註冊邏輯""" # 獲取註冊請求參數 user_name = request.POST.get('user_name') password = request.POST.get('pwd') email = request.POST.get('email') allow = request.POST.get('allow') return HttpResponse('這裏實現註冊邏輯')
class RegisterView(View): """類視圖:處理註冊""" def get(self, request): """處理GET請求,返回註冊頁面""" return render(request, 'register.html') def post(self, request): """處理POST請求,實現註冊邏輯""" # 獲取註冊請求參數 user_name = request.POST.get('user_name') password = request.POST.get('pwd') email = request.POST.get('email') allow = request.POST.get('allow') # 參數校驗:缺乏任意一個參數,就不要在繼續執行 if not all([user_name, password, email]): return redirect(reverse('users:register')) # 判斷郵箱 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': '沒有勾選用戶協議'}) return HttpResponse('這裏實現註冊邏輯')
class RegisterView(View): """類視圖:處理註冊""" def get(self, request): """處理GET請求,返回註冊頁面""" return render(request, 'register.html') def post(self, request): """處理POST請求,實現註冊邏輯""" # 獲取註冊請求參數 user_name = request.POST.get('user_name') password = request.POST.get('pwd') email = request.POST.get('email') allow = request.POST.get('allow') # 參數校驗:缺乏任意一個參數,就不要在繼續執行 if not all([user_name, password, email]): return redirect(reverse('users:register')) # 判斷郵箱 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: # 隱私信息須要加密,能夠直接使用django提供的用戶認證系統完成 user = User.objects.create_user(user_name, email, password) except db.IntegrityError: return render(request, 'register.html', {'errmsg': '用戶已註冊'}) # 手動的將用戶認證系統默認的激活狀態is_active設置成False,默認是True user.is_active = False # 保存數據到數據庫 user.save() return HttpResponse('這裏實現註冊邏輯')
查看保存用戶註冊信息結果
# 查詢出數據,並以列表形式展現 select * from df_users \G
1.服務器激活郵件如何發送?
激活郵件須要異步發送,集成Celery模塊能夠實現異步任務
2.服務器如何才能知道是誰要激活?
http://127.0.0.1:8000/users/active/user_id
token用於客戶端向服務器發送激活請求時,服務器對用戶身份的識別
class ActiveView(View): """郵件激活""" def get(self, request, token): """處理激活請求""" pass
# 郵件激活 url(r'^active/(?P<token>.+)$', views.ActiveView.as_view(), name='active'),
1.安裝 itsdangerous 模塊
pip install itsdangerous
2.生成用戶激活token的方法封裝在User模型類中
loads()解出token字符串,獲得用戶id明文
from itsdangerous import TimedJSONWebSignatureSerializer as Serializer from django.conf import settings class User(AbstractUser, BaseModel): """用戶""" class Meta: db_table = "df_users" def generate_active_token(self): """生成激活令牌""" serializer = Serializer(settings.SECRET_KEY, 3600) token = serializer.dumps({"confirm": self.id}) # 返回bytes類型 return token.decode()
3.生成激活token方法的調用
token = user.generate_active_token()
簽名過時的異常
提示:Django須要知道是誰在幫它發郵件,因此須要提早配置郵箱服務器
settings.py
中配置郵件服務器參數dailyfreshzxc@yeah.net
發件人郵箱受權
settings.py
中配置郵件服務器參數
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' # 導入郵件模塊 EMAIL_HOST = 'smtp.yeah.net' # 發郵件主機 EMAIL_PORT = 25 # 發郵件端口 EMAIL_HOST_USER = 'dailyfreshzxc@yeah.net' # 受權的郵箱 EMAIL_HOST_PASSWORD = 'dailyfresh123' # 郵箱受權時得到的密碼,非註冊登陸密碼 EMAIL_FROM = '每天生鮮<dailyfreshzxc@yeah.net>' # 發件人擡頭
from django.core.mail import send_mail from django.conf import settings def send_active_email(to_email, user_name, token): """封裝發送郵件方法""" subject = "每天生鮮用戶激活" # 標題 body = "" # 文本郵件體 sender = settings.EMAIL_FROM # 發件人 receiver = [to_email] # 接收人 html_body = '<h1>尊敬的用戶 %s, 感謝您註冊每天生鮮!</h1>' \ '<br/><p>請點擊此連接激活您的賬號<a href="http://127.0.0.1:8000/users/active/%s">' \ 'http://127.0.0.1:8000/users/active/%s</a></p>' % (user_name, token, token) send_mail(subject, body, sender, receiver, html_message=html_body)
3.安裝Celery
# 進入虛擬環境 pip install celery
4.Celery組成結構
Celery組成結構是生產者消費者模型的一種體現
調用python的send_mail()將激活郵件發送出去
from celery import Celery from django.core.mail import send_mail from django.conf import settings # 建立celery應用對象 app = Celery('celery_tasks.tasks', broker='redis://192.168.243.191:6379/4') @app.task def send_active_email(to_email, user_name, token): """發送激活郵件""" subject = "每天生鮮用戶激活" # 標題 body = "" # 文本郵件體 sender = settings.EMAIL_FROM # 發件人 receiver = [to_email] # 接收人 html_body = '<h1>尊敬的用戶 %s, 感謝您註冊每天生鮮!</h1>' \ '<br/><p>請點擊此連接激活您的賬號<a href="http://127.0.0.1:8000/users/active/%s">' \ 'http://127.0.0.1:8000/users/active/%s</a></p>' %(user_name, token, token) send_mail(subject, body, sender, receiver, html_message=html_body)
做爲中間人,咱們有幾種方案可選擇:
1.RabbitMQ
使用RabbitMQ的細節參照如下連接: http://docs.celeryproject.org/en/latest/getting-started/brokers/rabbitmq.html#broker-rabbitmq
若是使用的是Ubuntu或者Debian發行版的Linux,能夠直接經過命令安裝RabbitMQ: sudo apt-get install rabbitmq-server
2.Redis
Celery服務器建立worker步驟
1.把項目代碼拷貝一份到ubuntu虛擬機中
做用:讓Celery的worker可以加載Django配置環境
import os os.environ["DJANGO_SETTINGS_MODULE"] = "dailyfresh.settings" # 放到Celery服務器上時添加的代碼 import django django.setup()
2.終端建立worker
celery -A celery_tasks.tasks worker -l info
3.開啓redis-server,查看broker
4.測試發郵件
5.查看worker收到的異步任務消息
class RegisterView(View): """類視圖:處理註冊""" def get(self, request): """處理GET請求,返回註冊頁面""" return render(request, 'register.html') def post(self, request): """處理POST請求,實現註冊邏輯""" # 獲取註冊請求參數 user_name = request.POST.get('user_name') password = request.POST.get('pwd') email = request.POST.get('email') allow = request.POST.get('allow') # 參數校驗:缺乏任意一個參數,就不要在繼續執行 if not all([user_name, password, email]): return redirect(reverse('users:register')) # 判斷郵箱 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: # 隱私信息須要加密,能夠直接使用django提供的用戶認證系統完成 user = User.objects.create_user(user_name, email, password) except db.IntegrityError: return render(request, 'register.html', {'errmsg': '用戶已註冊'}) # 手動的將用戶認證系統默認的激活狀態is_active設置成False,默認是True user.is_active = False # 保存數據到數據庫 user.save() # 生成激活token token = user.generate_active_token() # celery發送激活郵件:異步完成,發送郵件不會阻塞結果的返回 send_active_email.delay(email, user_name, token) # 返回結果:好比重定向到首頁 return redirect(reverse('goods:index'))
class ActiveView(View): """用戶激活""" def get(self, request, token): # 建立序列化器 serializer = Serializer(settings.SECRET_KEY, 3600) try: # 使用序列化器,獲取token明文信息,須要判斷簽名是否過時 result = serializer.loads(token) except SignatureExpired: # 提示激活連接已過時 return HttpResponse('激活連接已過時') # 獲取用戶id user_id = result.get('confirm') try: # 查詢須要激活的用戶,須要判斷查詢的用戶是否存在 user = User.objects.get(id=user_id) except User.DoesNotExist: # 提示用戶不存在 return HttpResponse('用戶不存在') # 設置激活用戶的is_active爲Ture user.is_active = True # 保存數據到數據庫 user.save() # 響應信息給客戶端 return redirect(reverse('users:login'))
login(request, user)
django_session
數據庫表中django-redis-sessions
來輔助完成django-redis
來輔助完成(功能更加豐富,推薦使用)
class LoginView(View): """登錄""" def get(self, request): """響應登錄頁面""" return render(request, 'login.html') def post(self, request): """處理登錄邏輯""" # 獲取用戶名和密碼 user_name = request.POST.get('username') password = request.POST.get('pwd') # 參數校驗 if not all([user_name, password]): return redirect(reverse('users:login')) # django用戶認證系統判斷是否登錄成功 user = authenticate(username=user_name, password=password) # 驗證登錄失敗 if user is None: # 響應登陸頁面,提示用戶名或密碼錯誤 return render(request, 'login.html', {'errmsg':'用戶名或密碼錯誤'}) # 驗證登錄成功,並判斷是不是激活用戶 if user.is_active is False: # 若是不是激活用戶 return render(request, 'login.html', {'errmsg':'用戶未激活'}) # 使用django的用戶認證系統,在session中保存用戶的登錄狀態 login(request, user) # 登錄成功,重定向到主頁 return redirect(reverse('goods:index'))
如下配置是配合
Django用戶認證系統
的login()
方法,完成session信息
存儲
1.安裝django-redis
pip install django-redis
2.settings.py
文件配置django-redis
# 緩存 CACHES = { "default": { "BACKEND": "django_redis.cache.RedisCache", "LOCATION": "redis://192.168.243.193:6379/5", "OPTIONS": { "CLIENT_CLASS": "django_redis.client.DefaultClient", } } } # Session # http://django-redis-chs.readthedocs.io/zh_CN/latest/#session-backend SESSION_ENGINE = "django.contrib.sessions.backends.cache" SESSION_CACHE_ALIAS = "default"
登錄-->沒有記住用戶名-->退出瀏覽器-->再打開網頁-->狀態沒有保持-->須要再登錄
登錄-->記住用戶名-->退出瀏覽器-->再打開網頁-->狀態依然保持-->不用再登錄直接訪問網站
結論:記住用戶就是設置session有效期
request.session.set_expiry(value)
# 獲取是否勾選'記住用戶名' remembered = request.POST.get('remembered') # 登入用戶 login(request, user) # 判斷是不是否勾選'記住用戶名' if remembered != 'on': # 沒有勾選,不須要記住cookie信息,瀏覽會話結束後過時 request.session.set_expiry(0) else: # 已勾選,須要記住cookie信息,兩週後過時 request.session.set_expiry(None) # 響應結果: 重定向到主頁 return redirect(reverse('goods:index'))
結論:從request中能夠獲取到user信息,request.user
class LogoutView(View): """退出登陸""" def get(self, request): """處理退出登陸邏輯""" # 由Django用戶認證系統完成:須要清理cookie和session,request參數中有user對象 logout(request) # 退出後跳轉:由產品經理設計 return redirect(reverse('goods:index'))
配置URL正則
url(r'^logout$', views.LogoutView.as_view(), name='logout'),