Django項目之Web端電商網站的實戰開發(二)

說明:該篇博客是博主一字一碼編寫的,實屬不易,請尊重原創,謝謝你們!css

接着上一篇博客繼續往下寫 :http://www.javashuo.com/article/p-hjnmskdq-hs.htmlhtml

目錄前端

一丶用戶註冊python

二丶用戶登陸mysql


一丶用戶註冊

1.顯示用戶註冊頁面redis

  • step1 在static目錄下將register.html文件拷貝到templates模板目錄下

  • step2 在df_user模塊下的views視圖中定義一個register函數,定義這個函數的路由正則匹配爲/user/register,顯示用戶註冊頁面
# /user/register
def register(request):
    """顯示註冊頁面"""
    return render(request, "register.html")
  • step3 在df_user模塊下的urls地址中配置註冊頁面正則規則,以及調用視圖函數中的register函數
urlpatterns = [
    url(r"^register$", views.register, name="register")  # 註冊頁
]

  • step5 出現上面這種狀況是,頁面所須要的圖片和css以及js文件路徑錯誤404,由於此時的register.html文件放在了templates模板目錄下,因此須要在register.html中動態獲取路徑,需導入靜態資源,而後修改每一個連接,由於以前在settings配置文件中配置了靜態文件URL爲/static/因此這裏只須要寫以後的路徑便可
{% load staticfiles %}
<head>
	<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
	<title>每天生鮮-註冊</title>
	<link rel="stylesheet" type="text/css" href="{% static 'css/reset.css' %}">
	<link rel="stylesheet" type="text/css" href="{% static 'css/main.css' %}">
  • step6 刷新頁面,成功顯示出頁面內容

2.定義註冊頁面表單數據視圖函數sql

  • step1 首先註冊頁面數據是以POST請求方式向服務器發送,那麼在register.html文件中找到form表單標籤,編寫用戶點擊註冊按鈕後向服務器請求的url地址
<form method="post" action="/user/register_handle">
  • step2 在django中發送POST請求表單數據,防止跨站攻擊需在form標籤下加上{% csrf_token %}
<form method="post" action="/user/register_handle">
    {% csrf_token %}
  • step3 在df_user/views視圖函數中定義register_handle方法,用於處理註冊頁面數據
# /user/register/handle
def register_handle(request):
    """處理用戶註冊數據"""
    pass
  • step4 在在df_user/urls路由地址中定義register_handle視圖函數正則匹配規則
url(r"^register_handle$", views.register_handle, name="register_handle")  # 註冊數據處理

3.視圖函數register_handle代碼邏輯實現數據庫

  • step1 接收註冊表單數據
username = request.POST.get("user_name")
password = request.POST.get("pwd")
email = request.POST.get("email")
allow = request.POST.get("allow")
  • step2 判斷用戶傳遞過來的數據是否存在,不存在返回錯誤信息提示
if not all([username, password, email]):
    return render(request, "register.html", {"error_msg":"數據不完整"})
  • step3 判斷用戶填寫的郵箱是否爲正確郵箱
if not re.match(r"^[a-z0-9][\w.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$", email):
    return render(request, "register.html", {"error_msg":"郵箱格式不正確"})
  • step4 判斷用戶註冊時是否勾選贊成,贊成後該字段POST請求參數爲on
if allow != "on":
    return render(request, "register.html", {"error_msg":"請勾選贊成"})
  • step5 進行用戶註冊,將數據保存在數據庫用戶名中, 由於在執行遷移文件時,在settings中配置了django認證系統指定的模型類爲df_user.User 因此能夠不使用傳統方式向類中添加屬性再保存到數據庫,而是直接使用django認證系統封裝好的create_user函數將數據直接保存到數據庫
user = User.objects.create_user(username, email, password)
  • step6 註冊成功後,使用反向解析跳轉到首頁 reverse(根基urls中的主頁的namespace:goods模塊中的urls主頁的name)
return redirect(reverse("goods:index"))
  • step7 爲了顯示主頁,將static目錄下的index.html文件拷貝到templates目錄下,並加載靜態資源文件{% load staticfiles %}修改index.html中的靜態文件路徑,這個頁面的地址比較多,體力活

  • step8 在df_goods/views中定義index視圖函數
# http://127.0.0.1:8000
def index(request):
    """顯示首頁"""
    return render(request, "index.html")
  • step9 緊接着在df_goods/urls進行正則路由配置
urlpatterns = [
    url(r"^$", views.index, name="index"),  # 首頁
]
  • step10 查看數據庫中的用戶信息表

說明:前端註冊頁面使用js對密碼長度和兩次密碼是否一致以及郵箱地址是否贊成都進行了校驗django

  • step12 當點擊註冊按鈕時,此時在會跳轉到form表單中的action地址(/user/register_handle),匹配df_user/urls中的正則而後調用df_user/views中的register_handle視圖函數,處理完數據後最終重定向到主頁(index.html)

  • step13 查看數據庫df_user表數據,由於使用了django認證系統也就通俗點說在df_user/models中的User類繼承了AbstractUser類,因此django的認證系統已經將用戶註冊時填寫的密碼進行加密處理後存到數據庫,這樣咱們就不用在視圖函數中獲取密碼並加密而後再保存到數據庫表中

  • step14 django認證系統默認用戶表字段is_active爲1(激活),因此這裏須要進行設置爲0(未激活)
user.is_active = 0
user.save()
  •  step15 再此回到註冊頁面,進行另外一個用戶註冊,驗證上一步is_active默認是否爲未激活狀態

  • step16 使用已經註冊過的帳號進行註冊,查看django認證系統錯誤提示

  • step17 提示信息爲用戶名已存在,但這樣的顯示頁面不是咱們想要的 

  • step18 在進行用戶註冊以前,須要判斷用戶註冊的用戶名是否存在
try:
    user = User.objects.get(username=username)
except User.DoesNotExist:
    """若是出現該異常說明用戶名不存在,則讓user對象爲空"""
    user = None

# 若是user對象存在,則表示用戶名已存在,返回錯誤提示信息
if user:
    return render(request, "register.html", {"error_msg":"用戶名已存在"})

4.測試數據不合法的狀況下,提示錯誤信息windows

  • step1 在register.html中form標籤下添加error_msg變量
<span style="color: red">{{ error_msg }}</span>
  • step2 註冊已存在的用戶名cdtaogang,查看錯誤提示

  • step3 填寫錯誤郵箱地址,而後點擊註冊

  • step4 不填寫任何數據直接進行註冊

5.註冊優化處理,讓顯示註冊頁面和註冊數據處理爲同一個url地址(/user/register) ,由於顯示註冊頁面爲get請求,而註冊數據處理爲post請求,能夠根據請求方式不一樣來使用同一個url地址

  • step1 在register.html中將form表單action地址修改成/user/register與顯示頁面地址一致
<form method="post" action="/user/register">
  • step2 在df_user/views中的register視圖函數中進行請求方式判斷
# Create your views here.
# /user/register
def register(request):
    """註冊"""
    # 當請求方式爲get時表示請求註冊頁面,反之爲處理用戶註冊數據
    if request.method == "GET":
        """顯示註冊頁面"""
        return render(request, "register.html")
    else:
        """處理用戶註冊數據"""
  • step3 註冊一個新用戶

  • step4 查看數據庫用戶表

 6.使用類視圖來區分用戶請求

  • step1 在df_user/views視圖中定義RegisterView視圖類,在這個類中定義註冊所需的get方法以及post方法,這個方法名必須等同於請求方式名
from django.views.generic import View


# /user/register
class RegisterView(View):
    """註冊"""
    def get(self, request):
        """顯示註冊頁面"""
        return render(request, "register.html")

    def post(self, request):
        """處理用戶註冊數據"""
  • step2 在df_user/urls中需導入RegisterView類,並調用這個類所屬父類View中的as_view方法來根據請求方式調用對應的方法完成代碼邏輯
urlpatterns = [

    url(r"^register$", RegisterView.as_view(), name="register"),  # 註冊
]
  • step3 刷新註冊頁,進行新用戶註冊

7. 生成用戶激活郵件中的token,當在不錯的網站進行用戶註冊成功後,會想用戶註冊填寫的郵箱地址發送帳戶激活的郵件,在這個郵件內容中會有一個激活的連接地址,而且會提示用戶請在2小時內進行激活,2小時後失效;定義激活連接爲http://127.0.0.1:8000/user/active/用戶id若是在連接地址明文顯示用戶的id值的話,就會出現某些懂技術的用戶,修改連接地址中的用戶id,就頗有可能去激活其餘用戶,因此須要將連接地址中的用戶id值進行加密並設置密鑰的有效期

  • step1 安裝itsdangerous模塊,使用改模塊生成咱們所需的token
pip install itsdangerous
  • step2 致使該模塊中的TimedJSONWebSignatureSerializer類
from itsdangerous import TimedJSONWebSignatureSerializer as Serializer
  • step3 加密用戶id,生成激活的token
serializer = Serializer(settings.SECRET_KEY, 3600)  # 有效期1小時
info = {"confirm":user.id}
token = serializer.dumps(info)

8.使用django內置函數發送郵件(這個QQ郵箱爲博主小小小小號)

  • step1 這裏有QQ郵箱爲例,進入QQ郵箱設置,開啓POP3/SMTP服務

  • step2 使用提示的密保手機向指定的號碼發送指定內容來完成驗證

  • step3 發送成功後,顯示出受權碼,記住此受權碼後,點擊保存設置

  •  step4 在settings配置文件中進行發送郵件配置
# 發送郵件配置
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.qq.com'
EMAIL_PORT = 25
#發送郵件的郵箱
EMAIL_HOST_USER = '2384005622@qq.com'
#在郵箱中設置的客戶端受權密碼
EMAIL_HOST_PASSWORD = '受權碼'
#收件人看到的發件人
EMAIL_FROM = '每天生鮮<2384005622@qq.com>'
  • step5 在df_user/view視圖中導入django內置函數中的send_mail方法
from django.core.mail import send_mail
  • step6 在RegisterView類中調用send_mail方法發送郵件
subject = "每天生鮮歡迎你" # 郵件標題
message = "how are you"  # 郵件正文
sender = settings.EMAIL_FROM  # 發件人
receiver = [email]  # 收件人
send_mail(subject, message, sender, receiver)
  • step7 註冊一個新用戶

  • step8 登陸註冊時的郵箱,查看收件箱

  • step9 向郵箱發送帳戶激活連接地址,htmp_message參數爲渲染html標籤後再進行內容發送
subject = "每天生鮮歡迎你" # 郵件標題
message = ''  # 郵件正文
sender = settings.EMAIL_FROM  # 發件人
receiver = [email]  # 收件人
html_message = """
           <h1>%s  恭喜您成爲每天生鮮註冊會員</h1><br/><h3>請您在1小時內點擊如下連接進行帳戶激活</h3><a href="http://127.0.0.1:8000/user/active/%s">http://127.0.0.1:8000/user/active/%s</a>
"""  %  (username, token, token)
send_mail(subject, message, sender, receiver, html_message=html_message)
  •  step10 註冊一個新用戶

  • step11 查看郵件

  • step12 點擊郵件中的連接地址

9.用戶註冊激活

  • step1 在df_user/views視圖中定義ActiveView類,在這個類中定義get方法,用於處理用戶激活
# /user/active/......
class ActiveView(View):
    """帳戶激活"""
    def get(self, request, token):
        """進行用戶激活"""
        pass
  •  step2 獲取加密的serializer對象
serializer = Serializer(settings.SECRET_KEY, 3600)
  • step3 解密token,獲取要激活的用戶信息,首先須要導入itsdangerous包中的SignatureExpired類來處理超時異常,因此接下里的代碼須要寫到try裏面
try:
    info = serializer.loads(token)
    # 獲取用戶id
    user_id = info['confirm']
    # 根據用戶id 獲取該用戶對象
    user = User.objects.get(id=user_id)
    # 設置該用戶對象中的is_active字段的值爲1
    user.is_active = 1
    user.save()
    # 使用反向解析跳轉到登陸頁
    return redirect(reverse("user:login"))
except SignatureExpired as e:
    # 出現異常表示連接失效
    return HttpResponse("激活連接已過時")
  • step4 建立LoginView類並在這個類中定義get方法用於顯示登陸頁
# /user/login
class LoginView(View):
    """登陸"""
    def get(self, request):
        """顯示登陸頁"""
        return render(request, "login.html")
  • step5 在df_user/urls中定義以上兩個類視圖對應的正則以及對應的方法調用,將static目錄下的login.html文件拷貝到templates目錄下
url(r"^active/(?P<token>.*)$", ActiveView.as_view(), name="active"),  # 帳戶激活
url(r"^login$", LoginView.as_view(), name="login"),  # 登陸
  • step6 註冊一個新用戶,查看數據庫中is_active的值

  • step7 查看郵箱郵件信息

  • step8 在郵箱中點擊連接地址進行激活操做,成功跳轉到登陸頁

  • step9 查看數據庫,該用戶is_active字段的是爲1表示已激活

 

 10.使用celery異步發送郵件

  • step1 在項目目錄下建立celery_tasks包,在該包下建立tasks.py文件

  • step2 在tasks.py文件中建立Celery實例對象
app = Celery("celery_tasks.tasks", broker="redis://127.0.0.1:6379/4")
  • step3 定義任務函數send_active_email,說明之因此睡眠5秒是爲了體現celery異步的強大
@app.task
def send_active_email(to_email, username, token):
    """發送用戶激活郵件"""
    subject = "每天生鮮歡迎你"  # 郵件標題
    message = ''  # 郵件正文
    sender = settings.EMAIL_FROM  # 發件人
    receiver = [to_email]  # 收件人
    html_message = """
                      <h1>%s  恭喜您成爲每天生鮮註冊會員</h1><br/><h3>請您在1小時內點擊如下連接進行帳戶激活</h3><a href="http://127.0.0.1:8000/user/active/%s">http://127.0.0.1:8000/user/active/%s</a>
           """ % (username, token, token)
    send_mail(subject, message, sender, receiver, html_message=html_message)
    # 爲了體現出celery異步完成發送郵件,這裏睡眠5秒
    time.sleep(5)
  • step4 另打開一個Terminal終端,執行celery -A celery_tasks.tasks worker -l info 運行任務處理者,須要在broker所在的服務器中執行,須要注意的是windows不支持celery4.0以上的版本

  • step5 註冊一個新用戶,註冊成功跳轉到首頁後,查看celery處理者運行日誌,發現報錯了,致使用戶註冊成功,但郵件並未發送成功緣由是在tasks.py文件中導入了項目配置文件settings,而未在執行任務進行初始化,而且在windows環境中要成功使用celery,celery版本必須在4.0如下,任務隊列(中間人)redis數據庫版本必須在3.0如下,博主經驗

  • step6  在tasks.py文件中添加以下代碼,做用於worker工做室初始化django配置,由於博主這裏使用celery是將任務發佈者和中間人(broker)以及任務處理者(worker)在一臺主機上運行,因此將下面的初始化配置寫在這裏,該初始化配置是跟隨worker走的
import os
import django
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "dailyfresh.settings")
django.setup()
  • step7 在新終端中執行celery -A celery_tasks.tasks worker -l info,而後進行新用戶註冊

  • step8 查看celery運行日誌,顯示成功,時間爲6秒,之因此這麼長時間是由於在send_active_email函數中睡眠5秒,因而可知儘管睡眠五秒,但用戶在註冊的時候根本感受不到,註冊成功瞬間跳轉到主頁,說明使用celery進行異步發送郵件的重要性

  • step9 查看用戶表

 

  • step10 查看redis數據庫

二丶用戶登陸

1.顯示登陸頁面

  • step1 在用戶註冊時已經定義了LoginView類視圖中的get方法,顯示登陸頁,因此直接在login.html文件中定義form表單請求方式以及請求地址,注:action不寫默認表示與登陸地址一致,跟用戶註冊同樣,使用同一地址顯示並處理登陸
<form method="post">
    {% csrf_token %}

 2.處理登陸數據校驗

  • step1 在類視圖LoginView中定義post函數
def post(self, request):
    """登陸校驗"""
    pass
  • step2 接收用戶填寫的數據
username = request.POST.get("username")
password = request.POST.get("pwd")
  • step3 校驗參數完整性
if not all([username, password]):
    return render(request, "login.html", {"error_msg":"數據不完整"})
  • step4 校驗用戶名密碼,當用戶名密碼正確狀況下保存登陸狀態到session中,使用django認證系統中的authenticate和login方法
user = authenticate(username=username, password=password)  # 正確返回user對象,不正確返回None
if user is not None:
    # 用戶名密碼正確
    if user.is_active:
        # 用戶已激活
        # 將用戶登陸成功後狀態保存在session,使用django認證系統中的login方法
        login(request, user)
        # 重定向到主頁
        return redirect(reverse("goods:index"))
    else:
        # 用戶未激活
        return render(request, "login.html", {"error_msg":"帳戶未激活"})
else:
    # 用戶名或密碼錯誤
    return render(request, "login.html", {"error_msg":"用戶名或密碼錯誤"})

3.進行登陸測試 ,查看網頁走下方紅色字樣提示

  • step1 登陸已激活的帳戶

  • step2 登陸不存在的帳號

  • step3  登陸未激活的帳號,這裏有一個bug那就是在進行未激活帳號登陸時一直提示用戶名和密碼錯誤,在post方法中經過打印username和password的值查看輸入的用戶名和密碼沒錯與當初註冊時填寫的用戶名密碼對的上,查看django認證系統文檔,方法時候啥的都沒問題,可是在校驗用戶名密碼時調用的authenticate方法一直返回的是None,這就很奇怪了,經過網上查資料發現須要在settings配置文件中添加以下配置,讓django認證系統中的create_user方法再保存用戶註冊數據時,不關聯用戶表中的is_active字段,這樣再進行登陸驗證時調用authenticate方法返回錯誤的None對象
AUTHENTICATION_BACKENDS = ['django.contrib.auth.backends.AllowAllUsersModelBackend']

  • step4 不填寫數據直接登陸

4.配置django緩存以及session數據存儲後端到redis數據庫,django默認將session數據存儲到mysql數據庫(settings配置的數據庫)中的django_session表中

  • step1 安裝django-redis包
pip2 install django-redis
  • step2 在settings中添加django緩存配置以及設置django-redis做爲session存儲後端
# django緩存配置
CACHES = {
    "default": {
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": "redis://127.0.0.1:6379/5",
        "OPTIONS": {
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
        }
    }
}

# 使用django-redis 做爲 session 儲存後端
SESSION_ENGINE = "django.contrib.sessions.backends.cache"
SESSION_CACHE_ALIAS = "default"
  • step3 查看reids中5庫中的鍵

  • step4 進行用戶登陸,服務器返回響應的sessionid

  • step5 查看redis數據庫

 5.用戶勾選記住用戶名

  • step1 在保存用戶登陸狀態代碼中進行以下代碼邏輯判斷,當用戶勾選記住用戶名時,remember的值爲on,並將用戶名保存到cookie中
# 由於redirect方法返回的是HttpResponseRedirect對象,而這個對象是HttpResponse的子類,因此能夠設置cookie
response = redirect(reverse("goods:index"))
# 判斷用戶是否記勾選記住用戶名
remember = request.POST.get("remember")
if remember == "on":
    # 表示勾選了,將用戶名保存在cookie中
    response.set_cookie("username", username, max_age=7*24*3600)
else:
    # 刪除cookie
    response.delete_cookie("username")
# 重定向到主頁
return response
  • step2 在顯示登陸頁面get函數中判斷用戶是否記住用戶名,記住用戶名則獲取cookie中的username而且設置勾選框爲checked勾選狀態,並返回給前端模板中
# 判斷是否勾選記住用戶名
if 'username' in request.COOKIES:
    username = request.COOKIES.get("username")
    checked = "checked"
else:
    username=''
    checked = ''

return render(request, "login.html", {"username":username, "checked":checked})
  • step3 在login.html中設置用戶名username標籤的value值,以及remember的值
<input type="text" name="username" class="name_input" value="{{ username }}" placeholder="請輸入用戶名" autocomplete="off">
<input type="checkbox" name="remember" {{ checked }}>
  • step4 測試登陸時記住用戶名

  •  step5 勾選記住用戶名後,查看網站cookie看到剛設置的名爲username的cookie了

  • step6 測試登陸時不記住用戶名

相關文章
相關標籤/搜索