目录
感谢
感谢锋哥的指导。由于我使用的是MySQL 5.7版本,因此对项目代码进行了相应的调整。详细修改过程及源代码,请参考锋哥在B站发布的视频教程:
摘要
本项目利用Django框架,结合现代Web开发的最佳实践,构建了一个功能全面、易于扩展的博客平台。通过此项目,开发者可以学习到如何使用Django进行模型设计、视图逻辑编写、模板渲染以及静态文件管理等核心技能,同时掌握了用户认证、文章管理等博客系统必备功能的实现方法。
项目代码地址:
基于Django框架的博客平台开发与实现(三)-优快云博客https://blog.youkuaiyun.com/m0_50313048/article/details/146297896
博客帖子功能实现
博客首页帖子分页显示实现
查询所有博客帖子信息
article / models.py 新建帖子类:
# from django.utils import timezone
class Article(models.Model):
"""
博客帖子实体
"""
id = models.AutoField(primary_key=True)
title = models.CharField('标题', max_length=100)
type = models.ForeignKey(ArticleType, on_delete=models.CASCADE, verbose_name='帖子类别')
content = models.CharField('内容', max_length=1000)
author = models.ForeignKey(MyUser, on_delete=models.CASCADE, verbose_name='用户')
image = models.ImageField('文章图片', blank=True, upload_to='article/')
reads = models.IntegerField('阅读量', default=0)
abstract = models.CharField('摘要', max_length=300)
create_time = models.DateTimeField('创建时间', default=timezone.now)
update_time = models.DateTimeField('更新时间', auto_now=True)
def __str__(self):
return self.title
class Meta:
verbose_name = '博客帖子管理'
verbose_name_plural = '博客帖子管理'
再通过makemigrations,migrate,生成数据库表,
makemigrations article
migrate
新建查询,输入以下sql代码:
INSERT INTO `article_article` (`id`, `title`, `content`, `image`, `reads`,`create_time`, `update_time`, `author_id`, `type_id`, `abstract`)
VALUES('1','1','文字是心灵的港湾,是我们与世界相连接的桥梁。在文字的世界里,我们可以感受到历史的沧桑,体味生活的美好。文字是心灵的港湾,是我们与世界相连接的桥梁。在文字的世界里,我们可以感受到历史的沧桑,体味生活的美好。文字是心灵的港湾,是我们与世界相连接的桥梁。在文字的世界里,我们可以感受到历史的沧桑,体味生活的美好。文字是心灵的港湾,是我们与世界相连接的桥梁。在文字的世界里,我们可以感受到历史的沧桑,体味生活的美好。文字是心灵的港湾,是我们与世界相连接的桥梁。在文字的世界里,我们可以感受到历史的沧桑,体味生活的美好。','article/11.png','38','2024-12-04 15:50:55.000000','2024-12-03 15:50:55.000000','1','1','文字是心灵的港湾,是我们与世界相连接的桥梁。');
INSERT INTO `article_article` (`id`, `title`, `content`, `image`, `reads`,`create_time`, `update_time`, `author_id`, `type_id`, `abstract`)
VALUES('2','1','2','article/22.jpg','1','2024-12-03 15:56:24.000000','2024-12-03 15:56:24.000000','1','1','11');
INSERT INTO `article_article` (`id`, `title`, `content`, `image`, `reads`,`create_time`, `update_time`, `author_id`, `type_id`, `abstract`)
VALUES('3','2','2','','1','2024-12-03 15:56:24.000000','2024-12-03 15:56:24.000000','1','1','11');
INSERT INTO `article_article` (`id`, `title`, `content`, `image`, `reads`,`create_time`, `update_time`, `author_id`, `type_id`, `abstract`)
VALUES('4','3','2','','1','2024-12-03 15:56:24.000000','2024-12-03 15:56:24.000000','1','1','11');
INSERT INTO `article_article` (`id`, `title`, `content`, `image`, `reads`, `create_time`, `update_time`, `author_id`, `type_id`, `abstract`) VALUES('5','是的','2','','1','2024-12-01 15:56:24.000000','2024-12-03 15:56:24.000000','1','1','11');
INSERT INTO `article_article` (`id`, `title`, `content`, `image`, `reads`, `create_time`, `update_time`, `author_id`, `type_id`, `abstract`)
VALUES('6','5','2','','1','2024-12-03 15:56:24.000000','2024-12-03 15:56:24.000000','1','1','11');
INSERT INTO `article_article` (`id`, `title`, `content`, `image`, `reads`, `create_time`, `update_time`, `author_id`, `type_id`, `abstract`)
VALUES('7','6','2','','1','2024-12-03 15:56:24.000000','2024-12-03 15:56:24.000000','1','1','11');
INSERT INTO `article_article` (`id`, `title`, `content`, `image`, `reads`, `create_time`, `update_time`, `author_id`, `type_id`, `abstract`)
VALUES('8','7','2','','1','2024-12-03 15:56:24.000000','2024-12-03 15:56:24.000000','1','1','11');
INSERT INTO `article_article` (`id`, `title`, `content`, `image`, `reads`, `create_time`, `update_time`, `author_id`, `type_id`, `abstract`)
VALUES('9','8','好啊是的','','2','2024-12-03 15:56:24.000000','2024-12-03 15:56:24.000000','1','1','11');
INSERT INTO `article_article` (`id`, `title`, `content`, `image`, `reads`, `create_time`, `update_time`, `author_id`, `type_id`, `abstract`)
VALUES('10','9','2','','1','2024-12-02 15:56:24.000000','2024-12-03 15:56:24.000000','1','2','11');
INSERT INTO `article_article` (`id`, `title`, `content`, `image`, `reads`, `create_time`, `update_time`, `author_id`, `type_id`, `abstract`)
VALUES('11','10','2','','1','2024-12-03 15:56:24.000000','2024-12-03 15:56:24.000000','1','2','11');
INSERT INTO `article_article` (`id`, `title`, `content`, `image`, `reads`, `create_time`, `update_time`, `author_id`, `type_id`, `abstract`)
VALUES('12','1','<p>1</p>','','2','2024-12-17 03:26:00.000000','2024-12-17 03:27:26.235658','1','2','1');
INSERT INTO `article_article` (`id`, `title`, `content`, `image`, `reads`, `create_time`, `update_time`, `author_id`, `type_id`, `abstract`)
VALUES('15','带儿子去看植物','<p>太牛逼了。</p>\r\n\r\n<p><img alt=\"\"
src=\"/media/article_images/2024/12/18/login-background.jpg\"
style=\"height:394px; width:700px\" /></p>','article/login-background.jpg','9','2024-12-18 00:18:00.000000','2024-12-18 00:23:33.002701','1','3','超大的仙人掌');
article / views.py 实现下article方法:
from article.models import Article
def article(request, id, page, typeId):
"""
查询帖子信息
:param request:
:return:
"""
print(id, page, typeId)
if typeId == None or typeId == 0:
articleList = Article.objects.filter(author_id=id).order_by('-create_time')
else:
articleList = Article.objects.filter(author_id=id, type_id=typeId).order_by('-create_time')
return render(request, 'article.html', locals())
媒体资源和静态资源请求重写设置,项目urls.py里加下:
# from django.urls import re_path
# from Vlog_system import settings
# from django.views.static import serve
re_path('media/(?P<path>.*)', serve, {'document_root': settings.MEDIA_ROOT}, name='media'),
re_path('static/(?P<path>.*)', serve, {'document_root': settings.STATIC_ROOT}, name='static'),
在media文件夹下新建文件夹article,加入三个图片:11.png 、22.jpg 、login-backeground.jpg;
templates下重写article.html:
{% extends "base.html" %}
{% load static %}
{% block content %}
<div class="data_list">
<div class="data_list_title">
<img src="{% static 'images/list_icon.png' %}"/>
博客列表
</div>
<div class="datas">
{% if not articleList %}
<p style="text-align: center;padding-top: 10px">未查询到结果!</p>
{% else %}
<ul>
{% for article in articleList %}
<li style="margin-bottom: 30px">
<span class="date">
<a href="">{{ article.create_time | date:'Y年m月d日' }}</a>
</span>
<span class="title">
<a href="">{{ article.title }}</a>
</span>
<span class="summary">{{ article.abstract }}</span>
<span class="img">
{% if article.image %}
<img src="{{ article.image.url }}">
{% endif %}
</span>
<span class="info">发表于 {{ article.create_time | date:'Y-m-d H:i' }} 阅读({{ article.reads }})</span>
</li>
<hr style="height:5px;border:none;border-top:1px dashed gray;padding-bottom: 10px;"/>
{% endfor %}
</ul>
{% endif %}
</div>
</div>
{% endblock %}
分页查询博客帖子信息
通过Paginator实现分页;
article/views.py修改article函数
from django.shortcuts import redirect
from user.models import MyUser
from django.urls import reverse
from django.core.paginator import Paginator, PageNotAnInteger, EmptyPage
def article(request, id, page, typeId):
"""
查询帖子信息
:param request:
:return:
"""
print(id, page, typeId)
pageSize = 3 # 每页大小,默认为3个,3个看着最顺眼
user = MyUser.objects.filter(id=id).first()
if not user:
return redirect(reverse('toRegisterPage'))
if typeId == None or typeId == 0:
articleList = Article.objects.filter(author_id=id).order_by('-create_time')
else:
articleList = Article.objects.filter(author_id=id, type_id=typeId).order_by('-create_time')
paginator = Paginator(articleList, pageSize)
try:
pageData = paginator.page(page) # 获取一页数据
except PageNotAnInteger:
pageData = paginator.page(1) # 如果前端传来的页码不是整型,则返回第一页数据
except EmptyPage:
pageData = paginator.page(paginator.num_pages) # 如果前端传来的页码超过实际页数,则返回最后一页数据
return render(request, 'article.html', locals())
结合bootstrap5提供的分页组件以及分页组件自带的属性实现前端分页显示: 分页(Pagination) · Bootstrap v5 中文文档 v5.3 | Bootstrap 中文网
article.html
{% extends "base.html" %}
{% load static %}
{% block content %}
<div class="data_list">
<div class="data_list_title">
<img src="{% static 'images/list_icon.png' %}"/>
博客列表
</div>
<div class="datas">
{% if not pageData.object_list %}
<p style="text-align: center;padding-top: 10px">未查询到结果!</p>
{% else %}
<ul>
{% for article in pageData.object_list %}
<li style="margin-bottom: 30px">
<span class="date">
<a href="">{{ article.create_time | date:'Y年m月d日' }}</a>
</span>
<span class="title">
<a href="">{{ article.title }}</a>
</span>
<span class="summary">{{ article.abstract }}</span>
<span class="img">
{% if article.image %}
<img src="{{ article.image.url }}">
{% endif %}
</span>
<span class="info">发表于 {{ article.create_time | date:'Y-m-d H:i' }} 阅读({{ article.reads }})</span>
</li>
<hr style="height:5px;border:none;border-top:1px dashed gray;padding-bottom: 10px;"/>
{% endfor %}
</ul>
{% endif %}
</div>
</div>
<div>
<nav aria-label="...">
<ul class="pagination">
{% if pageData.has_previous %}
<li class="page-item">
<a class="page-link"
href="{% url 'article' id pageData.previous_page_number typeId %}">上一页</a>
</li>
{% endif %}
{% if pageData.object_list %}
{% for page in pageData.paginator.page_range %}
{% if pageData.number == page %}
<li class="page-item active" aria-current="page">
<a class="page-link" href="{% url 'article' id page typeId %}">{{ page }}</a>
</li>
{% else %}
<li class="page-item">
<a class="page-link" href="{% url 'article' id page typeId %}">{{ page }}</a>
</li>
{% endif %}
{% endfor %}
{% endif %}
{% if pageData.has_next %}
<li class="page-item">
<a class="page-link" href="{% url 'article' id pageData.next_page_number typeId %}">下一页</a>
</li>
{% endif %}
</ul>
</nav>
</div>
{% endblock %}
博客详情帖子页面实现
article / views.py 实现details方法:
def detail(request, id, aId):
"""
根据用户id和帖子id查看详细信息
:param request:
:param id: 作者id
:param aId: 帖子id
:return:
"""
article = Article.objects.filter(id=aId).first()
return render(request, 'detail.html', locals())
templates下新建detail.html
{% extends "base.html" %}
{% load static %}
{% block content %}
<div class="data_list">
<div class="data_list_title">
<img src="{% static 'images/blog_show_icon.png' %}"/>
博客信息
</div>
<div>
<div class="blog_title">
<h3><strong>{{ article.title }}</strong></h3>
</div>
<div class="blog_info">
作者:{{ user.name }} 发布时间:『 {{article.create_time|date:'Y-m-d H:i' }}』 阅读({{ article.reads }})
</div>
<div class="blog_content">
{{ article.content | safe }}
</div>
</div>
</div>
{% endblock %}
safe过滤器可以转移html标签。
article / urls.py 增加映射
# from article.views import detail
path('detail/<int:id>/<int:aId>.html', detail, name="detail"),
article.html 加上帖子详情的链接 {% url 'detail' id article.id %} :
点击测试:
阅读量统计功能通过Django ORM的F()表达式实现原子性更新。在帖子视图处理方法中执行Article.objects.filter(id=aId).update(reads=F('reads')+1),该操作在数据库层面直接对reads字段执行自增运算。这种基于查询表达式的更新方式避免了传统"读取-修改-写入"模式可能引发的竞争条件,同时消除了数据加载到Python层的性能损耗,确保高并发场景下的计数准确性。
article/views.py
# from django.db.models import F
# 阅读量加1
Article.objects.filter(id=aId).update(reads=F('reads') + 1)
博客评论功能实现
评论列表显示
article / models.py 新建留言类Comment:
class Comment(models.Model):
"""
博客帖子评论实体
"""
id = models.AutoField(primary_key=True)
article = models.ForeignKey(Article, on_delete=models.CASCADE, verbose_name='所属文章')
user = models.CharField('评论用户', max_length=60)
content = models.TextField('评论内容')
create_time = models.DateTimeField('创建时间', default=timezone.now)
author = models.ForeignKey(MyUser, on_delete=models.CASCADE, verbose_name='帖子作者')
def __str__(self):
return self.content
class Meta:
verbose_name = '评论管理'
verbose_name_plural = '评论管理'
再通过makemigrations,migrate,生成数据库表,
makemigrations article
migrate
以及添加以下数据:
INSERT INTO `article_comment` (`id`, `user`, `content`, `create_time`, `article_id`, `author_id`) VALUES('1','jack','11111','2024-12-06 17:34:16.000000','1','1');
INSERT INTO `article_comment` (`id`, `user`, `content`, `create_time`, `article_id`, `author_id`) VALUES('2','张三','222','2024-12-06 17:34:58.000000','1','1');
INSERT INTO `article_comment` (`id`, `user`, `content`, `create_time`, `article_id`, `author_id`) VALUES('3','匿名用户','11','2024-12-06 13:04:21.494838','1','1');
INSERT INTO `article_comment` (`id`, `user`, `content`, `create_time`, `article_id`, `author_id`) VALUES('4','匿名用户','3232','2024-12-06 13:05:40.925858','1','1');
INSERT INTO `article_comment` (`id`, `user`, `content`, `create_time`, `article_id`, `author_id`) VALUES('5','匿名用户','eewew','2024-12-06 00:00:00.000000','1','1');
INSERT INTO `article_comment` (`id`, `user`, `content`, `create_time`, `article_id`, `author_id`) VALUES('6','匿名用户','方式电风扇','2024-12-06 21:08:18.300357','1','1');
INSERT INTO `article_comment` (`id`, `user`, `content`, `create_time`, `article_id`, `author_id`) VALUES('7','11','11','2024-12-13 18:06:34.000000','1','1');
INSERT INTO `article_comment` (`id`, `user`, `content`, `create_time`, `article_id`, `author_id`) VALUES('8','11','牛逼','2024-12-28 17:22:27.041900','15','1');
INSERT INTO `article_comment` (`id`, `user`, `content`, `create_time`, `article_id`, `author_id`) VALUES('9','666','不错!','2024-12-28 18:05:42.221089','15','1');
article / views.py / detail方法,增加博客评论信息获取功能:
from article.models import Comment
def detail(request, id, aId):
"""
根据用户id和帖子id查看详细信息
:param request:
:param id: 作者id
:param aId: 帖子id
:return:
"""
article = Article.objects.filter(id=aId).first()
# 阅读量加1
Article.objects.filter(id=aId).update(reads=F('reads') + 1)
# 获取博客评论信息
commentList = Comment.objects.filter(article_id=aId).order_by('-create_time')
return render(request, 'detail.html', locals())
detail.html 增加 评论列表信息显示(这里贴上整个修改后的html代码):
{% extends "base.html" %}
{% load static %}
{% block content %}
<div class="data_list">
<div class="data_list_title">
<img src="{% static 'images/blog_show_icon.png' %}"/>
博客信息
</div>
<div>
<div class="blog_title">
<h3><strong>{{ article.title }}</strong></h3>
</div>
<div class="blog_info">
作者:{{ user.name }} 发布时间:『 {{article.create_time|date:'Y-m-d H:i' }}』 阅读({{ article.reads }})
</div>
<div class="blog_content">
{{ article.content | safe }}
</div>
</div>
</div>
<div class="data_list">
<div class="data_list_title">
<img src="{% static 'images/comment_icon.png' %}"/>
评论信息
</div>
<div class="commentDatas">
{% if not commentList %}
暂无评论
{% else %}
{% for comment in commentList %}
<div class="comment">
<span><font>{{ forloop.counter }}楼
{{ comment.user }}:</font>{{ comment.content}} [ {{ comment.create_time|date:"Y-m-d H:i" }} ]</span>
</div>
{% endfor %}
{% endif %}
</div>
</div>
{% endblock %}
添加评论功能实现
要实现添加评论的功能, 我们可以通过HTTP方法分派实现视图复用的方法实现这个功能。即在detail视图函数中,根据请求类型进行逻辑分支处理——响应GET请求时展示数据列表,处理POST请求时执行新增操作。
article / views.py / detail方法
import datetime
def detail(request, id, aId):
"""
根据用户id和帖子id查看详细信息
:param request:
:param id: 作者id
:param aId: 帖子id
:return:
"""
if request.method == 'GET': # 查询帖子信息
article = Article.objects.filter(id=aId).first()
# 阅读量加1
Article.objects.filter(id=aId).update(reads=F('reads') + 1)
# 获取博客评论信息
commentList = Comment.objects.filter(article_id=aId).order_by('-create_time')
return render(request, 'detail.html', locals())
else: # 添加评论信息
user = request.POST.get("user")
content = request.POST.get("content")
value = {'user': user, 'content': content, 'article_id': aId,
'create_time': datetime.datetime.now(),
'author_id': id}
Comment.objects.create(**value)
kwargs = {'id': id, 'aId': aId}
return redirect(reverse('detail', kwargs=kwargs))
detail.html 加下 提交表单,和验证js:
<div class="data_list">
<div class="data_list_title">
<img src="{% static 'images/publish_comment_icon.png' %}"/>
发表评论
</div>
<div class="publish_comment">
<form action="" method="post" onsubmit="return checkForm()">
{% csrf_token %}
<div style="padding: 5px">
用户:<input type="text" id="user" name="user" value="匿名用户">
</div>
<div>
<textarea style="width: 100%" rows="3" id="content" name="content"
placeholder="来说两句吧..."></textarea>
</div>
<div class="publishButton">
<button class="btn btn-primary" type="submit">发表评论</button>
</div>
</form>
</div>
</div>
{% block script %}
<script>
function checkForm() {
var user = $("#user").val();
var content = $("#content").val();
if (content == null || content == '') {
alert("请输入评论内容!");
return false;
} else if (user == null || user == '') {
alert("请填写用户!");
return false;
}
return true;
}
</script>
{% endblock %}
测试一下:
我的相册功能实现
我们会发现,这个我的相册功能,右侧和其他模块不一样。所以我们开发的话,可以在建一个公共父类 模版,base2.html
<!DOCTYPE html>
<html lang="en">
<head>
{% load static %}
<meta charset="UTF-8">
<title>{% block title %}博客首页{% endblock %}-Powered by python222</title>
<link href="{% static "bootstrap-5.3.3/css/bootstrap.css" %}" rel="stylesheet"/>
<link href="{% static "css/blog.css" %}" rel="stylesheet"/>
<script src="{% static "bootstrap-5.3.3/js/bootstrap.js" %}"></script>
<script src="{% static "js/jquery-1.11.2.min.js" %}"></script>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-4">
<img style="width: 326px;height: 60px" alt="开源博客系统" src="{% static "images/screenshot-logo.png" %}">
</div>
<div class="col-md-8">
<iframe style="float: right;" width="400" scrolling="no" height="60" frameborder="0" allowtransparency="true" src="http://i.tianqi.com/index.php?c=code&id=12&icon=1&num=5"></iframe>
</div>
</div>
<div class="row">
<div class="col-md-12" style="padding-top: 10px;padding-bottom: 10px">
<nav class="navbar navbar-expand-lg bg-body-tertiary">
<div class="container-fluid">
<a class="navbar-brand" href="{% url 'article' id 1 0 %}">博客首页</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item">
<a class="nav-link" href="{% url 'album' id 1%}">我的相册</a>
</li>
<li class="nav-item">
<a class="nav-link" href="">关于我</a>
</li>
<li class="nav-item">
<a class="nav-link" href="">留言</a>
</li>
<li class="nav-item">
<a class="nav-link" href="">博客后台管理</a>
</li>
</ul>
<form class="d-flex" role="search" method="post" action="" onsubmit="return checkSearchForm()">
{% csrf_token %}
<input class="form-control me-2" type="search" placeholder="请输入搜索内容..." aria-label="Search" name="v" id="v" value="{{v }}">
<button class="btn btn-outline-success" type="submit">Search</button>
</form>
</div>
</div>
</nav>
</div>
</div>
<div class="row">
<div class="col-md-12">
{% block content %}{% endblock %}
</div>
</div>
<div class="row">
<div class="col-md-12">
<div align="center" style="padding-top: 120px">
<span style="float: left;">Powered by <a href="http://python222.com" target="_blank">小龙ssss</a></span>
Copyright © 2023-2025 小龙ssss 版权所有
</div>
</div>
</div>
</div>
{% block script %}{% endblock %}
<script>
function checkSearchForm() {
var v = $("#v").val();
if (v == null || v == '') {
alert("请输入搜索内容!");
return false;
}
return true;
}
</script>
</body>
</html>
album / models.py 新建相册类:
from django.db import models
from user.models import MyUser
class AlbumInfo(models.Model):
id = models.AutoField(primary_key=True)
user = models.ForeignKey(MyUser, on_delete=models.CASCADE, verbose_name='用户')
title = models.CharField('标题', max_length=50, blank=True)
introduce = models.CharField('描述', max_length=200, blank=True)
photo = models.ImageField('图片', blank=True, upload_to='album/')
def __str__(self):
return self.title
class Meta:
verbose_name = '图片墙管理'
verbose_name_plural = '图片墙管理'
再通过makemigrations,migrate,生成数据库表,
makemigrations album
migrate album
以及添加下数据:
INSERT INTO `album_albuminfo` (`id`, `title`, `introduce`, `photo`, `user_id`) VALUES('1','图片1','图片1介绍','album/1.jpg','1');
INSERT INTO `album_albuminfo` (`id`, `title`, `introduce`, `photo`, `user_id`) VALUES('2','图片2','图片2介绍','album/2.jpg','1');
INSERT INTO `album_albuminfo` (`id`, `title`, `introduce`, `photo`, `user_id`) VALUES('3','图片3','图片3介绍','album/3.jpg','1');
INSERT INTO `album_albuminfo` (`id`, `title`, `introduce`, `photo`, `user_id`) VALUES('4','图片4','图片4介绍','album/4.jpg','1');
INSERT INTO `album_albuminfo` (`id`, `title`, `introduce`, `photo`, `user_id`) VALUES('5','图片5','图片5介绍','album/5.jpg','1');
INSERT INTO `album_albuminfo` (`id`, `title`, `introduce`, `photo`, `user_id`) VALUES('6','图片6','图片6介绍','album/6.jpg','1');
INSERT INTO `album_albuminfo` (`id`, `title`, `introduce`, `photo`, `user_id`) VALUES('7','图片7','图片7介绍','album/7.jpg','1');
INSERT INTO `album_albuminfo` (`id`, `title`, `introduce`, `photo`, `user_id`) VALUES('8','图片8','图片8介绍','album/8.jpg','1');
INSERT INTO `album_albuminfo` (`id`, `title`, `introduce`, `photo`, `user_id`) VALUES('9','图片9','图片9介绍','album/9.jpg','1');
INSERT INTO `album_albuminfo` (`id`, `title`, `introduce`, `photo`, `user_id`) VALUES('10','图片10','图片10介绍','album/10.jpg','1');
INSERT INTO `album_albuminfo` (`id`, `title`, `introduce`, `photo`, `user_id`) VALUES('11','图片11','图片11介绍','album/11.jpg','1');
INSERT INTO `album_albuminfo` (`id`, `title`, `introduce`, `photo`, `user_id`) VALUES('13','1','2','album/33.jpg','1');
INSERT INTO `album_albuminfo` (`id`, `title`, `introduce`, `photo`, `user_id`) VALUES('14','我去1','不从啊','album/55.jpg','1');
album / views.py 新建album方法,处理页面请求:
from django.core.paginator import Paginator, PageNotAnInteger, EmptyPage
from django.shortcuts import render
from album.models import AlbumInfo
def album(request, id, page):
"""
分页查询查询图片墙信息
:param request:
:return:
"""
pageSize = 6 # 每页大小
albumList = AlbumInfo.objects.filter(user_id=id)
paginator = Paginator(albumList, pageSize)
try:
pageData = paginator.page(page) # 获取一页数据
except PageNotAnInteger:
pageData = paginator.page(1) # 如果前端传来的页码不是整型,则返回第一页数据
except EmptyPage:
pageData = paginator.page(paginator.num_pages) # 如果前端传来的页码超过实际页数,则返回最后一页数据
return render(request, 'album.html', locals())
album / urls.py 加下映射:
from django.urls import path
from album.views import album
urlpatterns = [
# 相册列表
path('<int:id>/<int:page>.html', album, name='album'),
]
项目本身的urls.py的urlpatterns加上:
path('album/', include('album.urls')), # 相册模块
templates下新建album.html,注意,是继承base2.html模版
{% extends "base2.html" %}
{% block title %}相册{% endblock %}
{% load static %}
{% block content %}
<div class="row" style="padding: 10px">
{% for album in pageData.object_list %}
<div class="col-md-2">
<i><img style="width: 200px;height: 200px" src="{{album.photo.url }}"></i>
<div style="padding: 3px">
<h5 style="border-bottom: #ccc 1px solid;padding-top:10px;padding-bottom: 5px">
<strong>{{ album.title }}</strong>
</h5>
<span>{{ album.introduce }}</span>
</div>
</div>
{% endfor %}
</div>
<div class="row">
<nav aria-label="...">
<ul class="pagination" style="justify-content: center;padding-top:20px">
{% if pageData.has_previous %}
<li class="page-item">
<a class="page-link" href="{% url 'album' id pageData.previous_page_number %}">上一页</a>
</li>
{% endif %}
{% if pageData.object_list %}
{% for page in pageData.paginator.page_range %}
{% if pageData.number == page %}
<li class="page-item active" aria-current="page">
<a class="page-link" href="{% url 'album' id page %}">{{ page }}</a>
</li>
{% else %}
<li class="page-item"><a class="page-link" href="{% url 'album' id page %}">{{ page }}</a>
</li>
{% endif %}
{% endfor %}
{% endif %}
{% if pageData.has_next %}
<li class="page-item">
<a class="page-link" href="{% url 'album' id pageData.next_page_number %}">下一页</a>
</li>
{% endif %}
</ul>
</nav>
</div>
{% endblock %}
base.html和base2.html模版我的相册菜单链接都改成url调用: {% url 'album' id 1 %}
成功!
后续
持续开发中。。。