整体设计思路

  1. 1. 应该包含的内容:应该包含标签,随笔,档案三个类别
  2. 2. 处理请求的逻辑:一般由URL匹配路径,views负责数据处理以及表查询,最后由render渲染指定页面,如果有表查询,则数据也通过runder传递,并且由模板标签显示
  3. 3. 数据查询的方式
  4. 1. 第一个查询的目标:所有的[标题,category分类下有多少篇文章];
  5. 2.
  6. 4. 日期归档查询
  7. 1. date_format
  8. ==============date, time, datetime======================
  9. create table t_mul(d, date, t time, dt datetime);
  10. insert into t_mul values(now(), now(), now());
  11. select * form t_mul;
  12. mysql>select * from t_mul;
  13. +------------+------------+--------------------|
  14. | d + t | dt |
  15. +------------+------------+--------------------|
  16. | 2017-08-01 | 19:42:22 | 2017-08-01 19:42:22|
  17. +------------+------------+--------------------|
  18. select date_format(dt, "%Y/%m%/d")from t_mul;
  19. 5. extra
  20. 参数说明
  21. extra(self, select=None, where=None, params=None, tables=None,order_by=None, select_params=None)
  22. 功能描述
  23. """Add extra SQL fragments to the query."""
  24. ret = models.Category.objects.extra(select={'is_recent':"create_time > '2021-08-25'"})
  25. 描述: 结果集中每个Entry对象的都有一个额外的属性```is_recent``` 它是一个布尔值,表示Article的对象create_time 是否晚于20210906

辅助性知识增加

数据库日期查询

  1. mysql> select action_time from django_admin_log;
  2. +----------------------------+
  3. | action_time |
  4. +----------------------------+
  5. | 2021-09-03 04:44:22.186919 |
  6. | 2021-09-03 04:49:20.520822 |
  7. | 2021-09-03 07:12:52.348922 |
  8. | 2021-09-03 07:13:38.546223 |
  9. | 2021-09-03 07:13:58.242131 |
  10. | 2021-09-03 07:14:15.347263 |
  11. | 2021-09-03 07:16:10.456608 |
  12. | 2021-09-03 07:16:16.506109 |
  13. | 2021-09-03 07:17:54.765210 |
  14. | 2021-09-03 07:18:01.567483 |
  15. | 2021-09-03 07:18:46.797706 |
  16. | 2021-09-03 07:19:14.759294 |
  17. | 2021-09-03 07:21:18.118932 |
  18. | 2021-09-03 07:21:20.760727 |
  19. | 2021-09-03 13:22:46.382014 |
  20. | 2021-09-03 13:22:58.575269 |
  21. | 2021-09-05 14:56:17.859757 |
  22. | 2021-09-05 14:56:27.985515 |
  23. | 2021-09-05 14:56:39.436340 |
  24. +----------------------------+
  25. 19 rows in set (0.00 sec)
  26. mysql> select date_format(action_time,"%Y-%m-%d") from django_admin_log;
  27. +-------------------------------------+
  28. | date_format(action_time,"%Y-%m-%d") |
  29. +-------------------------------------+
  30. | 2021-09-03 |
  31. | 2021-09-03 |
  32. | 2021-09-03 |
  33. | 2021-09-03 |
  34. | 2021-09-03 |
  35. | 2021-09-03 |
  36. | 2021-09-03 |
  37. | 2021-09-03 |
  38. | 2021-09-03 |
  39. | 2021-09-03 |
  40. | 2021-09-03 |
  41. | 2021-09-03 |
  42. | 2021-09-03 |
  43. | 2021-09-03 |
  44. | 2021-09-03 |
  45. | 2021-09-03 |
  46. | 2021-09-05 |
  47. | 2021-09-05 |
  48. | 2021-09-05 |
  49. +-------------------------------------+
  50. 19 rows in set (0.00 sec)
  51. mysql> select date_format(action_time,"%Y/%m/%d") from django_admin_log;
  52. +-------------------------------------+
  53. | date_format(action_time,"%Y/%m/%d") |
  54. +-------------------------------------+
  55. | 2021/09/03 |
  56. | 2021/09/03 |
  57. | 2021/09/03 |
  58. | 2021/09/03 |
  59. | 2021/09/03 |
  60. | 2021/09/03 |
  61. | 2021/09/03 |
  62. | 2021/09/03 |
  63. | 2021/09/03 |
  64. | 2021/09/03 |
  65. | 2021/09/03 |
  66. | 2021/09/03 |
  67. | 2021/09/03 |
  68. | 2021/09/03 |
  69. | 2021/09/03 |
  70. | 2021/09/03 |
  71. | 2021/09/05 |
  72. | 2021/09/05 |
  73. | 2021/09/05 |
  74. +-------------------------------------+
  75. 19 rows in set (0.00 sec)
  76. mysql>

终端操作数据查询的必备数据

  1. >>> from blog.models import *
  2. >>> from django.db.models import Count
  3. >>> user = UserInfo.objects.first()
  4. >>> user
  5. <UserInfo: developer>
  6. >>> blog = user.blog
  7. >>> blog
  8. <Blog: Yuan的个人博客>

第一个设计—制作IP加username的快捷访问方式

urls.py[36] & views.py

  1. """whereabouts URL Configuration
  2. The `urlpatterns` list routes URLs to views. For more information please see:
  3. https://docs.djangoproject.com/en/3.2/topics/http/urls/
  4. Examples:
  5. Function views
  6. 1. Add an import: from my_app import views
  7. 2. Add a URL to urlpatterns: path('', views.home, name='home')
  8. Class-based views
  9. 1. Add an import: from other_app.views import Home
  10. 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
  11. Including another URLconf
  12. 1. Import the include() function: from django.urls import include, path
  13. 2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
  14. """
  15. from django.contrib import admin
  16. from django.urls import path, include, re_path
  17. from django.conf import settings
  18. from django.conf.urls.static import static
  19. from blog import views
  20. urlpatterns = [
  21. path('admin/', admin.site.urls),
  22. path('summernote/', include('django_summernote.urls')),
  23. # http://127.0.0.1:8001/login/
  24. path('login/', views.login),
  25. # http://127.0.0.1:8001/logout/
  26. path('logout/', views.logout),
  27. path('get_validCode_img/', views.get_validCode_img),
  28. # http://127.0.0.1:8001/index/
  29. path('index/', views.index),
  30. # http://127.0.0.1:8001/
  31. re_path('^$', views.index),
  32. # http://127.0.0.1:8001/registry/
  33. path('registry/', views.registry),
  34. # 个人站点URL
  35. re_path('^(?P<username>\w+)$', views.home_site),
  36. ]
  37. if settings.DEBUG:
  38. urlpatterns += static(settings.MEDIA_URL, document_root = settings.MEDIA_ROOT)
  39. #########################################################################################
  40. def home_site(request, username):
  41. """
  42. 个人站点视图函数
  43. """
  44. print("username", username)
  45. return render(request, "blog/home_site.html")

被渲染网页home_site.html

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>个人站点表</title>
  6. </head>
  7. <body>
  8. </body>
  9. </html>

实现效果

个人站点 - 图1

第二个设计—过滤用户,若不存在则返回404

views.py

  1. def home_site(request, username):
  2. """
  3. 个人站点视图函数
  4. """
  5. print("username", username)
  6. ret=UserInfo.objects.filter(username=username).exists()
  7. # 判断用户是否存在
  8. if not ret:
  9. return render(request, "blog/not_found.html")
  10. #
  11. return render(request, "blog/home_site.html")

home_site.html

  1. <!DOCTYPE html>
  2. {% load static %}
  3. <html lang="en">
  4. <head>
  5. <meta charset="UTF-8">
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  7. <link rel="stylesheet" href="{% static 'static/blog/css/home_site_self.css' %}">
  8. <title>404 - 页面丢失啦</title>
  9. </head>
  10. <body>
  11. <div class="main-container">
  12. <img class="img-container container-item">
  13. <img src="{% static 'static/blog/img/profile.png' %}" style="width: 40vw;
  14. position: fixed;
  15. left: 50%;
  16. top: 50%;
  17. transform: translate(-50%,-50%);">
  18. </img>
  19. <div class="text-container container-item">
  20. <div class="code">404</div>
  21. <div class="msg">你查看的页面貌似丢失了呢...</div>
  22. <div class="action">请确认您输入的网址正确,若问题持续存在,请发送邮件至 419997284@qq.com,与CaesarTylor联系</div>
  23. <div class="action"><p><a href="/">返回网站首页</a></p></div>
  24. </div>
  25. </div>
  26. </body>
  27. </html>

home_site_self.css

  1. * {
  2. padding: 0;
  3. margin: 0;
  4. }
  5. html {
  6. height: 100%;
  7. }
  8. /*
  9. #E71D36
  10. #FF9F1C
  11. */
  12. body {
  13. background: #FF9F1C;
  14. animation: bodyAction 2s ease-in-out;
  15. }
  16. @keyframes bodyAction {
  17. 0% {
  18. background: #E71D36;
  19. }
  20. 100% {
  21. background: #FF9F1C ;
  22. }
  23. }
  24. .num {
  25. font-size: 200px;
  26. position: fixed;
  27. color: #FF9F1C;
  28. text-shadow: 5px 0 0 #000;
  29. }
  30. .num span {
  31. display: block;
  32. vertical-align: top;
  33. height: 200px;
  34. width: 180px;
  35. text-align: center;
  36. line-height: 200px;
  37. }
  38. .num .check {
  39. color: #E71D36;
  40. }
  41. @keyframes checkAction {
  42. 0% {
  43. color: #FF9F1C;
  44. }
  45. 100% {
  46. color: #E71D36;
  47. }
  48. }
  49. .num.num1 {
  50. top: -1600px;
  51. left: calc(50% - 400px);
  52. animation: num1Action 2s ease-in-out;
  53. }
  54. @keyframes num1Action {
  55. 0% {
  56. top: 0px;
  57. }
  58. 100% {
  59. top: -1600px;
  60. /* color: #E71D36; */
  61. }
  62. }
  63. .num.num2 {
  64. left: calc(50% - 200px);
  65. top: -1200px;
  66. animation: num2Actoin 2s ease-in-out;
  67. }
  68. @keyframes num2Actoin {
  69. 0% {
  70. top: 0px;
  71. }
  72. 100% {
  73. top: -1200px;
  74. /* color: #E71D36; */
  75. }
  76. }
  77. .num.num3 {
  78. left: calc(50% + 0px);
  79. top: -1600px;
  80. animation: num3Actoin 2s ease-in-out;
  81. }
  82. @keyframes num3Actoin {
  83. 0% {
  84. top: 0px;
  85. }
  86. 100% {
  87. top: -1600px;
  88. /* color: #E71D36; */
  89. }
  90. }
  91. .num.num4 {
  92. left: calc(50% + 200px);
  93. top: -1200px;
  94. animation: num4Actoin 2s ease-in-out;
  95. }
  96. @keyframes num4Actoin {
  97. 0% {
  98. top: 0px;
  99. }
  100. 100% {
  101. top: -1200px;
  102. /* color: #E71D36; */
  103. }
  104. }

最终效果

个人站点 - 图2

问题记录

  1. Cannot resolve keyword 'article' into field. Choices are: Article_category, blog, blog_id, nid, title

关联代码

  1. ret=models.Category.objects.values("pk").annotate(c=Count("article__title")).values("title","c")

知识点—聚合查询

  1. https://docs.djangoproject.com/zh-hans/3.2/topics/db/aggregation/

第三个设计—-如何添加Tag标签

第一种在数据库中插入

个人站点 - 图3

第二种后台管理页面添加[面向对象]

个人站点 - 图4

数据库关系说明

  1. 1. 左侧第一栏是自动排序,第二栏是用户创建的title 第三栏则是绑定用户ID,此ID来自于UserInfonid
  2. 2. 在后台添加时则需要选择对应的个人站点,也就相当于第三列中blog的标记

个人站点 - 图5

个人站点 - 图6

第四个设计:从数据库查询数据

整体设计思路

  1. 1. 需要查询的数据:
  2. 当前用户或者当前站点对应的所有文章
  3. 查询每一个分类名称以及对应的文章数
  4. 查询当前站点的每一个分类名称以及对应的文章数目
  5. 查询当前站点的每一个标签名称以及对应的文章数
  6. 2. 查询的路径以及优缺点分析
  7. 1. Python console 查询,优点:无需频繁切换浏览器与控制台输出,几乎不需要等待;缺点:变量命令麻烦,需要导入包;数据更新需要退出再重新进入;每次进出数据不能保存;
  8. 2. IDE + browser 查询,优点:可视化,美观;数据库迁移与数据查询分开,前者不影响数据显示;变量和导包报错可以保存为固定代码,无需重复敲代码;
  9. 3. 细节处理
  10. 1. 查询的时候应该仔细检查该表下有那些字段,避免字段错误造成重复报错;db_column会修改列名,因此需要注意字段名是否正确;
  11. 2. tagarticle之间毫无关系,连路人都算不上,但是他们通过blog_id联系起来,一个人发表多篇文章,它又希望给文章绑定tag标签,但是由于两表完全没有关系,那么就建立一个中间表,专门用来绑定tagarticle的关系;
  12. 3. 对抽取数据的表达选择上,使用list类型的原因是;在展示数据时,可以用索引分开一个变量传递过来的数据,实现对数据的分类;
  13. 4. 可扩展性与数据隔离
  14. 1. 为了实现原地跳转展示信息,URL部分用conditionparam做数据分流,此处留有扩展性,还可以做多个下拉菜单一样的两级内容展示;
  15. 2. 用于数据查询中的条件匹配的两个变量,如何隔离存储;
  16. 3. 前端展示中,预期后期会为多个H5文件制作模板,然后以模板标签嵌入多个实例中;H5中的Bootstrap语法部分[panel]可以重用,代码重构;

查询标签Tag以及对应的文章数

  1. # 能够查出数据的查询语句
  2. tags = models.Tag.objects.values('pk').annotate(c=Count("blog_id")).values("title", "c").filter(blog_id=blog)
  3. 标签名称以及对应的文章数<QuerySet [{'title': 'DS', 'c': 1}, {'title': '服务器', 'c': 1}]>
  4. # 不进行过滤
  5. tags = models.Tag.objects.values('pk').annotate(c=Count("blog_id")).values("title", "c")
  6. 标签名称以及对应的文章数<QuerySet [{'title': '前端', 'c': 1}, {'title': 'DS', 'c': 1}, {'title': '软件工程', 'c': 1}, {'title': '数据库', 'c': 1}, {'title': '服务器', 'c': 1}]>
  7. # 能拿到数据的查询方法
  8. tags = models.Tag.objects.values('pk').annotate(c=Count("article")).values("title", "c").exclude(blog_id = nid)
  9. <QuerySet [{'title': '前端', 'c': 1}, {'title': '软件工程', 'c': 1}]>
  10. 标签名称以及对应的文章数<QuerySet [{'title': '前端', 'c': 1}, {'title': '软件工程', 'c': 1}, {'title': '数据库', 'c': 0}]>
  11. # 最终的匹配语句 用tag中的blog_id与用户的blog_id做匹配,后者要先从userinfo表中取得
  12. tags = models.Tag.objects.values('pk').annotate(c=Count("article")).values("title", "c").filter(blog_id=nid)
  13. <QuerySet [{'title': '前端', 'c': 1}, {'title': '软件工程', 'c': 1}]>
  14. 标签名称以及对应的文章数<QuerySet [{'title': 'DS', 'c': 2}, {'title': '服务器', 'c': 0}]> # 用户Alex的数据

查询当前站点每一个年月的名称以及对应的文章数—-单表分组查询

日期过滤语句的演练

  1. mysql> select date_format(create_time,"%Y/%m/%d") from 文章表;
  2. +-------------------------------------+
  3. | date_format(create_time,"%Y/%m/%d") |
  4. +-------------------------------------+
  5. | 2021/09/03 |
  6. | 2021/09/03 |
  7. | 2021/09/03 |
  8. | 2021/09/07 |
  9. +-------------------------------------+

逐步求解

  1. # 在django的查询语句中引入SQL语句,且查询结果用0/1标注,而非只显示目标内容
  2. era = models.Article.objects.extra(select={"is_recent":"create_time > '2021-09-07'"}).values("title", "is_recent")
  3. print(era)
  4. <QuerySet [{'is_recent': 0, 'title': 'spring 快速入门'}, {'is_recent': 0, 'title': '数据结构与算法——查找算法-斐波那契(黄金分割法)查找'}, {'is_recent': 0, 'title': '5M1E,软件质量管理最佳解决方案'}, {'is_recent': 1, 'title': 'LeetCode通关:通过排序一次秒杀五道题,舒服!'}]>
  5. era_a = models.Article.objects.extra(select={"y_m_d_date":"date_format(create_time,'%%Y-%%m-%%d')"}).values('title', 'y_m_d_date')
  6. <QuerySet [{'y_m_d_date': '2021-09-03', 'title': 'spring 快速入门'}, {'y_m_d_date': '2021-09-03', 'title': '数据结构与算法——查找算法-斐波那契(黄金分割法)查找'}, {'y_m_d_date': '2021-09-03', 'title': '5M1E,软件质量管理最佳解决方案'}, {'y_m_d_date': '2021-09-07', 'title': 'LeetCode通关:通过排序一次秒杀五道题,舒服!'}]>
  7. # 注意时间过滤规则的书写,可类比sqlite语法
  8. era_a = models.Article.objects.extra(select={"y_m_d_date": "date_format(create_time,'%%Y-%%m-%%d')"}).values( 'title', 'y_m_d_date')
  9. <QuerySet [{'y_m_d_date': '2021-09-03', 'title': 'spring 快速入门'}, {'y_m_d_date': '2021-09-03', 'title': '数据结构与算法——查找算法-斐波那契(黄金分割法)查找'}, {'y_m_d_date': '2021-09-03', 'title': '5M1E,软件质量管理最佳解决方案'}, {'y_m_d_date': '2021-09-07', 'title': 'LeetCode通关:通过排序一次秒杀五道题,舒服!'}]>
  10. # 用article中的user与userinfo中的nid做匹配,用于过滤不属于当前对象的文章
  11. era_b = models.Article.objects.filter(user=nid).extra(select={"y_m_date": "date_format(create_time,'%%Y-%%m')"}).values( 'y_m_date').annotate(c=Count("nid")).values('y_m_date', 'c')
  12. <QuerySet [{'y_m_date': '2021-09-03', 'c': 1}, {'y_m_date': '2021-09-07', 'c': 1}]>

第五个设计:个人站点页面样式设计

head设计

源码

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>个人站点表</title>
  6. <style>
  7. *{
  8. margin:0;
  9. padding:0;
  10. }
  11. .header{
  12. width: 100%;
  13. height:60px;
  14. background-color: #d3dce6;
  15. }
  16. .header .title{
  17. font-size:18px;
  18. font-weight:100;
  19. line-height:60px; /*设置上下居中*/
  20. color:lightpink;
  21. margin-left: 14px;
  22. margin-top: -10px;
  23. }
  24. .backend{
  25. float:right;
  26. color:darkslategrey;
  27. text-decoration: none; /*去掉多余的下划线*/
  28. font-size:16px;
  29. margin-left: 10px;
  30. margin-top: 10px; /*文字下移*/
  31. }
  32. </style>
  33. </head>
  34. <body>
  35. <div class="header">
  36. <div class="content">
  37. <p class="title">
  38. <span>{{ blog.title }}</span>
  39. <a href="" class="backend">管理</a>
  40. </p>
  41. </div>
  42. </div>
  43. </body>
  44. </html>

效果

个人站点 - 图7

文章表的渲染

源码

  1. <div class="container">
  2. <div class="row">
  3. <div class="col-md-3"></div>
  4. <div class="col-md-9">
  5. <div class="article_list">
  6. {% for article in article_list%}
  7. <div class="article_item clearfix">
  8. <h5><a href="">{{ article.title }}</a></h5>
  9. <div class="article-desc">
  10. {{ article.desc }}
  11. </div>
  12. <div class="small pub_info pull-right">
  13. <span>发布于&nbsp;&nbsp;{{ article.create_time|date:"Y-m-d H:i" }}</span>&nbsp;&nbsp;&nbsp;
  14. <span class="glyphicon glyphicon-comment"></span>评论({{ article.comment_count }})&nbsp;&nbsp;&nbsp;
  15. <span class="glyphicon glyphicon-thumbs-up"></span>评论({{ article.up_count }})&nbsp;&nbsp;&nbsp;
  16. </div>
  17. </div>
  18. <hr>
  19. {% endfor %}
  20. </div>
  21. </div>
  22. </div>
  23. </div>

效果

个人站点 - 图8

标签,随笔分类,随笔归档的渲染

源码

  1. <div class="col-md-3">
  2. <div class="panel panel-warning">
  3. <div class="panel-heading">我的标签</div>
  4. <div class="panel-body">
  5. {% for tag in tag_list %}
  6. <p>{{ tag.0 }}({{ tag.1 }})</p>
  7. {% endfor %}
  8. </div>
  9. </div>
  10. <div class="panel panel-danger">
  11. <div class="panel-heading">随笔分类</div>
  12. <div class="panel-body">
  13. {% for cate in cate_list %}
  14. <p>{{ cate.0 }}({{ cate.1 }})</p>
  15. {% endfor %}
  16. </div>
  17. </div>
  18. <div class="panel panel-success">
  19. <div class="panel-heading">随笔归档</div>
  20. <div class="panel-body">
  21. {% for ym in year_month %}
  22. <p>{{ ym.0 }}({{ ym.1 }})</p>
  23. {% endfor %}
  24. </div>
  25. </div>
  26. </div>

效果

个人站点 - 图9

原地跳转访问指定分类或者标签下的所有文章表

处理逻辑以及数据提取和处理

  1. 2. 数据处理过程
  2. 1. 需要查找两类信息,分别根据category & tag找到该用户下的所有文章;
  3. 2. condition交给if 条件语句,专心处理param参数与文章表进行匹配的问题;
  4. 3. param传递的参数是category下的title,由可视化窗口可以观察得到;只能将传递 参数paramtitle进行匹配;
  5. 4. 其次则为筛选用户:category中有blog参数,绑定的值为blog.idblog.nid在用户表中与用户是一对一的关系;还需要确认categoryuser.id之间的关系;
  6. 5. 首先blog为个人站点,user与其为一对一关系,然后通过blogcategory & tag产生依赖关系;
  7. 6. 匹配规则: 第一层判断,如果拿到数据,condition & param就进行匹配,如果没有拿到数据,那么就筛选当前用户的所有文章;第二层逻辑:在拿到数据的情况下,对condition中的categoryparam进行分流,前者从数据库抽取当前用户的blog,blog下的category,然后输出category下的所有文章,后者则获取blogblog下的tag,输出tag下的所有文章;
  8. 3. 修正
  9. category & tag都与blog_nid关联,但是字段名不一样,遂做统一,将tag绑定的blog改为b

源码

  1. # URL
  2. # 个人站点的原地跳转[点击标签触发内容]
  3. re_path('^(?P<username>\w+)/(?P<condition>tag|category|archive)/(?P<param>.*)/$', views.home_site),
  4. # 查询当前站点对象以及id
  5. blog = user.blog
  6. userid = user.nid
  7. nid = blog.nid # 用作原地跳转标签匹配
  8. # 当前用户或者当前站点对应的所有文章
  9. if kwargs:
  10. condition = kwargs.get("condition")
  11. param = kwargs.get("param")
  12. if condition == "category":
  13. article_list = models.Article.objects.filter(category__blog=nid).filter(category__title__icontains=param)
  14. elif condition == 'tag': # 通过tags字段回到Tag
  15. article_list = models.Article.objects.filter(tags__blog_id=nid).filter(tags__title__icontains=param)
  16. else: # filter(user=nid)以当前用户的ID筛选所有文章
  17. article_list = models.Article.objects.filter(user=userid) # 抽取当前用户站点下的所有文章

效果

该效果由后期编写测试样例提供,此刻不再展示

代码优化

V1

  1. """
  2. 个人站点视图函数
  3. """
  4. print("kwargs", kwargs)
  5. print("username",username)
  6. # 查询当前站点对象以及id
  7. blog = user.blog
  8. userid = user.nid
  9. nid = blog.nid # 用作原地跳转标签匹配
  10. # 当前用户或者当前站点对应的所有文章
  11. if kwargs:
  12. condition = kwargs.get("condition")
  13. param = kwargs.get("param") # 2012-12
  14. if condition == "category":
  15. article_list = models.Article.objects.filter(category__blog=nid).filter(category__title__icontains=param)
  16. elif condition == 'tag': # 通过tags字段回到Tag
  17. article_list = models.Article.objects.filter(tags__blog_id=nid).filter(tags__title__icontains=param)
  18. else:
  19. year, month = param.split("-")
  20. article_list = models.Article.objects.filter(category__blog=nid).filter(create_time__year=year,
  21. create_time__month=month)
  22. else:
  23. article_list = models.Article.objects.filter(user=userid) # 抽取当前用户站点下的所有文章
  24. # 查询当前站点的每一个分类名称以及对应的文章数目; 能用Article_category是因为article包含了外键category
  25. cate_list = models.Category.objects.filter(blog__nid=nid).values_list("title").annotate(c=Count("Article_category"))
  26. # 查询当前站点的每一个标签名称以及对应的文章数
  27. tag_list = models.Tag.objects.values('pk').annotate(c=Count("article")).values_list("title", "c").filter(
  28. blog_id=nid)
  29. # 查询当前站点每一个年月的名称以及对应的文章数---单表分组查询
  30. # 引入函数专门处理日期分组:from django.db.models.functions import TruncMonth
  31. year_month = models.Article.objects.filter(user=nid).extra(
  32. select={"y_m_date": "date_format(create_time,'%%Y-%%m')"}).values(
  33. 'y_m_date').annotate(c=Count("nid")).values_list('y_m_date', 'c')
  34. return render(request, "blog/home_site.html",
  35. {"username":username, "blog": blog, "article_list": article_list, "cate_list": cate_list, "tag_list": tag_list,
  36. "year_month": year_month})

V2

  1. """
  2. 个人站点视图函数
  3. """
  4. print("kwargs", kwargs)
  5. print("username",username)
  6. user = models.UserInfo.objects.filter(username=str(username)).first()
  7. if not user:
  8. return render(request, "blog/not_found.html")
  9. # 查询当前站点对象以及id
  10. blog = user.blog
  11. userid = user.nid
  12. nid = blog.nid # 用作原地跳转标签匹配
  13. # 当前用户或者当前站点对应的所有文章
  14. article_list = models.Article.objects.filter(user=userid)
  15. if kwargs:
  16. condition = kwargs.get("condition")
  17. param = kwargs.get("param") # 2012-12
  18. if condition == "category":
  19. article_list = article_list.filter(category__title__icontains=param)
  20. elif condition == 'tag': # 通过tags字段回到Tag
  21. article_list = article_list.filter(tags__title__icontains=param)
  22. else:
  23. year, month = param.split("-")
  24. article_list = article_list.filter(create_time__year=year,
  25. create_time__month=month)
  26. # 查询当前站点的每一个分类名称以及对应的文章数目; 能用Article_category是因为article包含了外键category
  27. cate_list = models.Category.objects.filter(blog__nid=nid).values_list("title").annotate(c=Count("Article_category"))
  28. # 查询当前站点的每一个标签名称以及对应的文章数
  29. tag_list = models.Tag.objects.values('pk').annotate(c=Count("article")).values_list("title", "c").filter(
  30. blog_id=nid)
  31. # 查询当前站点每一个年月的名称以及对应的文章数---单表分组查询
  32. # 引入函数专门处理日期分组:from django.db.models.functions import TruncMonth
  33. year_month = models.Article.objects.filter(user=nid).extra(
  34. select={"y_m_date": "date_format(create_time,'%%Y-%%m')"}).values(
  35. 'y_m_date').annotate(c=Count("nid")).values_list('y_m_date', 'c')
  36. return render(request, "blog/home_site.html",
  37. {"username":username, "blog": blog, "article_list": article_list, "cate_list": cate_list, "tag_list": tag_list,
  38. "year_month": year_month})

数据备份

未辨明原因的数据查询

  1. article_list2 = models.Article.objects.filter()
  2. print("---")
  3. print(article_list2)

可供选择的外键

  1. Cannot resolve keyword 'UserInfo_username' into field. Choices are: Article_category, blog, blog_id, c, nid, title

对个人站点填充数据的数据库查询语句测试

  1. cate_list = models.Category.objects.values("title").annotate(c=Count("Article_category")).filter(blog__title=blog)
  2. <QuerySet [{'title': 'DS', 'c': 2}]>
  3. cate_list = models.Category.objects.values("title").annotate(c=Count("Article_category")).filter(blog__nid=nid)
  4. <QuerySet [{'title': '前端', 'c': 1}, {'title': '软件工程', 'c': 1}]>
  5. cate_list = models.Category.objects.values("title").annotate(c=Count("Article_category")).filter(blog__nid=nid, blog__title=blog)
  6. <QuerySet []>
  7. cate_list=models.Category.objects.values("title").annotate(c=Count("Article_category")).filter(blog__nid=nid).filter(blog__title=blog)
  8. <QuerySet []>

home_site个人站点查询方法及结果保存

  1. def home_site(request, username):
  2. """
  3. 个人站点视图函数
  4. """
  5. print("username", str(username))
  6. user = models.UserInfo.objects.filter(username=str(username)).first()
  7. print('-------------')
  8. print(user)
  9. # 判断用户是否存在
  10. if not user:
  11. return render(request, "blog/not_found.html")
  12. # 查询当前站点对象
  13. blog = user.blog
  14. print("个人站点标题")
  15. print(blog)
  16. nid = blog.nid
  17. print("打印用户的blog_id")
  18. print(nid)
  19. # 当前用户或者当前站点对应的所有文章
  20. # https://docs.djangoproject.com/zh-hans/3.2/topics/db/examples/many_to_one/];2. 跨表查询
  21. # 1.基于对象user查询
  22. article_list = user.Article_user.all()
  23. print("---")
  24. print(article_list)
  25. # 2. 基于外键user_id反向查询
  26. article_list2 = models.Article.objects.filter(user=nid)
  27. print("---")
  28. print(article_list2)
  29. # 查询每一个分类名称以及对应的文章数,models.Category.objects.values("pk").annotate(c=Count("article__title"))
  30. cat_obj = models.Category.objects.values('pk').annotate(c=Count('Article_category')).values('c', 'title')
  31. print("打印分类名称以及对应的文章数" + str(cat_obj))
  32. print("---")
  33. ret = models.Category.objects.values("title").annotate(c=Count("Article_category"))
  34. print("---")
  35. print(ret)
  36. # 查询当前站点的每一个分类名称以及对应的文章数目; 能用Article_category是因为article包含了外键category
  37. cate_list = models.Category.objects.filter(blog__nid=nid).values("title").annotate(c=Count("Article_category"))
  38. # models.Category.objects.filter(blog=blog).annotate(c=Count("Article_category"))
  39. print("---")
  40. print(cate_list)
  41. # 查询当前站点的每一个标签名称以及对应的文章数
  42. tags = models.Tag.objects.values('pk').annotate(c=Count("article")).values("title", "c").filter(blog_id=nid)
  43. print("标签名称以及对应的文章数" + str(tags))
  44. print("---")
  45. # 查询当前站点每一个年月的名称以及对应的文章数---单表分组查询
  46. era = models.Article.objects.extra(select={"is_recent": "create_time > '2021-09-07'"}).values("title", "is_recent")
  47. print(era)
  48. print("---")
  49. era_a = models.Article.objects.extra(select={"y_m_d_date": "date_format(create_time,'%%Y-%%m-%%d')"}).values(
  50. 'title', 'y_m_d_date')
  51. print(era_a)
  52. print("---")
  53. # 用article中的user字段匹配userinfo中的nid
  54. era_b = models.Article.objects.filter(user=nid).extra(select={"y_m_date": "date_format(create_time,'%%Y-%%m')"}).values(
  55. 'y_m_date').annotate(c=Count("nid")).values('y_m_date', 'c')
  56. print(era_b)
  57. print("---")
  58. # 引入函数专门处理日期分组:from django.db.models.functions import TruncMonth
  59. era_c = models.Article.objects.filter(user=nid).annotate(year_month=TruncMonth('create_time')).values('year_month').annotate(c=Count('nid')).values_list("year_month",'c')
  60. print(era_c)
  61. print("------------------------------------------")
  62. return render(request, "blog/home_site.html")

个人站点页面代码简化

  1. def home_site(request, username):
  2. """
  3. 个人站点视图函数
  4. """
  5. user = models.UserInfo.objects.filter(username=str(username)).first()
  6. if not user:
  7. return render(request, "blog/not_found.html")
  8. # 查询当前站点对象以及id
  9. blog = user.blog
  10. nid = blog.nid
  11. # 当前用户或者当前站点对应的所有文章
  12. article_list = user.Article_user.all()
  13. # 查询当前站点的每一个分类名称以及对应的文章数目; 能用Article_category是因为article包含了外键category
  14. cate_list = models.Category.objects.filter(blog__nid=nid).values_list("title").annotate(c=Count("Article_category"))
  15. # 查询当前站点的每一个标签名称以及对应的文章数
  16. tag_list = models.Tag.objects.values('pk').annotate(c=Count("article")).values_list("title", "c").filter(blog_id=nid)
  17. # 查询当前站点每一个年月的名称以及对应的文章数---单表分组查询
  18. # 引入函数专门处理日期分组:from django.db.models.functions import TruncMonth
  19. year_month = models.Article.objects.filter(user=nid).extra(select={"y_m_date": "date_format(create_time,'%%Y-%%m')"}).values(
  20. 'y_m_date').annotate(c=Count("nid")).values_list('y_m_date', 'c')
  21. print(year_month)
  22. return render(request, "blog/home_site.html",{"blog":blog,"article_list":article_list,"cate_list":cate_list,"tag_list":tag_list,"year_month":year_month})

页面跳转[8,16,24]

  1. <div class="container">
  2. <div class="row">
  3. <div class="col-md-3">
  4. <div class="panel panel-warning">
  5. <div class="panel-heading">我的标签</div>
  6. <div class="panel-body">
  7. {% for tag in tag_list %}
  8. <p><a href="/{{ username }}/tag/{{ tag.0 }}">{{ tag.0 }}({{ tag.1 }})</a></p>
  9. {% endfor %}
  10. </div>
  11. </div>
  12. <div class="panel panel-danger">
  13. <div class="panel-heading">随笔分类</div>
  14. <div class="panel-body">
  15. {% for cate in cate_list %}
  16. <p><a href="/{{ username }}/category/{{ cate.0 }}">{{ cate.0 }}({{ cate.1 }})</a></p>
  17. {% endfor %}
  18. </div>
  19. </div>
  20. <div class="panel panel-success">
  21. <div class="panel-heading">随笔归档</div>
  22. <div class="panel-body">
  23. {% for ym in year_month %}
  24. <p><a href="/{{ username }}/archive/{{ ym.0 }}">{{ ym.0 }}({{ ym.1 }})</a></p>
  25. {% endfor %}
  26. </div>
  27. </div>
  28. </div>
  29. <div class="col-md-9">
  30. <div class="article_list">
  31. {% for article in article_list %}
  32. <div class="article_item clearfix">
  33. <h5><a href="">{{ article.title }}</a></h5>
  34. <div class="article-desc">
  35. {{ article.desc }}
  36. </div>
  37. <div class="small pub_info pull-right">
  38. <span>发布于&nbsp;&nbsp;{{ article.create_time|date:"Y-m-d H:i" }}</span>&nbsp;&nbsp;&nbsp;
  39. <span class="glyphicon glyphicon-comment"></span>评论({{ article.comment_count }})&nbsp;&nbsp;&nbsp;
  40. <span class="glyphicon glyphicon-thumbs-up"></span>评论({{ article.up_count }})&nbsp;&nbsp;&nbsp;
  41. </div>
  42. </div>
  43. <hr>
  44. {% endfor %}
  45. </div>
  46. </div>
  47. </div>
  48. </div>

测试URL路径

  1. # 访问时间分类标签
  2. http://127.0.0.1:8001/alex/archive/2021-09/
  3. # 点击随笔分类 category
  4. http://127.0.0.1:8001/alex/category/alex%E7%9A%84DS/
  5. # 点击标签分类 t

状态保存

home_site.html

  1. <!DOCTYPE html>
  2. {% load static %}
  3. <html lang="en">
  4. <head>
  5. <meta charset="UTF-8">
  6. <title>个人站点表</title>
  7. <link rel="stylesheet" href="{% static '/static/blog/bs/css/bootstrap.css' %}">
  8. <style>
  9. * {
  10. margin: 0;
  11. padding: 0;
  12. }
  13. .header {
  14. width: 100%;
  15. height: 60px;
  16. background-color: #d3dce6;
  17. }
  18. .header .title {
  19. font-size: 18px;
  20. font-weight: 100;
  21. line-height: 60px; /*设置上下居中*/
  22. color: lightpink;
  23. margin-left: 14px;
  24. margin-top: -10px;
  25. }
  26. .backend {
  27. float: right;
  28. color: darkslategrey;
  29. text-decoration: none; /*去掉多余的下划线*/
  30. font-size: 16px;
  31. margin-left: 10px;
  32. margin-top: 10px; /*文字下移*/
  33. }
  34. .pub_info {
  35. margin-top: 10px;
  36. color: springgreen;
  37. }
  38. </style>
  39. </head>
  40. <body>
  41. <div class="header">
  42. <div class="content">
  43. <p class="title">
  44. <span>{{ blog.title }}</span>
  45. <a href="" class="backend">管理</a>
  46. </p>
  47. </div>
  48. </div>
  49. <div class="container">
  50. <div class="row">
  51. <div class="col-md-3">
  52. <div class="panel panel-warning">
  53. <div class="panel-heading">我的标签</div>
  54. <div class="panel-body">
  55. {% for tag in tag_list %}
  56. <p><a href="/{{ username }}/tag/{{ tag.0 }}">{{ tag.0 }}({{ tag.1 }})</a></p>
  57. {% endfor %}
  58. </div>
  59. </div>
  60. <div class="panel panel-danger">
  61. <div class="panel-heading">随笔分类</div>
  62. <div class="panel-body">
  63. {% for cate in cate_list %}
  64. <p><a href="/{{ username }}/category/{{ cate.0 }}">{{ cate.0 }}({{ cate.1 }})</a></p>
  65. {% endfor %}
  66. </div>
  67. </div>
  68. <div class="panel panel-success">
  69. <div class="panel-heading">随笔归档</div>
  70. <div class="panel-body">
  71. {% for ym in year_month %}
  72. <p><a href="/{{ username }}/archive/{{ ym.0 }}">{{ ym.0 }}({{ ym.1 }})</a></p>
  73. {% endfor %}
  74. </div>
  75. </div>
  76. </div>
  77. <div class="col-md-9">
  78. <div class="article_list">
  79. {% for article in article_list %}
  80. <div class="article_item clearfix">
  81. <h5><a href="">{{ article.title }}</a></h5>
  82. <div class="article-desc">
  83. {{ article.desc }}
  84. </div>
  85. <div class="small pub_info pull-right">
  86. <span>发布于&nbsp;&nbsp;{{ article.create_time|date:"Y-m-d H:i" }}</span>&nbsp;&nbsp;&nbsp;
  87. <span class="glyphicon glyphicon-comment"></span>评论({{ article.comment_count }})&nbsp;&nbsp;&nbsp;
  88. <span class="glyphicon glyphicon-thumbs-up"></span>评论({{ article.up_count }})&nbsp;&nbsp;&nbsp;
  89. </div>
  90. </div>
  91. <hr>
  92. {% endfor %}
  93. </div>
  94. </div>
  95. </div>
  96. </div>
  97. </body>
  98. </html>

views.py—home_site

  1. def home_site(request, username, **kwargs):
  2. """
  3. 个人站点视图函数
  4. """
  5. print("kwargs", kwargs)
  6. print("username",username)
  7. user = models.UserInfo.objects.filter(username=str(username)).first()
  8. if not user:
  9. return render(request, "blog/not_found.html")
  10. # 查询当前站点对象以及id
  11. blog = user.blog
  12. userid = user.nid
  13. nid = blog.nid # 用作原地跳转标签匹配
  14. # 当前用户或者当前站点对应的所有文章
  15. article_list = models.Article.objects.filter(user=userid)
  16. if kwargs:
  17. condition = kwargs.get("condition")
  18. param = kwargs.get("param") # 2012-12
  19. if condition == "category":
  20. article_list = article_list.filter(category__title__icontains=param)
  21. elif condition == 'tag': # 通过tags字段回到Tag
  22. article_list = article_list.filter(tags__title__icontains=param)
  23. else:
  24. year, month = param.split("-")
  25. article_list = article_list.filter(create_time__year=year,
  26. create_time__month=month)
  27. # 查询当前站点的每一个分类名称以及对应的文章数目; 能用Article_category是因为article包含了外键category
  28. cate_list = models.Category.objects.filter(blog__nid=nid).values_list("title").annotate(c=Count("Article_category"))
  29. # 查询当前站点的每一个标签名称以及对应的文章数
  30. tag_list = models.Tag.objects.values('pk').annotate(c=Count("article")).values_list("title", "c").filter(
  31. blog_id=nid)
  32. # 查询当前站点每一个年月的名称以及对应的文章数---单表分组查询
  33. # 引入函数专门处理日期分组:from django.db.models.functions import TruncMonth
  34. year_month = models.Article.objects.filter(user=nid).extra(
  35. select={"y_m_date": "date_format(create_time,'%%Y-%%m')"}).values(
  36. 'y_m_date').annotate(c=Count("nid")).values_list('y_m_date', 'c')
  37. return render(request, "blog/home_site.html",
  38. {"username":username, "blog": blog, "article_list": article_list, "cate_list": cate_list, "tag_list": tag_list,
  39. "year_month": year_month})

urls.py

  1. """whereabouts URL Configuration
  2. The `urlpatterns` list routes URLs to views. For more information please see:
  3. https://docs.djangoproject.com/en/3.2/topics/http/urls/
  4. Examples:
  5. Function views
  6. 1. Add an import: from my_app import views
  7. 2. Add a URL to urlpatterns: path('', views.home, name='home')
  8. Class-based views
  9. 1. Add an import: from other_app.views import Home
  10. 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
  11. Including another URLconf
  12. 1. Import the include() function: from django.urls import include, path
  13. 2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
  14. """
  15. from django.contrib import admin
  16. from django.urls import path, include, re_path
  17. from django.conf import settings
  18. from django.conf.urls.static import static
  19. from blog import views
  20. urlpatterns = [
  21. path('admin/', admin.site.urls),
  22. path('summernote/', include('django_summernote.urls')),
  23. # http://127.0.0.1:8001/login/
  24. path('login/', views.login),
  25. # http://127.0.0.1:8001/logout/
  26. path('logout/', views.logout),
  27. path('get_validCode_img/', views.get_validCode_img),
  28. # http://127.0.0.1:8001/index/
  29. path('index/', views.index),
  30. # http://127.0.0.1:8001/
  31. re_path('^$', views.index),
  32. # http://127.0.0.1:8001/registry/
  33. path('registry/', views.registry),
  34. # 个人站点的原地跳转[点击标签触发内容]
  35. re_path('^(?P<username>\w+)/(?P<condition>tag|category|archive)/(?P<param>.*)/$', views.home_site),
  36. # 个人站点URL
  37. re_path('^(?P<username>\w+)/$', views.home_site),
  38. # 文章页
  39. re_path('^(?P<username>\w+)/article/(?P<article_id>\d+)$', views.article_detail),
  40. ]
  41. if settings.DEBUG:
  42. urlpatterns += static(settings.MEDIA_URL, document_root = settings.MEDIA_ROOT)

Solved Problems

Database returned an invalid datetime value. Are time zone definitions for your database installed?

  1. # 在settings中修改部分设置
  2. import datetime
  3. from django.utils.timezone import utc
  4. utcnow = datetime.datetime.utcnow().replace(tzinfo=utc)
  5. LANGUAGE_CODE = 'zh-Hans'
  6. TIME_ZONE = 'Asia/Shanghai'
  7. USE_I18N = True
  8. USE_L10N = True
  9. USE_TZ = False

可视化数据库软件DBeaver连接错误的

报错提示

  1. Public Key Retrieval is not allowed
  2. https://blog.csdn.net/qq_42816401/article/details/91303134

处理办法

个人站点 - 图10