我需要帮助为我的 Django 课程中的作业构建一个合适的登录系统。我应该构建一个应用程序,用户可以在基于令牌的身份验证中登录,并可以发布目的地并查看它,但我被困在登录部分。我已经成功地正确构建了注册系统,但现在我需要帮助登录。
这是我的登录视图。它不断抛出“NOT NULL约束失败:destination_session.user_id”错误,所以我不知道我做错了什么
def login(request: HttpRequest):
if request.method == "POST":
email = request.POST.get('email')
password_hash = request.POST.get('password')
hasher = hashlib.sha256()
hasher.update(bytes(password_hash, "UTF-8"))
password_hash = hasher.hexdigest()
token = ""
letters = string.ascii_lowercase
for _ in range(32):
token = "".join(random.choice(letters) for _ in range(32))
session_token = Session.objects.create(token=token)
response = HttpResponse("Cookie Set")
try:
user = User.objects.get(email=email, password_hash=password_hash)
if user.check_password(password_hash):
response = redirect("/")
response.set_cookie('token', token)
return response
else:
return HttpResponse("Invalid password")
except User.DoesNotExist:
return Http404({"Invalid email"})
return render(request, "destination/login.html")
这是我的模型
from django.db import models
import hashlib
class User(models.Model):
id = models.BigAutoField(primary_key=True)
name = models.TextField()
email = models.EmailField(unique=True)
password_hash = models.TextField()
def check_password(self, hashed_password):
hasher = hashlib.sha256()
hasher.update(bytes(self.password_hash, "UTF-8"))
hashed_password = hasher.hexdigest()
return self.password_hash == hashed_password
class Session(models.Model):
id = models.BigAutoField(primary_key=True)
user = models.OneToOneField(User, on_delete=models.CASCADE)
token = models.TextField()
class Destination(models.Model):
id = models.BigAutoField(primary_key=True)
name = models.TextField()
review = models.TextField()
rating = models.PositiveIntegerField()
share_publicly = models.BooleanField(default=False)
user = models.ForeignKey("User", related_name="destinations", on_delete=models.CASCADE)
这是我的登录表单:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<form action="/login" method="POST">
<label for="">Email</label>
<input type="email" name="email" id="email">
<label for="">Password</label>
<input type="password" name="password" id="password">
<button type="submit">Login</button>
</form>
</body>
</html>
如果有人能发现问题所在或帮助我找到更好的方法,我将不胜感激。另外,我不允许使用内置模块中的身份验证、会话或管理,因此请不要建议它。如果您向我展示如何仅显示登录用户的目的地,那就太好了 xD
在创建会话之前,您应该首先确保拥有用户对象。
此外,您需要正确检查密码,而无需重新散列密码。
我还可以看到您在表单中使用了字段名称
password
,但在您看来,您正在尝试使用 password_hash
来获取它。这将导致密码哈希为空,因此登录将失败。
您可以更新您的登录视图,例如:
import hashlib
import random
import string
from django.shortcuts import render, redirect
from django.http import HttpResponse
from .models import User, Session
def login(request):
if request.method == "POST":
email = request.POST.get('email')
password = request.POST.get('password')
user = User.objects.filter(email=email).first()
if user and user.check_password(password):
token = ''.join(random.choice(string.ascii_letters) for _ in range(32))
session = Session.objects.create(user=user, token=token)
response = redirect("/")
response.set_cookie('token', token)
return response
return HttpResponse("Invalid email or password")
return render(request, "destination/login.html")
并更新
check_password
模型中的方法:
class User(models.Model):
# Fields...
def check_password(self, password):
hasher = hashlib.sha256()
hasher.update(bytes(password, "UTF-8"))
return self.password_hash == hasher.hexdigest()
最后,为了仅显示登录用户的目的地,您需要从 cookie 中存储的令牌中获取用户。这是显示目的地的视图:
def user_destinations(request):
token = request.COOKIES.get('token')
if token:
session = Session.objects.filter(token=token).first()
if session:
destinations = session.user.destinations.all()
return render(request, "destination/user_destinations.html", {"destinations": destinations})
return redirect("/login")