• 报账系统总结(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.  
  • 相关阅读:
    Prime Land(poj 1365)
    备用交换机(cogs 8)
    救命(洛谷 U4525)
    消息传递(cogs 1001)
    SQLite 使用主键,ROWID 及自增列
    SqlHelper 类
    一个继承的 DataGridView
    给JAVA的eclipse IDE 在线安装 SVN插件 / 给 eclipse 添加打开所在的文件夹功能
    实时更新DataGridView 合计值
    导出为文本格式
  • 原文地址:https://www.cnblogs.com/sama/p/9285247.html
Copyright © 2020-2023  润新知