Django学习---多人博客项目
Posted sinlearn
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Django学习---多人博客项目相关的知识,希望对你有一定的参考价值。
Django学习---多人博客项目(2)
? 上一部分内容完成了博客项目的搭建,以及博客标题和博客内容的展示,熟悉了Django的使用,下面,接着实现用户管理部分功能。
一、自定义模板和静态文件的位置
(1)自定义模板的位置
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # 当前文件路径的上两级文件路径--即是根目录
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')] #即模板目录的位置是相对项目根目录的templates目录——./templates
,
'APP_DIRS': False,# True, # False表示不允许Django按照默认方式寻找模板文件
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
(2)自定义静态文件的位置
# settings 文件的最后三行
# Django 支持这三种静态文件
# Static files (CSS, javascript, Images)
# 想知道Django是如何实现的可以查看上面这个网址
# https://docs.djangoproject.com/en/3.0/howto/static-files/
#在默认状态下,如果通过URL访问静态文件,各个应用的静态文件都有自己的静态文件存放地
#例如可以通过http://localhost:8000/blog/static/newton.jpg的模式进行访问,blog应用的静态文件newton.jpg
STATIC_URL = '/static/'
#注,本项目不打算这样设置,而是把静态文件放到指定的目录,在上一行下面添加如下代码:
STATICFILES_DIRS =(
os.path.join(BASE_DIR, "static"),
)
# 在根目录下创建static目录,添加newton.jpg文件,在浏览器进行测试
(3)通用静态文件和基础模板
? 1、首先下载jquery和bootstrap等相关的文件并放到创建的static目录下:
bootstrap下载链接:https://www.bootcss.com/
? 2、创建新的通用的基础模板
头部代码:header.html
{% load staticfiles %}
<div class="container">
<nav class="navbar navbar-default" role="navigation">
<div class="navbar-header">
<a class="navbar-brand" href="http://www.itdiffer.com">
<img src="{% static '/images/logo.jpg' %}" width="100px">
</a>
</div>
<div>
<ul class="nav navbar-nav" role="navigation">
<li><a href="{% url 'blog:blog_title' %}"></a></li>
</ul>
<ul class="nav navbar-nav navbar-right">
<li><a href="#">LOGIN</a></li>
</ul>
</div>
</nav>
</div>
脚部代码:footer.html
<div class="container">
<hr>
<p class=""text-center>
copy right www.itdiffer.com
</p>
</div>
base.html
{% load staticfiles %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{% block title %}
{% endblock %}</title>
<link rel="stylesheet" href="{% static 'css/bootstrap.css' %}">
</head>
<body>
{% include "header.html" %}
<div class="container">
{% block content %}
{% endblock %}
</div>
{% include "footer.html" %}
{% block javascript %}{% endblock %}
</body>
</html>
(4)配置路由
方式一:
在./mysite/urls.py的urlpatterns中进行如下设置。特别注意,include()中的第一参数提供的是一个二元的元组。
urlpatterns=[
path('admin/',admin.site.urls),
# path('blog/', include('blog.urls'))
path('blog/', include(('blog.urls', 'blog'), namespace='blog'))
]
在./blog/urls.py的urlpatterns中进行如下配置。
urlpatterns = [
# path('', views.blog_title), # 此处将函数视图添加进来
# path('<int:article_id>', views.blog_article)
path('', views.blog_title, name='blog_title'), # 此处将函数视图添加进来
path('<int:article_id>/', views.blog_article, name='blog_article')
]
方式二:
在./mysite/urls.py的urlpatterns中进行如下设置。注意,被注释了的那一行是“方式一”的配置,请读者注意比较两种配置方式之不同。
urlpatterns=[
path('admin/',admin.site.urls),
# path('blog/', include('blog.urls')),
# path('blog/', include(('blog.urls', 'blog'), namespace='blog')),
path('blog/', include('blog.urls', namespace='blog')),
]
在./blog/urls.py的urlpatterns中进行如下配置,比“方式一”增加了app_name = "blog"这一行。
app_name = "blog" # 新增加这一行
urlpatterns = [
# path('', views.blog_title), # 此处将函数视图添加进来
# path('<int:article_id>', views.blog_article)
path('', views.blog_title, name='blog_title'), # 此处将函数视图添加进来
path('<int:article_id>/', views.blog_article, name='blog_article')
]
以上两种方式,供读者自行选择。
二、用户登录
(1)创建应用
1、创建新应用(account)
python manage.py startapp account
# 修改配置: ./mysite/settings.py 中:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'blog',
'account',
]
2、URL配置
# ./mysite/urls.py
urlpatterns=[
path('admin/', admin.site.urls),
# path('blog/', include('blog.urls')),
path('blog/', include(('blog.urls', 'blog'), namespace='blog')),
# path('blog/', include('blog.urls', namespace='blog')), #该方法配置和上面一样的效果
# 新添加的路由
path('account/', include(('account.urls', 'account'), namespace='account')),
]
# 在新应用account目录下,创建urls.py, 进行配置。
from django.urls import path
from . import views
urlpatterns = [
path('login/', views.user_login, name='user_login'),
]
(2)创建表单类
在 ./account目录中新建文件forms.py ,在forms.py中创建表单类用于用户登录:
from django import forms
class LoginForm(forms.Form):
username = forms.CharField()
password = forms.CharField(widget=forms.PasswordInput)
(3)创建登录的视图函数
在 ./account/views.py文件中创建视图函数user_login()
from django.shortcuts import render
from django.http import HttpResponse
from django.contrib.auth import authenticate, login
from .forms import LoginForm
# Create your views here.
def user_login(request):
if request.method == "POST":
login_form = LoginForm(request.POST)
if login_form.is_valid():
cd = login_form.cleaned_data
user = authenticate(username=cd['username'], password=cd['password'])
if user:
login(request, user)
return HttpResponse("Welcome you. You have been authenticated successfully. ")
else:
return HttpResponse("Your username or password is not right.")
else:
return HttpResponse("Invalid login")
if request.method == "GET":
login_form = LoginForm()
return render(request, "account/login.html", {"form": login_form})
(4)创建登录的前端界面
? 在./templates/account/login.py 里添加如下代码:
{% extends "base.html" %}
{% block title %}Login{% endblock %}
{% block content %}
<div class="row text-center vertical-middle-sm">
<h1>Login</h1>
<p>Input your username and password</p>
<form class="form-horizontal" action="." method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Login">
</form>
</div>
{% endblock %}
三、用内置方法实现登录和退出
(1)内置方法实现登录
? 1、在./account/urls.py 中配置路由如下:
from django.urls import path
from . import views
from django.contrib.auth import views as auth_views # 用户内置登录引入
urlpatterns = [
# path('login/', views.user_login, name='user_login'),
path('login/', auth_views.LoginView.as_view(template_name='account/login2.html'), name='user_login'),
]
? 2、添加路由配置里的网页login2.html
{% extends "base.html" %}
{% load staticfiles %}
{% block title %}Login{% endblock %}
{% block content %}
<div class="row text-center vertical-middle-sm">
<h1>Login--Built in method of Django</h1>
{% if form.errors %}
<p>Your username and password didn't match.Please try agin.</p>
{%endif %}
<p>Input your username and password</p>
<form calss="form-horizontal" action="{% url 'account:user_login' %}" method="post">
{% csrf_token %}
<div class="form-group">
<label for="{{ form.username.id_for_label }}" class="col-md-5 control-label" style="color:red">
<span class="glyphicon glyphicon-user">
</span>
Username
</label>
<div class="col-md-6 text-left">
{{ form.username }}
</div>
</div>
<div class="form-group">
<label for="{{ form.password.id_for_label }}" class="col-md-5 control-label" style="color:blue">
<span class="glyphicon glyphicon-user">
</span>
Password
</label>
<div class="col-md-6 text-left">
{{ form.password }}
</div>
</div>
<input type="submit" class="btn btn-primary btn-lg" value="Login">
</form>
</div>
{% endblock %}
? 3、修改配置文件
为了设置项目所需要的转向目标,需要在./mysite/settings.py中增加LOGIN_REDIRECT_URL的值(将以下配置放置到./mysite/settings.py文件的最后)。
LOGIN_REDIRECT_URL = '/blog/'
(2)判断是否登录
{% load staticfiles %}
<div class="container">
<nav class="navbar navbar-default" role="navigation">
<div class="navbar-header">
<a class="navbar-brand" href="http://www.itdiffer.com">
<img src="{% static '/images/logo.png' %}" width="100px">
</a>
</div>
<div>
<ul class="nav navbar-nav" role="navigation">
<li><a href="{% url 'home' %}">HOME</a></li>
<li><a href="{% url 'blog:blog_title' %}">BLOG</a></li>
<li><a href="{% url 'article:article_titles' %}">文章</a></li>
<li><a href="{% url 'image:falls_images' %}">美图</a></li>
<li><a href="{% url 'course:course_list' %}">课程</a></li>
<li><a href="{% url 'course:about'%}">关于本站</a></li>
</ul>
<ul class="nav navbar-nav navbar-right" style="margin-right:10px">
{% if user.is_authenticated %}
<li>
<div class="dropdown" style="margin-top:8px">
<button class='btn btn-default dropdown-toggle' type='button' id='dropdownMenu' data-toggle='dropdown'>{{ user.username }}
<span class='caret'></span>
</button>
<ul class="dropdown-menu">
<li><a href="{% url 'account:password_change' %}">修改密码</a></li>
<li><a href="{% url 'account:my_information' %}">个人信息</a></li>
<li><a href="{% url 'article:article_column' %}">后台管理</a></li>
</ul>
</div>
</li>
<li><a href="{% url 'account:user_logout' %}">Logout</a></li>
{% else %}
<li><a href="{% url 'account:user_login' %}">LOGIN</a></li>
<li><a href="{% url 'account:user_register' %}">Sign up</a></li>
{% endif %}
</ul>
</div>
</nav>
</div>
<script src="{% static 'js/jquery.js' %}"></script>
<script src="{% static 'js/bootstrap.js' %}"></script>
<!--
现在就来修改./templates/header.html模板,使LOGIN所在的位置根据用户登录状态显示不同的内容。如果用户已经登录,则显示用户名和Logout字样;如果用户尚未登录,则显示LOGIN字样,并做超链接到登录界面。
--/>
{% load staticfiles %}
<div class="container">
<nav class="navbar navbar-default" role="navigation">
<div class="navbar-header">
<a class="navbar-brand" href="http://www.itdiffer.com">
<img src="{% static '/images/logo.jpg' %}" width="100px">
</a>
</div>
<div>
<ul class="nav navbar-nav" role="navigation">
<li><a href="{% url 'blog:blog_title' %}">BLOG</a></li>
</ul>
<ul class="nav navbar-nav navbar-right" style="margin-right: 10px">
{% if user.is_authenticated %}
<li><a href="#">{{ user.username }}</a></li>
<li><a href="#">Logout</a></li>
{% else %}
<li><a href="{% url 'account:user_login' %}">LOGIN</a></li>
{% endif %}
</ul>
</div>
</nav>
</div>
(3)内置退出
? 与登录类似,首先配置URL。编辑./account/urls.py文件,增加如下内容。
urlpatterns = [
# path('login/', views.user_login, name='user_login'),
path('login/', auth_views.LoginView.as_view(template_name='account/login2.html'), name='user_login'),
path('logout/', auth_views.LoginView.as_view(template_name='account/logout.html'), name='user_logout'),
]
? 此处配置好后,把./templates/header.html文件中那个针对Logout的超链接修改一下。
<li><a href="{% url 'account:user_logout' %}">Logout</a></li>
? 在./templates/account/中创建一个退出的模板文件,名为logout.html,代码如下。
{% extends "base.html" %}
{% block title %}Login{% endblock %}
{% block content %}
<div class="row text-center vertical-middle-sm">
<p>You have log out</p>
<p>You can <a href="{% url 'account:user_login' %}" >Login</a> again .</p>
</div>
{% endblock %}
四、用户注册
(1)简单注册
? 1、编写表单类 ./account/form.py文件,增加一个注册用户表单类:
from django import forms
from django.contrib.auth.models import User
class RegistrationForm(forms.ModelForm):
password = forms.CharField(label="Password", widget=forms.PasswordInput)
password2 = forms.CharField(label="Confirm Password", widget=forms.PasswordInput)
class Meta:
model = User
fields = ("username", "email")
def clean_password2(self):
cd = self.cleaned_data
if cd['password'] != cd['password2']:
raise forms.ValidationError("passwords do not match.")
return cd['password2']
? 2、在./account/views.py中 ,添加视图函数:
from .forms import RegistrationForm
def register(request):
if request.method == "POST":
user_form = RegistrationForm(request.POST)
if user_form.is_valid():
new_user = user_form.save(commit=False)
new_user.set_password(user_form.cleaned_data['password'])
new_user.save()
return HttpResponse("successfully .")
else:
return HttpResponse("sorry, your can not register .")
else:
user_from = RegistrationForm()
return render(request, "account/register.html", {"form":user_from})
3、在./templates/account/ 下创建前端页面 register.html:
{% extends base.html %}
{% load staticfiles %}
{% block title %} register user{% endblock %}
{% block content %}
<div class="row text-center vertical-middle-sm">
<h1>Register</h1>
<p>If you are a user,<strong><a href="{% url 'account:user_login' %}">Login</a></strong>,please</p>
<p>or register.</p>
<from class="form-horizontal" action="." method="post">
{% csrf_token %}
<div class="form-group">
<label for="{{ form.username.id_for_label }}" class="col-md-5 control-label">
Username
</label>
<div class="col-md-6 text-left">{{ form.username }}</div>
</div>
<div class="form-group">
<label for="{{ form.eamil.id_for_label }}" class="col-md-5 control-label">
Email
</label>
<div class="col-md-6 text-left">{{ form.email }}</div>
</div>
<div class="form-group">
<label for="{{ form.password.id_for_label }}" class="col-md-5 control-label">
PassWord
</label>
<div class="col-md-6 text-left">{{ form.password }}</div>
</div>
<div class="form-group">
<label for="{{ form.password2.id_for_label }}" class="col-md-5 control-label">
Confirm Password
</label>
<div class="col-md-6 text-left">{{ form.password2 }}</div>
<input type="submit" class="btn btn-primary btn-lg" value="REGISTER">
</div>
</from>
</div>
{% endblock %}
4、配置路由, ./account/urls.py 中配置:
urlpatterns = [
path('register/',views.register, name ='user_register') # 新增
]
? 5、进行测试
http://127..0.0.1:8080/account/register.html
(2)增加注册内容
1、要增加一个User数据模型中没有的字段(比如手机号),编辑./account中的models.py文件,并在其中输入如下代码。
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, unique=True)
birth = models.DateField(blank=True, null=True)
phone = models.CharField(max_length=20, null=True)
def __str__(self):
return 'user {}'.format(self.user.username)
# 数据迁移
python manage.py makemigrations account
python manage.py migrate account
2、按照流程,下面应该编写表单类了,编辑./account/forms.py文件,代码如下:
from .models import UserProfile
class UserProfileForm(forms.ModelForm):
class Meta:
model = UserProfile
fields = ("phone", "birth")
3、下面要完善视图函数。编辑./account/views.py文件,增加和修改如下代码。修改后的视图函数与原来相比,主要是兼顾了另外一个表单类,所以只是在代码行数上增加了,并没有增加新的内容。
def register(request):
if request.method == "POST":
user_form = RegistrationForm(request.POST)
userprofile_form = UserProfileForm(request.POST)
if user_form.is_valid()*userprofile_form.is_valid():
new_user = user_form.save(commit=False)
new_user.set_password(user_form.cleaned_data['password'])
new_user.save()
new_profile = userprofile_form.save(commit=False)
new_profile.user = new_user
new_profile.save()
return HttpResponse("successfully")
else:
return HttpResponse("sorry, your can not register.")
else:
user_form = RegistrationForm()
userprofile_form = UserProfileForm()
return render(request, "account/register.html", {"form": user_form, "profile":userprofile_form})
? 4、修改模板,重新编辑./templates/account/register.html文件,代码如下:
{% extends "base.html" %}
{% load staticfiles %}
{% block title %}register user{% endblock %}
{% block content %}
<div class="row text-center vertical-middle-sm">
<h1>Register</h1>
<p>If you are a user, <strong><a href="{% url 'account:user_login' %}">Login</a> </strong>,please</p>
<p>or register.</p>
<form class="form-horizontal" action="." method="post">{% csrf_token %}
<div class="form-group">
<label for="{{ form.username.id_for_label }}" class="col-md-5 control-label">Username</label>
<div class="col-md-6 text-left">{{ form.username }}</div>
</div>
<div class="form-group">
<label for="{{ form.email.id_for_label }}" class="col-md-5 control-label"> Email</label>
<div class="col-md-6 text-left">{{ form.email }}</div>
</div>
<div class="form-group">
<label for="{{ form.password.id_for_label }}" class="col-md-5 control-label">Password</label>
<div class="col-md-6 text-left">{{ form.password }}</div>
</div>
<div class="form-group">
<label for="{{ form.password.id_for_label }}" class="col-md-5 control-label"> Confirm Password</label>
<div class="col-md-6 text-left">{{ form.password2 }}</div>
</div>
<div class="form-group">
<label for="{{ profile.birth.id_for_label }}" class="col-md-5 control-label"> Birth Date</label>
<div class="col-md-6 text-left">{{ profile.birth }}</div>
</div>
<div class="form-group">
<label for="{{ profile.phone.id_for_label }}" class="col-md-5 control-label">Phone</label>
<div class="col-md-6 text-left">{{ profile.phone }}</div>
</div>
<input type="submit" class="btn btn-primary btn-lg" value="REGISTER">
</form>
</div>
{% endblock %}
(3)管理增加注册内容
? 1、在我们增加用户注册信息后,所增加的内容能不能也在超级管理员界面中进行集中管理,要实现这个功能,需要对./account/admin.py文件进行编辑,代码如下:
class UserProfileAdmin(admin.ModelAdmin):
list_display = ('user', 'birth', 'phone')
list_filter = ("phone",)
admin.site.register(UserProfile, UserProfileAdmin)
#· list_display属性的作用是列出列表中的项目。注意这个属性的名称不能改变,后面所有类似的属性也是如此。
#· list_filter的作用是规定网页右边FILTER的显示内容,读者可以根据这里的电话号码过滤显示列表的内容。
四、关于密码的操作
(1)修改密码
在进行具体操作之前,先梳理清楚修改密码的步骤:
第一步,要判断用户是否登录,只有登录用户才能修改密码。
第二步,要打开设置新密码的界面,在该界面中提交新密码。
第三步,要给用户反馈,是否修改完成。
? 1、先写上述第二步中用于提交新密码的界面,即在./templates/account/中创建password_change_form.html文件。以下是./templates/account/password_change_form.html的代码:
{% extends "base.html" %}
{% block title %}passowrd change{% endblock %}
{% block content %}
<div class="row text-center vertical-middle-sm">
<h1>Change Password</h1>
<p>Please enter your old password,for security's sake, and then enter your new password twice so we can verify you typed it in correctly.</p>
{% if form.new_password1.help_text %}
<div class="text-left" style="margin-left:400px">
<p>{{ form.new_password1.help_text|safe }}</p>
</div>
{% endif %}
<form class="form-horizontal" action="." method="post">{% csrf_token %}
<div class="form-group">
<label class='col-md-5 control-label text-right'>
{{ form.old_password.label_tag }}
</label>
<div class="col-md-6 text-left">{{ form.old_password }}</div>
</div>
<div class="form-group">
<label class='col-md-5 control-label text-right'>
{{ form.new_password1.label_tag }}
</label>
<div class="col-md-6 text-left">{{ form.new_password1 }}</div>
</div>
<div class="form-group">
<label class="col-md-5 control-label text-right">
{{ form.new_password2.label_tag }}
</label>
<div class="col-md-6 text-left">{{ form.new_password2 }}</div>
</div>
<input type="submit" value="Change my password" class="btn btn-primary btn-lg"/>
</form>
</div>
{% endblock %}
? 2、同样,也写好第三步中密码修改完成的页面,即./templates/account/password_change_done.html,代码如下:
app_name = "account"
urlpatterns = [
path('login/', auth_views.LoginView.as_view(template_name='account/login2.html'), name='user_login'),
path('logout/', auth_views.LogoutView.as_view(template_name='account/logout.html'), name='user_logout'),
path('register/', views.register, name='user_register'),
path('password-change/', auth_views.PasswordChangeView.as_view(template_name="account/password_change_form.html", success_url="/account/password-change-done/"), name='password_change'),
path('password-change-done/', auth_views.PasswordChangeDoneView.as_view(template_name="account/password_change_done.html"), name='password_change_done'),
]
3、如何让Django能够跳转到/account/login/请编辑./mysite/settings.py文件,在文件中增加如下内容:
LOGIN_URL = '/account/login/'
? 4、为了实现再次跳转,还需要编辑./templates/account/login2.html文件,该文件新增代码如下:
{% extends "base.html" %}
{% load staticfiles %}
{% block title %}Login{% endblock %}
{% block content %}
<div class="row text-center vertical-middle-sm">
<h1>Login</h1>
{% if form.errors %}
<p>Your username and password didn't match. Please try again.</p>
{% else %}
<p>Input your username and password</p>
{% endif %}
# 新增
{% if next %}
<form class="form-horizontal" action="{% url 'account:user_login' %}?next={{next}}" method="post" >
{% else %}
<form class="form-horizontal" action="{% url 'account:user_login' %}" method="post">
{% endif %}
#
{% csrf_token %}
<div class="form-group">
<label for="{{ form.username.id_for_label }}" class="col-md-5 control-label" style="color:red">
<span class="glyphicon glyphicon-user"></span>Username</label>
<div class="col-md-6 text-left">{{ form.username }}</div>
</div>
<div class="form-group">
<label for="{{ form.password.id_for_label }}" class="col-md-5 control-label" style="color:blue">
<span class="glyphicon glyphicon-floppy-open"></span>Password</label>
<div class="col-md-6 text-left">{{ form.password }}</div>
</div>
<input type="submit" class="btn btn-primary btn-lg" value="Login">
</form>
</div>
{% endblock %}
按照上面的方式修改了登录模板文件之后,再次测试,就能够实现登录之后跳转到修改密码页面的功能了。
修改的仅仅是一个模板文件./templates/header.html,修改之后其代码如下:
{% if user.is_authenticated %}
<li>
<div class="dropdown" style="margin-top:8px">
<button class='btn btn-default dropdown-toggle' type='button' id='dropdownMenu' data-toggle='dropdown'>
{{ user.username }}<span class='caret'></span>
</button>
<ul class="dropdown-menu">
<li><a href="{% url 'account:password_change' %}">修改密码</a></li>
{# <li><a href="{% url 'account:my_information' %}">个人信息</a></li>#}
{# <li><a href="{% url 'article:article_column' %}">后台管理</a></li>#}
</ul>
</div>
</li>
<li><a href="{% url 'account:user_logout' %}">Logout</a></li>
{% else %}
<li><a href="{% url 'account:user_login' %}">LOGIN</a></li>
<li><a href="{% url 'account:user_register' %}">Sign up</a></li>
{% endif %}
? 上述代码中