报账系统总结(1):路由分配/数据库/主页/注册/登陆

1. 路由分配

1.1 知识点

  1. 为区分主页index中不同的标签请求,使用正则路由匹配
  2. 路由匹配为空时,从上向下匹配时,若上面没有匹配到,则会执行空对应的路由函数

1.2 示例代码

  1. urls.py
  1. # filename: urls.py 
  2. from django.contrib import admin 
  3. from django.urls import path 
  4. from django.conf.urls import url 
  5. from app01 import views 
  6.  
  7. urlpatterns = [ 
  8. path('admin/', admin.site.urls), 
  9. # 正则别名 便于取数据 
  10. url(r'^all/(?P<type_id>d+)', views.index), 
  11. url(r'^login/', views.login), 
  12. url(r'^register/', views.register), 
  13. url(r'^check_code/', views.check_code), 
  14. url(r'^upload_avatar/', views.upload_avatar), 
  15. url(r'^', views.index), 

2. 数据库

2.1 知识点

  1. auto_now_add 与 auto_now的区别
  2. ManyToMany 正反向操作
  3. 联合唯一索引与ManyToMany混合使用
  4. OneToOneField的正反向操作
  5. 枚举的使用

2.2 示例代码

  1. models.py
  1. # filename: models.py 
  2. from django.db import models 
  3.  
  4.  
  5. class UserInfo(models.Model): 
  6. ''' 
  7. 用户信息表 
  8. ''' 
  9. nid = models.BigAutoField(primary_key=True
  10. username = models.CharField(verbose_name='用户名', max_length=32, unique=True
  11. password = models.CharField(verbose_name='密码', max_length=64
  12. nickname = models.CharField(verbose_name='昵称', max_length=32
  13. email = models.EmailField(verbose_name='邮箱', unique=True
  14. avatar = models.ImageField(verbose_name='头像'
  15. # 注意创建时间 
  16. create_time = models.DateField(verbose_name='创建时间', auto_now_add=True
  17. # U2U 
  18. U2U = models.ManyToManyField(verbose_name='粉丝们'
  19. to='UserInfo'
  20. through='UserFans'
  21. through_fields=('user', 'follwers'), 
  22. related_name='fans'
  23.  
  24.  
  25. class UserFans(models.Model): 
  26. ''' 
  27. 互粉关系表 
  28. ''' 
  29. nid = models.BigAutoField(primary_key=True
  30. user = models.ForeignKey(verbose_name='博主', to='UserInfo', to_field='nid', related_name='user', on_delete=models.CASCADE) 
  31. follwers = models.ForeignKey(verbose_name='粉丝', to='UserInfo', to_field='nid', related_name='follwers', on_delete=models.CASCADE) 
  32.  
  33. # 联合唯一索引 
  34. class Meta: 
  35. unique_together = [ 
  36. ('user', 'follwers'), 
  37.  
  38.  
  39. class Blog(models.Model): 
  40. ''' 
  41. 博客信息表 
  42. ''' 
  43. nid = models.BigAutoField(primary_key=True
  44. title = models.CharField(verbose_name='个人博客标题', max_length=64
  45. theme = models.CharField(verbose_name='个人博客主题', max_length=32
  46. site = models.CharField(verbose_name='个人博客域名', max_length=32, unique=True
  47. user = models.OneToOneField(verbose_name='博客用户', to='UserInfo', to_field='nid', on_delete=models.CASCADE) 
  48.  
  49.  
  50. class Article(models.Model): 
  51. ''' 
  52. 文章信息表 
  53. ''' 
  54. nid = models.BigAutoField(primary_key=True
  55. title = models.CharField(verbose_name='文章标题', max_length=128
  56. summary = models.CharField(verbose_name='文章简介', max_length=255
  57. create_time = models.DateTimeField(verbose_name='创建时间', auto_now_add=True
  58. blog = models.ForeignKey(verbose_name='所属博客', to='Blog', to_field='nid', on_delete=models.CASCADE) 
  59. category = models.ForeignKey(verbose_name='文章类型', to='Category', to_field='nid', null=True, on_delete=models.CASCADE) 
  60.  
  61. # 因为牵扯到多次从数据库中获取,会造成多次查询 故直接将常用信息放到article中 
  62. # 数据冗余 
  63. read_count = models.IntegerField(default=0
  64. comment_count = models.IntegerField(default=0
  65. up_count = models.IntegerField(default=0
  66. down_count = models.IntegerField(default=0
  67.  
  68. type_choice = [ 
  69. (1, 'Python'), 
  70. (2, 'Linux'), 
  71. (3, '人工智能'), 
  72. (4, '区块链'), 
  73. (5, 'Golang'), 
  74.  
  75. # 主页文章分类 
  76. article_type_id = models.IntegerField(choices=type_choice, default=None
  77.  
  78. # article to tag 
  79. tags = models.ManyToManyField(verbose_name='标签类型'
  80. to='Tag'
  81. through='Article2Tag'
  82. through_fields=('article', 'tag')) 
  83.  
  84.  
  85. class Category(models.Model): 
  86. ''' 
  87. 个人用户文章分类 
  88. ''' 
  89. nid = models.AutoField(primary_key=True
  90. title = models.CharField(verbose_name='分类标题', max_length=32
  91. blog = models.ForeignKey(verbose_name='所属博客', to='Blog', to_field='nid', on_delete=models.CASCADE) 
  92.  
  93.  
  94. class Tag(models.Model): 
  95. ''' 
  96. 标签表 
  97. ''' 
  98. nid = models.AutoField(primary_key=True
  99. title = models.CharField(verbose_name='标签名称', max_length=32
  100. blog = models.ForeignKey(verbose_name='所属博客', to='Blog', to_field='nid', on_delete=models.CASCADE) 
  101.  
  102.  
  103. class Article2Tag(models.Model): 
  104. ''' 
  105. 文章to标签 多对多 关系表 
  106. ''' 
  107. nid = models.BigAutoField(primary_key=True
  108. article = models.ForeignKey(verbose_name='文章', to='Article', to_field='nid', on_delete=models.CASCADE) 
  109. tag = models.ForeignKey(verbose_name='标签', to='Tag', to_field='nid', on_delete=models.CASCADE) 
  110.  
  111. class Meta: 
  112. unique_together = [ 
  113. ('article', 'tag'), 
  114.  
  115.  
  116. class ArticleDetail(models.Model): 
  117. ''' 
  118. 文章详细表 
  119. ''' 
  120. content = models.TextField(verbose_name='文章内容'
  121. article = models.OneToOneField(verbose_name='所属文章', to='Article', to_field='nid', on_delete=models.CASCADE) 
  122.  
  123.  
  124. class UpDown(models.Model): 
  125. ''' 
  126. 文章 顶/踩 
  127. ''' 
  128. article = models.ForeignKey(verbose_name='所属文章', to='Article', to_field='nid', on_delete=models.CASCADE) 
  129. user = models.ForeignKey(verbose_name='顶或踩的用户', to='UserInfo', to_field='nid', on_delete=models.CASCADE) 
  130. up = models.BooleanField(verbose_name='是否赞'
  131.  
  132. class Meta: 
  133. unique_together = [ 
  134. ('article', 'user'), 
  135.  
  136.  
  137. class Comment(models.Model): 
  138. ''' 
  139. 文章评论表 
  140. ''' 
  141. nid = models.BigAutoField(primary_key=True
  142. content = models.CharField(verbose_name='评论内容', max_length=255
  143. create_time = models.DateTimeField(verbose_name='评论时间', auto_now_add=True
  144. article = models.ForeignKey(verbose_name='被评论文章', to='Article', to_field='nid', on_delete=models.CASCADE) 
  145. user = models.ForeignKey(verbose_name='评论者', to='UserInfo', to_field='nid', on_delete=models.CASCADE) 
  146. reply = models.ForeignKey(verbose_name='被回复评论', to='self', to_field='nid', null=True, on_delete=models.CASCADE) 

3. 主页

3.1 知识点

  1. 获取当前请求request的URL
  2. 数据库操作models.filter(**kwargs)为空字典时,将会获取全部数据
  3. 通过数据库中的枚举,实现显示主页的标签
  4. BootStrap中 class 默认navbar是圆角的 如果不想要 则需自己定制 类 no-radius
  5. container-fluid 表示100%平铺 如果改成container 就可以设置宽度 并且container中包括响应式
  6. 前端可直接调用request
  7. 前端中文字与图片的排版
  8. BootStrap中 class = ‘clearfix’ 相当于在类所在标签的最后增加一个空标签 clear:both 用于清除浮动

3.2 示例代码

  1. Views.py
  1. # filename: views.py 
  2. def index(request, *args, **kwargs): 
  3. ''' 
  4. 主页 
  5. :param request: 
  6. :param args: 
  7. :param kwargs: 
  8. :return: 
  9. ''' 
  10. result = request.session.get('username'
  11. if result: 
  12.  
  13. # 分页 
  14. # 获取当前URL request.path_info 
  15. current_page = request.GET.get('page'
  16. base_url = request.path_info 
  17.  
  18. # 标签分类 
  19. # 基本方式一 
  20. # type_id = int(kwargs.get('type_id')) if kwargs.get('type_id') else None 
  21. # if type_id: 
  22. # article_list = models.Article.objects.filter(article_type_id=type_id) 
  23. # else: 
  24. # article_list = models.Article.objects.all() 
  25.  
  26. # 方式二 
  27. content = {} 
  28. type_id = int(kwargs.get('type_id')) if kwargs.get('type_id') else None 
  29. if type_id: 
  30. content['article_type_id'] = type_id 
  31. # 注意此处 filter条件为空字典的时候获取全部数据 
  32. # ******分页 
  33. all_count = models.Article.objects.filter(**content).count() 
  34. page_info = PageInfo(current_page, all_count, 10, base_url, 11
  35. # ******分页 
  36. article_list = models.Article.objects.filter(**content)[page_info.start():page_info.end()] 
  37.  
  38. type_choice = models.Article.type_choice 
  39. login_flag = True 
  40. return render(request, 'index.html', { 
  41. 'type_choice': type_choice, 
  42. 'article_list': article_list, 
  43. 'type_id': type_id, 
  44. 'page_info': page_info, 
  45. 'login_flag': login_flag 
  46. }) 
  47. else
  48. return redirect('/login/'
  1. index.html
  1. <!--filename:index.html --> 
  2. <!DOCTYPE html> 
  3. <html lang="en"> 
  4. <head> 
  5. <meta charset="UTF-8"> 
  6. <meta http-equiv="x-ua-compatible" content="IE=edge"> 
  7. <meta name="viewport" content="width=device-width, initial-scale=1"> 
  8. <title>Title</title> 
  9. <link rel="stylesheet" href="/static/plugins/bootstrap-3.3.7-dist/css/bootstrap.css"> 
  10. <link rel="stylesheet" href="/static/css/commons.css"> 
  11. <link rel="stylesheet" href="/static/plugins/fontawesome-free-5.1.0-web/css/fontawesome.css"> 
  12.  
  13. </head> 
  14.  
  15. <body> 
  16. <!-- 默认navbar是圆角的 如果不想要 则需自己定制 类 no-radius --> 
  17. <nav class="navbar navbar-default no-radius"> 
  18. <!-- ******** --> 
  19. <!-- container-fluid 表示100%平铺 如果改成container 就可以设置宽度 --> 
  20. <!-- 并且container中包括响应式 --> 
  21. <div class="container"> 
  22. <!-- Brand and toggle get grouped for better mobile display --> 
  23. <div class="navbar-header"> 
  24. <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" 
  25. data-target="#bs-example-navbar-collapse-1" aria-expanded="false"> 
  26. <span class="sr-only">Toggle navigation</span> 
  27. <span class="icon-bar"></span> 
  28. <span class="icon-bar"></span> 
  29. <span class="icon-bar"></span> 
  30. </button> 
  31. <a class="navbar-brand" href="/">老子的技术论坛</a> 
  32. </div> 
  33.  
  34. <!-- Collect the nav links, forms, and other content for toggling --> 
  35. <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1"> 
  36. <ul class="nav navbar-nav"> 
  37. {% if type_id %} 
  38. <li><a href="/">全部</a></li> 
  39. {% else %} 
  40. <li class="active"><a href="/">全部</a></li> 
  41. {% endif %} 
  42. {% for item in type_choice %} 
  43. {% if type_id == item.0 %} 
  44. <li class="active"><a href="/all/{{ item.0 }}/">{{ item.1 }}</a></li> 
  45. {% else %} 
  46. <li><a href="/all/{{ item.0 }}/">{{ item.1 }}</a></li> 
  47. {% endif %} 
  48. {% endfor %} 
  49. </ul> 
  50. <ul class="nav navbar-nav navbar-right"> 
  51. {% if login_flag %} 
  52. <!-- 注意此处--> 
  53. <li><a href="#">{{ request.session.username }}</a></li> 
  54. <li><a href="#">我的博客</a></li> 
  55. <li><a href="#">管理</a></li> 
  56. <li><a href="#">退出</a></li> 
  57.  
  58. {% else %} 
  59. <li><a href="/login/">登陆</a></li> 
  60. <li><a href="#">注册</a></li> 
  61. {% endif %} 
  62. </ul> 
  63. </div><!-- /.navbar-collapse --> 
  64. </div><!-- /.container-fluid --> 
  65. </nav> 
  66.  
  67. <div class="container"> 
  68. <div class="col-md-8"> 
  69. <div class="article-list"> 
  70. {% for article in article_list %} 
  71. <div class="article-item"> 
  72. <h4 class="article-head"><a>{{ article.title }}</a></h4> 
  73. <div class="article-body clearfix"> 
  74. <a class="left"><img src="{{ article.blog.user.avatar }}"></a> 
  75. {{ article.summary }} 
  76. <!-- clearfix相当于在此处增加一个标签 clear:both --> 
  77. </div> 
  78. <div class="article-foot"> 
  79. <a> 
  80. <span class="glyphicon glyphicon-user"></span> 
  81. {{ article.blog.user.username }} 
  82. </a> 
  83. <span> 
  84. 发布于 {{ article.create_time|date:"Y-m-d H:i:s" }} 
  85. </span> 
  86. <a href="#"> 
  87. <span class="glyphicon glyphicon-pencil"></span> 
  88. {{ article.comment_count }} 
  89. </a> 
  90. <a href="#"> 
  91. <span class="glyphicon glyphicon-thumbs-up"></span> 
  92. {{ article.up_count }} 
  93. </a> 
  94. </div> 
  95.  
  96. </div> 
  97. {% endfor %} 
  98. </div> 
  99. <div> 
  100. <nav aria-label="Page navigation"> 
  101. <ul class="pagination"> 
  102. {{ page_info.page|safe}} 
  103. </ul> 
  104. </nav> 
  105. </div> 
  106. </div> 
  107. <div class="col-md-4"> 
  108. <div class="panel panel-default"> 
  109. <div class="panel-heading">Panel heading without title</div> 
  110. <div class="panel-body"> 
  111. <p>123</p> 
  112. <p>123</p> 
  113. <p>123</p> 
  114. <p>123</p> 
  115. <p>123</p> 
  116. </div> 
  117. </div> 
  118.  
  119. <div class="panel panel-default"> 
  120. <div class="panel-heading">Panel heading without title</div> 
  121. <div class="panel-body"> 
  122. Panel content 
  123. </div> 
  124. </div> 
  125. </div> 
  126. </div> 
  127.  
  128. </body> 
  129. </html> 

4. 注册

4.1 知识点

4.2 示例代码

  1. forms.py
  2. register.html
  3. Views.py

5. 登陆

5.1 知识点

5.2 示例代码

  1. login.html
  1. <!DOCTYPE html> 
  2. <html lang="en"> 
  3. <head> 
  4. <meta charset="UTF-8"> 
  5. <meta http-equiv="x-ua-compatible" content="IE=edge"> 
  6. <meta name="viewport" content="width=device-width, initial-scale=1"> 
  7. <title>Title</title> 
  8. <link rel="stylesheet" href="/static/plugins/bootstrap-3.3.7-dist/css/bootstrap.css"> 
  9.  
  10. <style> 
  11. .login { 
  12. margin: 0 auto; 
  13. width: 600px; 
  14. padding: 20px; 
  15. margin-top: 80px; 
  16. } 
  17.  
  18. .head { 
  19. text-align: center; 
  20. padding: 10px; 
  21. margin-bottom: 20px; 
  22. margin-left: 90px; 
  23. margin-top: -60px; 
  24. } 
  25.  
  26. .logined, .register { 
  27. width: 460px; 
  28. } 
  29. </style> 
  30. </head> 
  31.  
  32. <body> 
  33. <div class="login"> 
  34. <div class="head"> 
  35. <h2><a href="/login/">用户登陆</a></h2> 
  36. </div> 
  37.  
  38. <div> 
  39. <form class="form-horizontal" novalidate method="post" action="/login/"> 
  40. {% csrf_token %} 
  41. {% for row in range %} 
  42. <div class="form-group"> 
  43. <label class="col-sm-2 control-label">用户名</label> 
  44. <div class="col-sm-10"> 
  45. <!-- <input type="email" class="form-control" placeholder="用户名">--> 
  46. {{ my_login_form.username }}{{ my_login_form.errors.username.0 }}{{ user_error }} 
  47. </div> 
  48. </div> 
  49. <div class="form-group"> 
  50. <label class="col-sm-2 control-label">密码</label> 
  51. <div class="col-sm-10"> 
  52. <!-- <input type="password" class="form-control" placeholder="密码">--> 
  53. {{ my_login_form.password }}{{ my_login_form.errors.password.0 }} 
  54. </div> 
  55. </div> 
  56. <div class="form-group"> 
  57. <label class="col-sm-2 control-label">验证码</label> 
  58. <div class="col-sm-3"> 
  59. <!-- <input type="text" class="form-control" placeholder="验证码">--> 
  60. {{ my_login_form.code }}{{ my_login_form.errors.code.0 }}{{ code_error }} 
  61. </div> 
  62. <div class="col-sm-5"> 
  63. <!--验证码刷新原理--> 
  64. <!--get方式请求 url后面加东西 不影响访问 但会刷新--> 
  65. <!--/check_code/?--> 
  66. <img id="check_code" style=" 120px;height: 30px" src="/check_code/"> 
  67.  
  68. </div> 
  69. </div> 
  70. <div class="form-group"> 
  71. <div class="col-sm-offset-2 col-sm-10"> 
  72. <button type="submit" class="btn btn-default logined">登陆</button> 
  73. </div> 
  74. </div> 
  75. <div class="form-group"> 
  76. <div class="col-sm-offset-2 col-sm-10"> 
  77. <a href="/register/"> 
  78. <button type="button" class="btn btn-default register">注册</button> 
  79. </a>
  80. </div> 
  81. </div> 
  82. </form> 
  83. </div> 
  84. </div> 
  85. <script src="/static/jquery-3.3.1.js"></script> 
  86. <script> 
  87. // 验证码图片刷新 
  88. $('#check_code').click(function () { 
  89. $('#check_code')[0].src = $('#check_code')[0].src + '?' 
  90. }) 
  91.  
  92. </script> 
  93.  
  94. </body> 
  95. </html> 
  1. form.py
  1. # filename: form.py 
  2. class MyLoginForm(Form): 
  3. ''' 
  4. 用户登陆Form 
  5. ''' 
  6. username = fields.CharField(max_length=32
  7. error_messages={ 
  8. 'required': '用户名不能为空'
  9. 'max_length': '用户名最多为32个字符'
  10. }, 
  11. widget=widgets.TextInput( 
  12. attrs={ 
  13. 'class': "form-control"
  14. 'placeholder': "用户名"
  15. )) 
  16. password = fields.CharField( 
  17. max_length=32
  18. min_length=6
  19. error_messages={ 
  20. 'required': '密码不能为空'
  21. 'max_length': '密码最多为32个字符'
  22. 'min_length': '密码最多为6个字符'
  23. }, 
  24. widget=widgets.PasswordInput( 
  25. attrs={ 
  26. 'name': 'password'
  27. 'class': "form-control"
  28. 'placeholder': "密码"
  29. })) 
  30. code = fields.CharField(max_length=5, min_length=5
  31. error_messages={ 
  32. 'required': '验证码不能为空'
  33. 'max_length': '验证码只能为5个字符'
  34. 'min_length': '验证码只能为5个字符'
  35. }, 
  36. widget=widgets.TextInput( 
  37. attrs={ 
  38.  
  39. 'class': "form-control"
  40. 'placeholder': "验证码"
  41. )) 
  1. Views.py
  1.  
原文地址:https://www.cnblogs.com/sama/p/9285247.html