1.功能
1.1.个人资料
1.2.修改个人资料部分信息
1.3.修改分类
1.4.删除分类
1.5.写博客页面优化
2.个人资料
2.1.URL配置
from django.urls import path, re_path
from . import views
app_name = 'blog'
urlpatterns = [
path('login/', views.login),
path('logout/', views.logout),
path('register/', views.register),
path('', views.IndexView.as_view(), name='index'),
re_path('blog/(?P<pk>[0-9]+)/', views.BlogDetailView.as_view(), name='detail'),
path('test_ckeditor_front/', views.test_ckeditor_front),
path('add_category/', views.add_category, name='add_category'),
path('add_tag/', views.add_tag, name='add_tag'),
path('write_blog/', views.write_blog),
re_path('category/(?P<pk>[0-9]+)/', views.CategoryView.as_view(), name='category'),
re_path('tag/(?P<pk>[0-9]+)/', views.TagView.as_view(), name='tag'),
re_path('userinfo/(?P<pk>[0-9]+)/', views.UserInfo.as_view(), name='userinfo'),
]
2.2.给模型增加get_absolute_url()
class LogUser(AbstractUser):
nikename = models.CharField(max_length=32, verbose_name="昵称", blank=True)
telephone = models.CharField(max_length=11, null=True, unique=True)
head_img = models.ImageField(upload_to='headimage', blank=True, null=True, verbose_name='头像')
def get_absolute_url(self):
"""
调用redirect(obj)函数时,如果obj是这个数据模型实例对象(相当一条表记录),
redirect()执行后重定向到该obj对象的get_absolute_url()方法返回的URL.
reverse()函数是一个URL反向解析函数
"""
return reverse('blog:userinfo', kwargs={'pk': self.pk})
def __str__(self):
return self.username
class Meta:
verbose_name = "用户信息表"
verbose_name_plural = verbose_name
2.3.html
base.html:
userinfo.html:
{% load static %}
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>用户详情</title>
<!-- 导入Bootstrap框架样式-->
<link href="{% static 'css/bootstrap.min.css' %}" rel="stylesheet" >
<link href="{% static 'css/blog.css' %}" rel="stylesheet">
<script src="{% static '/js/jquery-3.6.0.js' %}"></script>
</head>
<body>
<div class="container">
<header class="blog-header lh-1 py-3">
<div class="row flex-nowrap align-items-center">
<div class="col-4 pt-1">
<a class="link-secondary" href="/blog/">返回</a>
</div>
<div class="col-4 pt-1">
<h1 class="text-dark text-center" href="#">个人资料</h1>
</div>
</div>
</header>
<form class="form-horizontal" style="display: block" id="detail">
<div class="row p-2">
<label for="staticEmail" class="col-sm-2 col-form-label">头像</label>
<div class="col-sm-10">
<img src="/media/{{ userinfo.head_img }}" class="rounded" alt="..." style="height:100px;width:100px;">
</div>
</div>
<div class="row p-2">
<label for="staticEmail" class="col-sm-2 col-form-label">昵称</label>
<div class="col-sm-10">
<p id="nikename">{{ userinfo.nikename }}</p>
</div>
</div>
<div class="row p-2">
<label for="{{ userinfo.email.id_for_label }}" class="col-sm-2 col-form-label">邮箱</label>
<div class="col-sm-10">
<p id="email">{{ userinfo.email }}</p>
</div>
</div>
<button type="button" class="btn btn-outline-primary btn-sm" id="change">修改</button>
</form>
<form class="form-horizontal" style="display: none" id="edit"
action="{% url 'blog:update_userinfo' userinfo.id %} " method="post" enctype="multipart/form-data" id="edit">
{% csrf_token %}
<div class="row p-2">
<label for="staticEmail" class="col-sm-2 col-form-label">昵称</label>
<div class="col-sm-10">
<input type="text" class="form-control" value="{{ userinfo.nikename }}" name="nikename">
</div>
</div>
<div class="row p-2">
<label for="{{ userinfo.email.id_for_label }}" class="col-sm-2 col-form-label">邮箱</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="email" value="{{ userinfo.email }}" name="email">
</div>
</div>
<div class="">
<button type="submit" class="btn btn-outline-primary btn-sm">提交</button>
<button type="button" class="btn btn-outline-primary btn-sm" id="cancel">取消</button>
</div>
</form>
</div>
</body>
</html>
<script>
$(function(){
var old_nikename = $('#nikename').html();
var old_email = $('#email').html();
// 点击修改
$('#change').click(function() {
// 把原文本改成输入框
// $('#nikename').html("<input id='editname' type='text' name='nikename' value="+old_nikename+" >")
document.getElementById("edit").style.display="block";
document.getElementById("detail").style.display="none";
});
// 点击取消
$('#cancel').click(function() {
// $('#nikename').html("<p id='nikename'>"+old_nikename+"</p>")
document.getElementById("edit").style.display="none";
document.getElementById("detail").style.display="block";
})
});
</script>
2.4.视图函数
class UserInfo(DetailView):
# 指定数据模型
model = models.LogUser
# 指定模板文件
template_name = 'blog/userinfo.html'
# 指定模板变量名
context_object_name = 'userinfo'
# 指定主键,'pk'为配置文件中的URL参数名
pk_url_kwarg = 'pk'
3.修改个人资料
3.1.URL配置
path("userinfo/update/<int:pk>/", views.UpdateUserinfo.as_view(), name="update_userinfo"),
3.2.视图函数
class UpdateUserinfo(UpdateView):
model = models.LogUser
fields = ["nikename", "email"]
4.修改分类
4.1.URL配置
path("category/update/<int:pk>/", views.UpdateCategory.as_view(), name="update_category"),
4.2.html
index.html:
<div>
<!-- 调用自定义标签文件custom_tags中定义的get_categories()函数,显示每个类中的文章篇数 -->
{% get_categories as category_list %}
<a href="/blog/">全部分类</a>
{% for category in category_list %}
<ol class="list-unstyled mb-0">
<li class="d-flex justify-content-between">
<a href="{% url 'blog:category' category.pk %}" style="text-decoration: none">{{ category.name }}
<!-- 显示每个类中的文章篇数-->
<span class="post-count">({{ category.num_blogs }})</span>
</a>
<div>
<button type="submit" class="btn btn-outline-primary"
style="--bs-btn-padding-y: .25rem; --bs-btn-padding-x: .5rem; --bs-btn-font-size: .75rem;" onclick="location.href='{% url 'blog:update_category' category.pk %}'">编辑</button>
{% if category.num_blogs == 0 %}
<form action="{% url 'blog:delete_category' category.pk %}" method="post" style="display: inline-block;">
{% csrf_token %}
<button type="submit" class="btn btn-outline-danger" style="--bs-btn-padding-y: .25rem; --bs-btn-padding-x: .5rem; --bs-btn-font-size: .75rem;">删除</button>
</form>
{% endif %}
</div>
</li>
</ol>
{% empty %}
<span>暂无分类</span>
{% endfor %}
</div>
update_category.html:
{% load static %}
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>修改分类</title>
<!-- 导入Bootstrap框架样式-->
<link href="{% static 'css/bootstrap.min.css' %}" rel="stylesheet" >
<link href="{% static 'css/blog.css' %}" rel="stylesheet">
</head>
<body>
<div class="container">
<header class="blog-header lh-1 py-3">
<div class="row flex-nowrap align-items-center">
<div class="col-4 pt-1">
<a class="link-secondary" href="/blog/">返回</a>
</div>
<div class="col-4 pt-1">
<h1 class="text-dark text-center" href="#">categoryinfo</h1>
</div>
</div>
</header>
<form class="form-horizontal" method="post" enctype="multipart/form-data" action="{% url 'blog:update_category' category.pk %}">
{% csrf_token %}
<div class="row p-2">
<label for="staticEmail" class="col-sm-2 col-form-label">分类名称</label>
<div class="col-sm-10">
<input type="text" class="" value="{{ category.name }}" name="name">
</div>
</div>
<div class="row p-2">
<label for="" class="col-sm-2 col-form-label">描述</label>
<div class="col-sm-10">
<input type="text" class="" id="email" value="{{ category.des }}" name="des">
</div>
</div>
<div class="">
<button type="submit" class="btn btn-outline-primary btn-sm" id="submit">提交</button>
<button type="button" class="btn btn-outline-primary btn-sm" id="cancel" onclick="location.href='/blog/'">取消</button>
</div>
</form>
</div>
</body>
</html>
4.3.视图函数
class UpdateCategory(UpdateView):
model = models.Category
template_name = 'blog/update_category.html'
fields = ["name", "des"]
success_url = '/blog/'
5.删除分类
5.1.URL
path("category/delete/<int:pk>/", views.DeleteCategory.as_view(), name="delete_category"),
5.2.视图函数
class DeleteCategory(DeleteView):
model = models.Category
template_name = 'blog/index.html'
success_url = '/blog/'
5.3.html
<form action="{% url 'blog:delete_category' category.pk %}" method="post" style="display: inline-block;">
{% csrf_token %}
<button type="submit" class="btn btn-outline-danger" style="--bs-btn-padding-y: .25rem; --bs-btn-padding-x: .5rem; --bs-btn-font-size: .75rem;">删除</button>
</form>
6.写博客页面优化
{% load static %}
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<!-- 导入Bootstrap框架样式-->
<link href="{% static '/css/bootstrap.min.css' %}" rel="stylesheet">
<link href="{% static 'css/blog.css' %}" rel="stylesheet">
<!--导入ckeditor的初始化Java Script脚本,src的值是默认路径 -->
<script src="{% static 'ckeditor/ckeditor-init.js' %}"></script>
<!--导入ckeditor的Java Script脚本,src的值是默认路径 -->
<script src="{% static 'ckeditor/ckeditor/ckeditor.js'%}"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css">
<title>写博客</title>
</head>
<body>
<div class="container">
<header class="blog-header lh-1 py-3">
<div class="row flex-nowrap align-items-center">
<div class="col-4 pt-1">
<a class="link-secondary bi bi-arrow-left" href="/blog/">返回</a>
</div>
<div class="col-4 pt-1">
<h1 class="text-dark text-center bi bi-brush" href="#">写博客</h1>
</div>
</div>
</header>
<div class="row">
<div class="col-md-offset-2 col-md-8">
<!--<form>标签中的enctype属性设为"multipart/form-data",才能实现图片上传-->
<form novalidate action="" method="post" class="form-horizontal p-2" enctype="multipart/form-data">
{% csrf_token %}
<div class="form-group d-flex flex-row mb-3">
<label for="title" class="col-sm-2 control-label">{{ form_blog.title.label }}</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="title" name="title">
</div>
</div>
<div class="form-group d-flex flex-row mb-3">
<label for="title" class="col-sm-2 control-label">{{ form_blog.excerpt.label }}</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="excerpt" name="excerpt">
</div>
</div>
<div class="form-group d-flex flex-row mb-3">
<label for="title" class="col-sm-2 control-label">{{ form_blog.category.label }}</label>
<div class="col-sm-10">
{{ form_blog.category }}
</div>
</div>
<div class="form-group d-flex flex-row mb-3">
<label for="title" class="col-sm-2 control-label">{{ form_blog.tags.label }}</label>
<div class="col-sm-10">
{{ form_blog.tags }}
</div>
</div>
<div class="form-group d-flex flex-row mb-3">
<label for="title" class="col-sm-2 control-label">{{ form_blog.type.label }}</label>
<div class="col-sm-10">
{{ form_blog.type }}
</div>
</div>
<div class="form-group d-flex flex-row mb-3">
<label for="title" class="col-sm-2 control-label">{{ form_blog.body.label }}</label>
<div class="col-sm-10">
{{ form_blog.body }}
</div>
</div>
<div class="form-group d-flex flex-row mb-3">
<label class="col-sm-2 control-label">
{{ form_blog.cover_img.label }}
</label>
<div>
<label for="{{ form_blog.cover_img.id_for_label }}" class="col-sm-2 control-label">
<!-- {{ form_blog.cover_img }} -->
<input type="file" name="cover_img" style="display: none" accept="image/*" id="id_cover_img">
<!-- <image>标签的src属性先指向一个默认图片地址 //-->
<img id="file-img" src="{% static 'images/image-regular.svg' %}" class="rounded" style="height:100px;width:100px;">
<script>
var fileInput = document.querySelector('input[type="file"]'),
previewImg = document.querySelector('img');
fileInput.addEventListener('change', function () {
var file = this.files[0];
var reader = new FileReader();
// 监听reader对象的的onload事件,当图片加载完成时,把base64编码賦值给预览图片
reader.addEventListener("load", function () {
previewImg.src = reader.result;
}, false);
// 调用reader.readAsDataURL()方法,把图片转成base64
reader.readAsDataURL(file);
}, false);
</script>
</label>
</div>
</div>
<div class="form-group d-flex flex-row mb-3">
<div class="col-sm-2 control-label">
<button type="submit">保存</button>
<button type="button" onclick="location.href='/blog/'">取消</button>
</div>
</div>
</form>
</div>
</div>
</div>
</body>
<script src="{% static '/js/jquery-3.6.0.js' %}"></script>
<script src="{% static '/js/bootstrap.min.js' %}"></script>
</html>