当前位置:   article > 正文

Django学习第四天

Django学习第四天

启动项目命令

python manage.py runserver

分页功能封装到类中去

封装的类的代码

  1. """
  2. 自定义的分页组件,以后如果想要使用这个分页组件,你需要做:
  3. def pretty_list(request):
  4. # 靓号列表
  5. data_dict = {}
  6. search_data = request.GET.get('q', "")
  7. if search_data:
  8. data_dict["mobile__contains"] = search_data
  9. from app01.utils.pagination import Pagination
  10. # 根据自己的情况去筛选自己的数据
  11. queryset = models.PrettyNum.objects.filter(**data_dict).order_by("-level")
  12. # 实例化分页对象1
  13. page_object = Pagination(request, queryset)
  14. context = {
  15. "queryset": page_object.page_queryset,
  16. "search_data": search_data, # 分完页的数据
  17. "page_string": page_object.html() # 页码
  18. }
  19. return render(request, 'pretty_list.html', context)
  20. 在html页面中
  21. {% for obj in queryset %}
  22. {{ obj.xx }}
  23. {% endfor %}
  24. <ul class="pagination">
  25. {{ page_string }}
  26. </ul>
  27. """
  28. from django.utils.safestring import mark_safe
  29. class Pagination(object):
  30. def __init__(self, request, queryset, page_size=10, page_param="page", plus=5):
  31. from django.http.request import QueryDict
  32. import copy
  33. query_dict = copy.deepcopy(request.GET)
  34. query_dict._mutable = True
  35. self.query_dict = query_dict
  36. self.page_param = page_param
  37. page = request.GET.get(page_param, "1")
  38. if page.isdecimal():
  39. page = int(page)
  40. else:
  41. page = 1
  42. self.page = page
  43. self.page_size = page_size
  44. self.start = (page - 1) * page_size
  45. self.end = page * page_size
  46. self.page_queryset = queryset[self.start:self.end]
  47. total_count = queryset.count()
  48. # 总页码
  49. total_page_count, div = divmod(total_count, page_size)
  50. if div:
  51. total_page_count += 1
  52. self.total_page_count = total_page_count
  53. self.plus = plus
  54. def html(self):
  55. if self.total_page_count <= 2 * self.plus + 1:
  56. # 数据库中的数据比较少,都没有达到11页
  57. start_page = 1
  58. end_page = self.total_page_count + 1
  59. else:
  60. # 当前页<5时
  61. if self.page <= self.plus:
  62. start_page = 1
  63. end_page = 2 * self.plus + 1
  64. else:
  65. if (self.page + self.plus) > self.total_page_count:
  66. start_page = self.total_page_count - 2 * self.plus
  67. end_page = self.total_page_count
  68. else:
  69. # 数据库中的数据比较多>11页
  70. start_page = self.page - self.plus
  71. end_page = self.page + self.plus
  72. # 页码
  73. page_str_list = []
  74. self.query_dict.setlist(self.page_param, [1])
  75. print(self.query_dict.urlencode())
  76. # 上一页
  77. if self.page > 1:
  78. self.query_dict.setlist(self.page_param, [self.page - 1])
  79. prev = '<li><a href="?{}">上一页</a></li>'.format(self.query_dict.urlencode())
  80. else:
  81. self.query_dict.setlist(self.page_param, [1])
  82. prev = '<li><a href="?{}">上一页</a></li>'.format(self.query_dict.urlencode())
  83. page_str_list.append(prev)
  84. for i in range(start_page, end_page):
  85. self.query_dict.setlist(self.page_param, [i])
  86. if i == self.page:
  87. ele = '<li class="active"><a href="?{}">{}</a></li>'.format(self.query_dict.urlencode(), i)
  88. else:
  89. ele = '<li><a href="?{}">{}</a></li>'.format(self.query_dict.urlencode(), i)
  90. page_str_list.append(ele)
  91. page_str_list.append('<li><a href="?{}">首页</a></li>'.format(self.query_dict.urlencode()))
  92. # 下一页
  93. if self.page < self.total_page_count:
  94. self.query_dict.setlist(self.page_param, [self.page + 1])
  95. prev = '<li><a href="?{}">下一页</a></li>'.format(self.query_dict.urlencode())
  96. else:
  97. self.query_dict.setlist(self.page_param, [self.total_page_count])
  98. prev = '<li><a href="?{}">下一页</a></li>'.format(self.query_dict.urlencode())
  99. page_str_list.append(prev)
  100. self.query_dict.setlist(self.page_param, [self.total_page_count])
  101. page_str_list.append('<li><a href="?{}">尾页</a></li>'.format(self.query_dict.urlencode()))
  102. search_string = """
  103. <li>
  104. <form style="float: left;margin-left: -1px" method="get">
  105. <input type="text" name="page"
  106. style="position: relative;float: left;display: inline-block;width: 80px;border-radius: 0;"
  107. class="form-control" placeholder="页码">
  108. <button style="border-radius: 0" class="btn btn-default" type="submit">跳转</button>
  109. </form>
  110. </li>
  111. """
  112. page_str_list.append(search_string)
  113. page_string = mark_safe("".join(page_str_list))
  114. return page_string

小bug,搜索+分页情况下

分页时候保留原来的搜索条件

http://127.0.0.1:8000/pretty/list/?q=888&page=1

在用户列表页面使用分页功能

ModelForm引入时间样式(自动生成了id为id_create_time)

  1. {% extends 'layout.html' %}
  2. {% block css %}
  3. <link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/bootstrap-datepicker/1.9.0/css/bootstrap-datepicker.min.css">
  4. {% endblock %}
  5. {% block content %}
  6. <div class="container">
  7. <div class="panel panel-default">
  8. <div class="panel-heading">
  9. <h3 class="panel-title">新建用户</h3>
  10. </div>
  11. <div class="panel-body">
  12. <form method="post" novalidate>
  13. {% csrf_token %}
  14. {% for field in form %}
  15. <div class="form-group">
  16. <label>{{ field.label }}</label>
  17. {{ field }}
  18. <span style="color: red;">{{ field.errors.0 }}</span>
  19. </div>
  20. {% endfor %}
  21. <button type="submit" class="btn btn-primary">提 交</button>
  22. </form>
  23. </div>
  24. </div>
  25. </div>
  26. {% endblock %}
  27. {% block js %}
  28. <script src="https://cdn.bootcdn.net/ajax/libs/bootstrap-datepicker/1.9.0/js/bootstrap-datepicker.js"></script>
  29. <script src="https://cdn.bootcdn.net/ajax/libs/bootstrap-datepicker/1.9.0/locales/bootstrap-datepicker.zh-CN.min.js"></script>
  30. <script>
  31. $(function(){
  32. $('#id_create_time').datepicker({
  33. format: 'yyyy-mm-dd',
  34. startDate: '0',
  35. language: "zh-CN",
  36. autoclose: true
  37. });
  38. })
  39. </script>
  40. {% endblock %}

引入时间样式(自定义组件id为dt)

  1. {% extends 'layout.html' %}
  2. {% load static %}
  3. {% block css %}
  4. <link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/bootstrap-datepicker/1.9.0/css/bootstrap-datepicker.min.css">
  5. {% endblock %}
  6. {% block content %}
  7. <div class="container">
  8. <div class="panel panel-default">
  9. <div class="panel-heading">
  10. <h3 class="panel-title">新建用户</h3>
  11. </div>
  12. <div class="panel-body">
  13. <form method="post">
  14. {% csrf_token %}
  15. <div class="form-group">
  16. <label>姓名</label>
  17. <input type="text" class="form-control" placeholder="姓名" name="user">
  18. </div>
  19. <div class="form-group">
  20. <label>密码</label>
  21. <input type="text" class="form-control" placeholder="密码" name="pwd">
  22. </div>
  23. <div class="form-group">
  24. <label>年龄</label>
  25. <input type="text" class="form-control" placeholder="年龄" name="age">
  26. </div>
  27. <div class="form-group">
  28. <label>余额</label>
  29. <input type="text" class="form-control" placeholder="余额" name="ac">
  30. </div>
  31. <div class="form-group">
  32. <label>入职时间</label>
  33. <input id="dt" type="text" class="form-control" placeholder="入职时间" name="ctime">
  34. </div>
  35. <div class="form-group">
  36. <label>性别</label>
  37. <select class="form-control" name="gd">
  38. {% for item in gender_choices %}
  39. <option value="{{ item.0 }}">{{ item.1 }}</option>
  40. {% endfor %}
  41. </select>
  42. </div>
  43. <div class="form-group">
  44. <label>部门</label>
  45. <select class="form-control" name="dp">
  46. {% for item in depart_list %}
  47. <option value="{{ item.id }}">{{ item.title }}</option>
  48. {% endfor %}
  49. </select>
  50. </div>
  51. <button type="submit" class="btn btn-primary">提 交</button>
  52. </form>
  53. </div>
  54. </div>
  55. </div>
  56. {% endblock %}
  57. {% block js %}
  58. <script src="https://cdn.bootcdn.net/ajax/libs/bootstrap-datepicker/1.9.0/js/bootstrap-datepicker.js"></script>
  59. <script src="https://cdn.bootcdn.net/ajax/libs/bootstrap-datepicker/1.9.0/locales/bootstrap-datepicker.zh-CN.min.js"></script>
  60. <script>
  61. $(function(){
  62. $('#dt').datepicker({
  63. format: 'yyyy-mm-dd',
  64. startDate: '0',
  65. language: "zh-CN",
  66. autoclose: true
  67. });
  68. })
  69. </script>
  70. {% endblock %}

在html中增加属性的方法1

在html中增加属性的方法2

在html中增加属性的方法3

UserEditModelForm类继承了BootStrapModelForm类的方法,BootStrapModelForm继承了forms.ModelForm的方法所以使用继承能够更好封装代码功能

 封装每部分的功能,拆分到每个模块中去

运行创建数据库代码的命令语句

 python manage.py makemigrations
 python manage.py migrate 

两种方式实现密码输入框

实现密码不一致不会被清空

密码加密

实现重置密码功能

管理员添加,编辑,删除和重置密码功能实现

admin.py代码

  1. from django.core.exceptions import ValidationError
  2. from django.shortcuts import render, redirect
  3. from app01 import models
  4. from app01.utils.pagination import Pagination
  5. def admin_list(request):
  6. """ 管理员列表 """
  7. data_dict = {}
  8. search_data = request.GET.get('q', "")
  9. if search_data:
  10. data_dict["username__contains"] = search_data
  11. queryset = models.Admin.objects.filter(**data_dict)
  12. page_object = Pagination(request, queryset)
  13. context = {
  14. "queryset": page_object.page_queryset,
  15. "page_string": page_object.html(),
  16. "search_data": search_data
  17. }
  18. return render(request, 'admin_list.html', context)
  19. from django import forms
  20. from app01.utils.bootstrap import BootStrapModelForm
  21. from app01.utils.encrypt import md5
  22. class AdminModelForm(BootStrapModelForm):
  23. confirm_password = forms.CharField(
  24. label="确认密码",
  25. widget=forms.PasswordInput(render_value=True)
  26. )
  27. class Meta:
  28. model = models.Admin
  29. fields = ["username", "password", "confirm_password"]
  30. widgets = {
  31. "password": forms.PasswordInput(render_value=True)
  32. }
  33. def clean_password(self):
  34. pwd = self.cleaned_data.get("password")
  35. return md5(pwd)
  36. def clean_confirm_password(self):
  37. pwd = self.cleaned_data.get("password")
  38. confirm = md5(self.cleaned_data.get("confirm_password"))
  39. if confirm != pwd:
  40. raise ValidationError("密码不一致")
  41. return confirm
  42. class AdminEditModelForm(BootStrapModelForm):
  43. class Meta:
  44. model = models.Admin
  45. fields = ['username']
  46. class AdminResetModelForm(BootStrapModelForm):
  47. confirm_password = forms.CharField(
  48. label="确认密码",
  49. widget=forms.PasswordInput(render_value=True)
  50. )
  51. class Meta:
  52. model = models.Admin
  53. fields = ['password', 'confirm_password']
  54. widgets = {
  55. "password": forms.PasswordInput(render_value=True)
  56. }
  57. def clean_password(self):
  58. pwd = self.cleaned_data.get("password")
  59. md5_pwd = md5(pwd)
  60. exists = models.Admin.objects.filter(id=self.instance.pk, password=md5_pwd).exists()
  61. if exists:
  62. raise ValidationError("密码不能与之前的密码相同")
  63. return md5_pwd
  64. def clean_confirm_password(self):
  65. pwd = self.cleaned_data.get("password")
  66. confirm = md5(self.cleaned_data.get("confirm_password"))
  67. if confirm != pwd:
  68. raise ValidationError("密码不一致")
  69. return confirm
  70. def admin_add(request):
  71. """ 添加管理员 """
  72. title = "新建管理员"
  73. if request.method == "GET":
  74. form = AdminModelForm()
  75. return render(request, 'change.html', {"form": form, "title": title})
  76. form = AdminModelForm(data=request.POST)
  77. if form.is_valid():
  78. form.save()
  79. return redirect('/admin/list/')
  80. return render(request, 'change.html', {'form': form, "title": title})
  81. def admin_edit(request, nid):
  82. """ 编辑管理员 """
  83. row_object = models.Admin.objects.filter(id=nid).first()
  84. if not row_object:
  85. # return render(request, 'error.html', {"msg": "数据不存在"})
  86. return redirect('/admin/list/')
  87. title = "编辑管理员"
  88. if request.method == "GET":
  89. form = AdminEditModelForm(instance=row_object)
  90. return render(request, 'change.html', {"form": form, "title": title})
  91. form = AdminEditModelForm(data=request.POST, instance=row_object)
  92. if form.is_valid():
  93. form.save()
  94. return redirect('/admin/list/')
  95. return render(request, 'change.html', {"form": form, "title": title})
  96. def admin_delete(request, nid):
  97. """ 删除管理员 """
  98. models.Admin.objects.filter(id=nid).delete()
  99. return redirect('/admin/list/')
  100. def admin_reset(request, nid):
  101. """ 重置密码 """
  102. row_object = models.Admin.objects.filter(id=nid).first()
  103. if not row_object:
  104. return redirect('/admin/list/')
  105. title = "重置密码 - {}".format(row_object.username)
  106. if request.method == "GET":
  107. form = AdminResetModelForm()
  108. return render(request, 'change.html', {"form": form, "title": title})
  109. form = AdminResetModelForm(data=request.POST, instance=row_object)
  110. if form.is_valid():
  111. form.save()
  112. return redirect('/admin/list/')
  113. return render(request, 'change.html', {"form": form, "title": title})

admin_list.html代码

  1. {% extends 'layout.html' %}
  2. {% block content %}
  3. <div class="container">
  4. <div style="margin-bottom: 10px" class="clearfix">
  5. <a class="btn btn-success" href="/admin/add/" target="_blank">
  6. <span class="glyphicon glyphicon-plus-sign" aria-hidden="true"></span>
  7. 新建管理员
  8. </a>
  9. <div style="float: right;width: 300px;">
  10. <form method="get">
  11. <div class="input-group">
  12. <input type="text" name="q" class="form-control" placeholder="关键字"
  13. value="{{ search_data }}">
  14. <span class="input-group-btn">
  15. <button class="btn btn-default" type="submit">
  16. <span class="glyphicon glyphicon-search" aria-hidden="true"></span>
  17. </button>
  18. </span>
  19. </div>
  20. </form>
  21. </div>
  22. </div>
  23. <div class="panel panel-default">
  24. <!-- Default panel contents -->
  25. <div class="panel-heading">
  26. <span class="glyphicon glyphicon-th-list" aria-hidden="true"></span>
  27. 管理员列表
  28. </div>
  29. <!-- Table -->
  30. <table class="table table-bordered">
  31. <thead>
  32. <tr>
  33. <th>ID</th>
  34. <th>用户名</th>
  35. <th>密码</th>
  36. <th>重置密码</th>
  37. <th>操作</th>
  38. </tr>
  39. </thead>
  40. <tbody>
  41. {% for obj in queryset %}
  42. <tr>
  43. <th>{{ obj.id }}</th>
  44. <td>{{ obj.username }}</td>
  45. <td>******</td>
  46. <td>
  47. <a href="/admin/{{ obj.id }}/reset/">重置密码</a>
  48. </td>
  49. <td>
  50. <a class="btn btn-primary btn-xs" href="/admin/{{ obj.id }}/edit/">编辑</a>
  51. <a class="btn btn-danger btn-xs" href="/admin/{{ obj.id }}/delete/">删除</a>
  52. </td>
  53. </tr>
  54. {% endfor %}
  55. </tbody>
  56. </table>
  57. </div>
  58. <div class="clearfix">
  59. <ul class="pagination" style="float:left;">
  60. {{ page_string }}
  61. </ul>
  62. </div>
  63. </div>
  64. {% endblock %}

change.html模板

  1. {% extends 'layout.html' %}
  2. {% block content %}
  3. <div class="container">
  4. <div class="panel panel-default">
  5. <div class="panel-heading">
  6. <h3 class="panel-title">{{ title }}</h3>
  7. </div>
  8. <div class="panel-body">
  9. <form method="post" novalidate>
  10. {% csrf_token %}
  11. {% for field in form %}
  12. <div class="form-group">
  13. <label>{{ field.label }}</label>
  14. {{ field }}
  15. <span style="color: red;">{{ field.errors.0 }}</span>
  16. </div>
  17. {% endfor %}
  18. <button type="submit" class="btn btn-primary">提 交</button>
  19. </form>
  20. </div>
  21. </div>
  22. </div>
  23. {% endblock %}

表示字段不能为空

提示用户名或密码输入错误

django自动帮我们把session功能定义好了,使用只需要这样一个语句

登录成功后:

cookie,随机字符串

session,用户信息

在其他需要登录才能访问的页面中,都需要加入:

  1. def index(request):
  2. info = request.session.get("info")
  3. if not info:
  4. return redirect('/login/')

目标:在18个视图函数中统一加上

  1. info = request.session.get("info")
  2. if not info:
  3. return redirect('/login/')

编写中间件

  1. from django.utils.deprecation import MiddlewareMixin
  2. from django.shortcuts import HttpResponse, redirect
  3. class AuthMiddleware(MiddlewareMixin):
  4. def process_request(self, request):
  5. # 0.排除那些不需要登录就能访问的页面
  6. # request.path_info == "/login/"
  7. if request.path_info == "/login/":
  8. return
  9. # 1.读取当前访问的用户的session信息,如果能读到,说明已登录过,就可以继续向后走
  10. info_dict = request.session.get("info")
  11. if info_dict:
  12. return
  13. # 2.没有登录过,重新回到登录页面
  14. return redirect('/login/')

应用中间件

  1. MIDDLEWARE = [
  2. 'django.middleware.security.SecurityMiddleware',
  3. 'django.contrib.sessions.middleware.SessionMiddleware',
  4. 'django.middleware.common.CommonMiddleware',
  5. 'django.middleware.csrf.CsrfViewMiddleware',
  6. 'django.contrib.auth.middleware.AuthenticationMiddleware',
  7. 'django.contrib.messages.middleware.MessageMiddleware',
  8. 'django.middleware.clickjacking.XFrameOptionsMiddleware',
  9. 'app01.middleware.auth.AuthMiddleware',
  10. ]

从session中取到用户名

{{ request.session.info.name }}

设置图像验证码

  1. import random
  2. from PIL import Image, ImageDraw, ImageFont, ImageFilter
  3. def check_code(width=120, height=40, char_length=5, font_file='ZixunHappyBold.ttf', font_size=28):
  4. code = []
  5. img = Image.new(mode='RGB', size=(width, height), color=(255, 255, 255))
  6. draw = ImageDraw.Draw(img, mode='RGB')
  7. def rndChar():
  8. """
  9. 生成随机字母
  10. :return:
  11. """
  12. return chr(random.randint(65, 90))
  13. def rndColor():
  14. """
  15. 生成随机颜色
  16. :return:
  17. """
  18. return (random.randint(0, 255), random.randint(10, 255), random.randint(64, 255))
  19. # 写文字
  20. font = ImageFont.truetype(font_file, font_size)
  21. for i in range(char_length):
  22. char = rndChar()
  23. code.append(char)
  24. h = random.randint(0, 4)
  25. draw.text([i * width / char_length, h], char, font=font, fill=rndColor())
  26. # 写干扰点
  27. for i in range(40):
  28. draw.point([random.randint(0, width), random.randint(0, height)], fill=rndColor())
  29. # 写干扰圆圈
  30. for i in range(40):
  31. draw.point([random.randint(0, width), random.randint(0, height)], fill=rndColor())
  32. x = random.randint(0, width)
  33. y = random.randint(0, height)
  34. draw.arc((x, y, x + 4, y + 4), 0, 90, fill=rndColor())
  35. # 画干扰线
  36. for i in range(5):
  37. x1 = random.randint(0, width)
  38. y1 = random.randint(0, height)
  39. x2 = random.randint(0, width)
  40. y2 = random.randint(0, height)
  41. draw.line((x1, y1, x2, y2), fill=rndColor())
  42. img = img.filter(ImageFilter.EDGE_ENHANCE_MORE)
  43. return img, ''.join(code)
  44. if __name__ == '__main__':
  45. # 1. 直接打开
  46. # img,code = check_code()
  47. # img.show()
  48. # 2. 写入文件
  49. # img,code = check_code()
  50. # with open('code.png','wb') as f:
  51. # img.save(f,format='png')
  52. # 3. 写入内存(Python3)
  53. # from io import BytesIO
  54. # stream = BytesIO()
  55. # img.save(stream, 'png')
  56. # stream.getvalue()
  57. # 4. 写入内存(Python2)
  58. # import StringIO
  59. # stream = StringIO.StringIO()
  60. # img.save(stream, 'png')
  61. # stream.getvalue()
  62. pass

设置七天免登录功能

图片验证码account.py

  1. from django import forms
  2. from django.shortcuts import render, redirect, HttpResponse
  3. from app01 import models
  4. from app01.utils.bootstrap import BootStrapForm
  5. from app01.utils.encrypt import md5
  6. from app01.utils.code import check_code
  7. class LoginForm(BootStrapForm):
  8. username = forms.CharField(
  9. label="用户名",
  10. widget=forms.TextInput,
  11. required=True
  12. )
  13. password = forms.CharField(
  14. label="密码",
  15. widget=forms.PasswordInput(render_value=True),
  16. required=True
  17. )
  18. code = forms.CharField(
  19. label="验证码",
  20. widget=forms.TextInput,
  21. required=True
  22. )
  23. def clean_password(self):
  24. pwd = self.cleaned_data.get("password")
  25. return md5(pwd)
  26. def login(request):
  27. """ 登录 """
  28. if request.method == "GET":
  29. form = LoginForm()
  30. return render(request, 'login.html', {'form': form})
  31. form = LoginForm(data=request.POST)
  32. if form.is_valid():
  33. # 验证码的校验
  34. user_input_code = form.cleaned_data.pop('code')
  35. code = request.session.get('image_code', "")
  36. if code.upper() != user_input_code.upper():
  37. form.add_error("code", "验证码错误")
  38. return render(request, 'login.html', {'form': form})
  39. # 验证成功,获取到的用户名和密码1
  40. # 去数据库校验用户名和密码是否正确,获取用户对象
  41. admin_object = models.Admin.objects.filter(**form.cleaned_data).first()
  42. if not admin_object:
  43. form.add_error("password", "用户名或密码错误!")
  44. return render(request, 'login.html', {'form': form})
  45. # 用户名和密码正确
  46. # 网站生成随机字符串;写到用户浏览器的cookie中,在写入到session中;
  47. request.session["info"] = {'id': admin_object.id, 'name': admin_object.username}
  48. request.session.set_expiry(60 * 60 * 24 * 7)
  49. return redirect("/admin/list/")
  50. return render(request, 'login.html', {'form': form})
  51. from io import BytesIO
  52. def image_code(request):
  53. """ 生成图片验证码 """
  54. # 调用pillow函数,生成图片
  55. img, code_string = check_code()
  56. # 写入到自己的session中(以便于后续获取验证码再进行校验)
  57. request.session['image_code'] = code_string
  58. # 给session设置60s超时
  59. request.session.set_expiry(60)
  60. stream = BytesIO()
  61. img.save(stream, 'png')
  62. return HttpResponse(stream.getvalue())
  63. def logout(request):
  64. """ 注销 """
  65. request.session.clear()
  66. return redirect('/login/')

login.html

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Title</title>
  6. <link rel="stylesheet" href="/static/plugins/bootstrap-3.3.5/css/bootstrap.css">
  7. <style>
  8. .account {
  9. width: 400px;
  10. border: 1px solid #dddddd;
  11. border-radius: 5px;
  12. box-shadow: 5px 5px 20px #aaa;
  13. margin-left: auto;
  14. margin-right: auto;
  15. margin-top: 100px;
  16. padding: 20px 40px;
  17. }
  18. .account h2 {
  19. margin-top: 10px;
  20. text-align: center;
  21. }
  22. </style>
  23. </head>
  24. <body>
  25. <div class="account">
  26. <h2>用户登录</h2>
  27. <form method="post" novalidate>
  28. {% csrf_token %}
  29. <div class="form-group">
  30. <label>用户名</label>
  31. {{ form.username }}
  32. <span style="color: red;">{{ form.username.errors.0 }}</span>
  33. </div>
  34. <div class="form-group">
  35. <label>密码</label>
  36. {{ form.password }}
  37. <span style="color: red;">{{ form.password.errors.0 }}</span>
  38. </div>
  39. <div class="form-group">
  40. <label for="id_code">图片验证码</label>
  41. <div class="row">
  42. <div class="col-xs-7">
  43. {{ form.code }}
  44. <span style="color: red;">{{ form.code.errors.0 }}</span>
  45. </div>
  46. <div class="col-xs-5">
  47. <img id="image_code" src="/image/code/" style="width: 125px;">
  48. </div>
  49. </div>
  50. </div>
  51. <input type="submit" value="登 录" class="btn btn-primary">
  52. </form>
  53. </div>
  54. </body>
  55. </html>

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop】
推荐阅读
相关标签
  

闽ICP备14008679号