1、随机验证码

  1. url(r'^get_code/', views.get_code, name='get_code'),
  2. # 获取随机3个0-255数
  3. def get_random():
  4. """
  5. :return: 返回0-255三个随机数,元组
  6. """
  7. return random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)
  8. # 获取验证码
  9. def get_code(request):
  10. # 1.产生一张随机颜色的图片
  11. img_obj = Image.new('RGB', (350, 35), get_random())
  12. # 2.产生一只在图片上的画笔
  13. img_draw = ImageDraw.Draw(img_obj)
  14. # 3.产生字体样式
  15. img_font = ImageFont.truetype(r'static\font\font.ttf', 35)
  16. io_obj = BytesIO()
  17. # 产生5个随机验证码
  18. code = ''
  19. for i in range(5):
  20. upper_str = chr(random.randint(65, 90)) # 大写字母
  21. lower_str = chr(random.randint(97, 122)) # 小写字母
  22. random_int = str(random.randint(0, 9)) # 数字
  23. # 随机取一个
  24. temp_str = random.choice([upper_str, lower_str, random_int])
  25. # 写在图片上,位置,内容,颜色,字体
  26. img_draw.text((45 + i * 60, -2), temp_str, get_random(), font=img_font)
  27. # 储存
  28. code += temp_str
  29. print(code)
  30. img_obj.save(io_obj, 'png')
  31. request.session['code'] = code
  32. return HttpResponse(io_obj.getvalue())

前端代码:

  1. <img src="/get_code/" alt="图片验证码" id="id_img">

js代码:

原理:src改变,立马刷新。点击一次图片,给url添加一个?号

  1. $('#id_img').click(function () {
  2. var oldSrc = $(this).attr('src');
  3. $(this).attr('src', oldSrc += '?')
  4. });

2、注册功能

前端代码:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>注册</title>
  6. <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
  7. <link rel="stylesheet" href="https://cdn.bootcss.com/font-awesome/4.7.0/css/font-awesome.min.css">
  8. <script src="https://cdn.bootcss.com/sweetalert/2.0.0/sweetalert.min.js"></script>
  9. <link rel="https://cdn.bootcss.com/sweetalert/1.1.3/sweetalert.min.css">
  10. {% load static %}
  11. <link rel="stylesheet" href="{% static '/bootstrap-3.3.7-dist/css/bootstrap.min.css'%}">
  12. <script src="{% static 'bootstrap-3.3.7-dist/js/bootstrap.min.js' %}"></script>
  13. </head>
  14. <body>
  15. <div class="container">
  16. <div class="row">
  17. <h2 class="text-center">注册页面</h2>
  18. <div class="col-md-8 col-md-offset-2">
  19. <form id="myform">
  20. {% csrf_token %}
  21. {% for form in form_obj %}
  22. <div class="form-group">
  23. <label for="{{ form.id_for_label }}">{{ form.label }}</label>
  24. {{ form }}
  25. <span style="color: red" class="pull-right"></span>
  26. </div>
  27. {% endfor %}
  28. <div class="form-group">
  29. <label for="id_avatar">头像
  30. <img src="/static/images/default.jpg" alt="" width="100" style="margin-left: 10px" id="id_img">
  31. </label>
  32. <input type="file" name="myfile" id="id_avatar">
  33. </div>
  34. <a href="/login/"><input type="button" value="登录" class="btn btn-success pull-left"></a>
  35. &nbsp;&nbsp;<input type="button" value="注册" class="btn btn-danger" id="id_submit">
  36. </form>
  37. </div>
  38. </div>
  39. </div>
  40. <script>
  41. $('#id_avatar').change(function () {
  42. // 1 先获取用户上传的头像文件
  43. var avatarFile = $(this)[0].files[0];
  44. // 2 利用文件阅读器对象
  45. var myFileReader = new FileReader();
  46. // 3 将文件交由阅读器对象读取
  47. myFileReader.readAsDataURL(avatarFile);
  48. // 4 修改img标签的src属性 等待文件阅读器对象读取文件之后再操作img标签
  49. myFileReader.onload = function(){
  50. $('#id_img').attr('src',myFileReader.result)
  51. }
  52. });
  53. // 点击按钮触发ajax提交动作
  54. $('#id_submit').on('click',function () {
  55. // 1 先生成一个内置对象 FormData
  56. var myFormData = new FormData();
  57. // 2 添加普通键值对
  58. {#console.log($('#myform').serializeArray())#}
  59. $.each($('#myform').serializeArray(),function (index,obj) {
  60. myFormData.append(obj.name,obj.value)
  61. });
  62. // 3 添加文件数据
  63. myFormData.append('avatar',$('#id_avatar')[0].files[0]);
  64. // 4 发送数据
  65. $.ajax({
  66. url:'',
  67. type:'post',
  68. data:myFormData,
  69. // 两个关键性参数
  70. contentType:false,
  71. processData:false,
  72. success:function (data) {
  73. if (data.code===1000){
  74. // 注册成功之后 应该跳转到后端返回过来的url
  75. location.href = data.url
  76. }else{
  77. $.each(data.msg,function(index,obj){
  78. // 1 先手动拼接字段名所对应的input框的id值
  79. var targetId = '#id_' + index; // #id_username
  80. // 2 利用id选择器查找标签 并且将div标签添加报错类
  81. $(targetId).next().text(obj[0]).parent().addClass('has-error')
  82. })
  83. }
  84. }
  85. })
  86. });
  87. $('input').focus(function () {
  88. // 移除span标签内部的文本 还需要移除div标签的class中has-error属性
  89. $(this).next().text('').parent().removeClass('has-error')
  90. })
  91. </script>
  92. </body>
  93. </html>

后端urls.py:

  1. # 注册
  2. url(r'^register/', views.register, name='register'),

views.py:

  1. # 注册
  2. def register(request):
  3. form_obj = MyRegForm()
  4. if request.method == 'POST':
  5. back_dic = {'code': 1000, 'msg': ""}
  6. # 校验用户名、密码
  7. form_obj = MyRegForm(request.POST)
  8. if form_obj.is_valid():
  9. # 用变量接收正确的结果 clean_data = {'username' 'password' 're_password' 'email'}
  10. clean_data = form_obj.cleaned_data
  11. # 将确认密码键值对删除,表中没有re_password
  12. clean_data.pop('re_password')
  13. # 把签名、用户CSS名字存进Blog表中
  14. sign = clean_data.get('sign')
  15. username = clean_data.get('username')
  16. site_theme = username + '.css'
  17. models.Blog.objects.create(site_name=username, site_title=sign, site_theme=site_theme)
  18. # 添加字段
  19. clean_data['blog'] = models.Blog.objects.filter(site_name=username).first()
  20. clean_data.pop('sign')
  21. # 额外做的事情:给每个新的注册用户添加3个默认的分类和3个默认的标签
  22. create_list = []
  23. blog = models.Blog.objects.filter(site_name=username).first()
  24. for i in ['一', '二', '三']:
  25. category_name = username+'的分类'+i
  26. create_list.append(models.Category(name=category_name, blog=blog))
  27. models.Category.objects.bulk_create(create_list)
  28. # 添加3个默认标签
  29. create_list = []
  30. for i in ['一', '二', '三']:
  31. tag_name = username + '的标签' + i
  32. create_list.append(models.Tag(name=tag_name, blog=blog))
  33. models.Tag.objects.bulk_create(create_list)
  34. # 获取用户头像文件
  35. avatar_obj = request.FILES.get('avatar')
  36. # 判断用户头像文件是否为空,用户没有上传
  37. if avatar_obj:
  38. # 用户上传了,添加到clean_data中
  39. clean_data['avatar'] = avatar_obj # clean_data = {'username' 'password' 'email' 'avatar'}
  40. models.UserInfo.objects.create_user(**clean_data) # 打散传入 ??=??的形式
  41. back_dic['msg'] = '注册成功'
  42. back_dic['url'] = '/login/'
  43. else:
  44. back_dic['code'] = 2000
  45. back_dic['msg'] = form_obj.errors
  46. return JsonResponse(back_dic)
  47. return render(request, 'register.html', locals())

myforms.py:

  1. from django import forms
  2. from app01 import models
  3. class MyRegForm(forms.Form):
  4. username = forms.CharField(min_length=3,max_length=8,label='用户名',
  5. error_messages={
  6. "min_length":'用户名最短3位',
  7. "max_length":'用户名最长8位',
  8. "required":'用户名不能为空',
  9. },widget=forms.widgets.TextInput(attrs={'class':'form-control'})
  10. )
  11. password = forms.CharField(min_length=3, max_length=8, label='密码',
  12. error_messages={
  13. "min_length": '密码最短3位',
  14. "max_length": '密码最长8位',
  15. "required": '密码不能为空',
  16. }, widget=forms.widgets.PasswordInput(attrs={'class': 'form-control'})
  17. )
  18. re_password = forms.CharField(min_length=3, max_length=8, label='确认密码',
  19. error_messages={
  20. "min_length": '确认密码最短3位',
  21. "max_length": '确认密码最长8位',
  22. "required": '确认密码不能为空',
  23. }, widget=forms.widgets.PasswordInput(attrs={'class': 'form-control'})
  24. )
  25. email = forms.EmailField(label='邮箱',
  26. error_messages={
  27. "required": '邮箱不能为空',
  28. "invalid":"邮箱格式不正确"
  29. },
  30. widget=forms.widgets.EmailInput(attrs={'class': 'form-control'})
  31. )
  32. sign = forms.CharField(min_length=5, max_length=15, label='学习宣言',
  33. error_messages={
  34. "min_length": '学习宣言最短5位',
  35. "max_length": '学习宣言最长15位',
  36. "required": '学习宣言不能为空',}
  37. , widget=forms.widgets.TextInput(attrs={'class': 'form-control'})
  38. )
  39. # 钩子函数
  40. # 局部钩子校验用户名是否已存在
  41. def clean_username(self):
  42. username = self.cleaned_data.get('username')
  43. is_alive = models.UserInfo.objects.filter(username=username)
  44. if is_alive:
  45. self.add_error('username','用户名已存在')
  46. return username
  47. # 全局钩子校验密码与确认密码是否一致
  48. def clean(self):
  49. password = self.cleaned_data.get('password')
  50. re_password = self.cleaned_data.get('re_password')
  51. if not password == re_password:
  52. self.add_error('re_password','两次密码不一致')
  53. return self.cleaned_data

3、登录功能

前端代码:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Title</title>
  6. <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
  7. <link rel="stylesheet" href="https://cdn.bootcss.com/font-awesome/4.7.0/css/font-awesome.min.css">
  8. <script src="https://cdn.bootcss.com/sweetalert/2.0.0/sweetalert.min.js"></script>
  9. <link rel="https://cdn.bootcss.com/sweetalert/1.1.3/sweetalert.min.css">
  10. {% load static %}
  11. <link rel="stylesheet" href="{% static '/bootstrap-3.3.7-dist/css/bootstrap.min.css'%}">
  12. <script src="{% static 'bootstrap-3.3.7-dist/js/bootstrap.min.js' %}"></script>
  13. </head>
  14. <body>
  15. <div class="container">
  16. <h2 class="text-center">登录页面</h2>
  17. <div class="row">
  18. <div class="col-md-8 col-md-offset-2">
  19. <div class="form-group">
  20. <label for="id_username">用户名</label>
  21. <input type="text" name="username" class="form-control" id="id_username">
  22. </div>
  23. <div class="form-group">
  24. <label for="id_password">密码</label>
  25. <input type="password" name="password" class="form-control" id="id_password">
  26. </div>
  27. <div class="form-group">
  28. <label for="id_code">验证码</label>
  29. <div class="row">
  30. <div class="col-md-6">
  31. <input type="text" name="code" class="form-control" id="id_code">
  32. </div>
  33. <div class="col-md-6">
  34. <img src="/get_code/" alt="图片验证码" id="id_img">
  35. </div>
  36. </div>
  37. </div>
  38. <input type="button" value="登录" class="btn btn-success" id="id_submit">
  39. <a href="/register/"><input type="button" value="注册" class="btn btn-danger"></a>
  40. <span style="color: red" id="error"></span>
  41. </div>
  42. </div>
  43. </div>
  44. <script>
  45. $('#id_img').click(function () {
  46. var oldSrc = $(this).attr('src');
  47. $(this).attr('src', oldSrc += '?')
  48. });
  49. $('#id_submit').click(function () {
  50. $.ajax({
  51. url:'',
  52. type:'post',
  53. data:{
  54. 'username': $('#id_username').val(),
  55. 'password': $('#id_password').val(),
  56. 'csrfmiddlewaretoken':'{{ csrf_token }}',
  57. 'code':$('#id_code').val()
  58. },
  59. success:function (data) {
  60. if (data.code === 1000){
  61. // 登录成功,跳转页面
  62. location.href = data.url
  63. }else {
  64. // 点击此按钮,添加文本信息
  65. $('#error').text(data.msg)
  66. }
  67. }
  68. })
  69. })
  70. </script>
  71. </body>
  72. </html>

后端代码:

urls.py:

  1. # 登录
  2. url(r'^login/', views.login, name='login'),

views.py:

  1. # 登录
  2. def login(request):
  3. back_dic = {'code': None, 'msg': None}
  4. if request.method == 'POST':
  5. username = request.POST.get('username')
  6. password = request.POST.get('password')
  7. code = request.POST.get('code') # 从前端拿过来的验证码
  8. # 先对比验证码
  9. if request.session.get('code').lower() == code.lower():
  10. # 校验用户名和密码
  11. user_obj = auth.authenticate(username=username, password=password)
  12. if user_obj:
  13. # 记录登录状态
  14. auth.login(request, user_obj)
  15. back_dic['code'] = 1000
  16. back_dic['msg'] = '登录成功'
  17. back_dic['url'] = '/home/'
  18. # back_dic['url'] = '/%s/' % username
  19. else:
  20. back_dic['code'] = 2000
  21. back_dic['msg'] = '用户名或密码错误'
  22. else:
  23. back_dic['code'] = 3000
  24. back_dic['msg'] = '验证码错误'
  25. return JsonResponse(back_dic)
  26. return render(request, 'login.html')

4、登录认证装饰器配置

settings.py:

  1. LOGIN_URL = '/login/'

5、修改密码模态框方法

前端代码:

  1. <li><a href="#" data-toggle="modal" data-target=".bs-example-modal-lg">修改密码</a></li>
  2. {#修改密码模态框#}
  3. <div class="modal fade bs-example-modal-lg" tabindex="-1" role="dialog" aria-labelledby="myLargeModalLabel">
  4. <div class="modal-dialog modal-lg" role="document">
  5. <div class="modal-content">
  6. <h2 class="text-center">修改密码</h2>
  7. <div class="row">
  8. <div class="col-md-8 col-md-offset-2">
  9. <div class="form-group">
  10. <label for="">用户名</label>
  11. <input type="text" name="username" value={{ request.user.username }} class="form-control"
  12. disabled>
  13. </div>
  14. <div class="form-group">
  15. <label for="id_old_password">原密码</label>
  16. <input type="password" name="old_password" class="form-control" id="id_old_password">
  17. </div>
  18. <div class="form-group">
  19. <label for="id_new_password">新密码</label>
  20. <input type="password" name="new_password" class="form-control" id="id_new_password">
  21. </div>
  22. <div class="form-group">
  23. <label for="id_confirm_password">确认密码</label>
  24. <input type="password" name="confirm_password" class="form-control" id="id_confirm_password">
  25. </div>
  26. <button class="btn btn-primary" id="id_set">修改</button>
  27. <button type="button" class="btn btn-default" data-dismiss="modal">取消</button>
  28. <span style="color: red"></span>
  29. </div>
  30. </div>
  31. <br>
  32. </div>
  33. </div>
  34. </div>

js代码:

  1. <script>
  2. {#修改密码#}
  3. $('#id_set').click(function () {
  4. var $btn = $(this);
  5. $.ajax({
  6. url: '{% url 'set_password' %}',
  7. type: 'post',
  8. data: {
  9. old_password: $('#id_old_password').val(),
  10. new_password: $('#id_new_password').val(),
  11. confirm_password: $('#id_confirm_password').val(),
  12. csrfmiddlewaretoken: '{{ csrf_token }}'
  13. },
  14. success: function (data) {
  15. if (data.code === 1000) {
  16. location.href = data.url
  17. } else {
  18. $btn.next().next().text(data.msg)
  19. }
  20. }
  21. })
  22. });
  23. </script>

后端代码:

urls.py:

  1. # 修改密码
  2. url(r'^set_password', views.set_password, name='set_password'),

views.py:

  1. # 修改密码
  2. @login_required
  3. def set_password(request):
  4. if request.is_ajax():
  5. back_dic = {'code': 1000, 'msg': ''}
  6. old_password = request.POST.get('old_password')
  7. new_password = request.POST.get('new_password')
  8. confirm_password = request.POST.get('confirm_password')
  9. if new_password == confirm_password:
  10. is_right = request.user.check_password(old_password)
  11. if is_right:
  12. request.user.set_password(new_password)
  13. request.user.save()
  14. back_dic['msg'] = '修改成功'
  15. back_dic['url'] = reverse('login')
  16. else:
  17. back_dic['code'] = 2000
  18. back_dic['msg'] = '原密码错误'
  19. else:
  20. back_dic['code'] = 3000
  21. back_dic['msg'] = '两次密码不一致'
  22. return JsonResponse(back_dic)

6、修改头像

前端代码:

  1. <li><a href="/set_avatar/">修改头像</a></li>

stt_avatar.html:

  1. {% extends 'base.html' %}
  2. {% block content %}
  3. <form action="" method="post" enctype="multipart/form-data">
  4. <p><a href="/home/">返回</a></p>
  5. <input type="file" name="myfile" id="id_avatar"><br>
  6. {% csrf_token %}
  7. <div class="form-group">
  8. <label for="id_avatar">
  9. <img src="/static/images/default.jpg" alt="" width="100" id="id_img">&nbsp;<span>新头像</span>
  10. </label>
  11. </div>
  12. <label for="id_avatar">
  13. <img src="/media/{{ request.user.avatar }}/" width="200" alt="原头像">&nbsp;<span>原头像</span>
  14. </label>
  15. <p><input type="submit" class="btn btn-primary"></p>
  16. </form>
  17. <script>
  18. $('#id_avatar').change(function () {
  19. // 1 先获取用户上传的头像文件
  20. var avatarFile = $(this)[0].files[0];
  21. // 2 利用文件阅读器对象
  22. var myFileReader = new FileReader();
  23. // 3 将文件交由阅读器对象读取
  24. myFileReader.readAsDataURL(avatarFile);
  25. // 4 修改img标签的src属性 等待文件阅读器对象读取文件之后再操作img标签
  26. myFileReader.onload = function () {
  27. $('#id_img').attr('src', myFileReader.result)
  28. }
  29. });
  30. </script>
  31. {% endblock %}

后端代码:

urls.py:

  1. # 修改用户头像
  2. url(r'^set_avatar/', views.set_avatar, name='set_avatar'),

views.py:

  1. # 修改头像
  2. @ login_required
  3. def set_avatar(request):
  4. if request.method == 'POST':
  5. avatar_obj = request.FILES.get('myfile')
  6. # models.UserInfo.objects.filter(pk=request.user.pk).update(avatar=avatar_obj) # 不会帮你自动添加前缀
  7. # 用自己的save方法,自动帮你添加前缀
  8. request.user.avatar = avatar_obj
  9. request.user.save()
  10. return render(request, 'set_avatar.html')

7、修改签名模态框方法

前端代码:

  1. <li><a href="#" data-toggle="modal" data-target=".set_sign">编辑签名</a></li>
  2. {#编辑签名模态框#}
  3. <div class="modal fade bs-example-modal-lg set_sign" id="set_sign" tabindex="-1" role="dialog"
  4. aria-labelledby="myLargeModalLabel">
  5. <div class="modal-dialog modal-lg" role="document">
  6. <div class="modal-content">
  7. <h2 class="text-center">编辑签名</h2>
  8. <div class="row">
  9. <div class="col-md-8 col-md-offset-2">
  10. <div class="form-group">
  11. <label for="">用户名</label>
  12. <input type="text" name="username" value={{ request.user.username }} class="form-control"
  13. disabled>
  14. </div>
  15. <div class="form-group">
  16. <label for="id_old_sign">原签名</label><br>
  17. <textarea name="old_sign" id="id_old_sign" cols="81" rows="5"
  18. disabled>{{ request.user.blog.site_title }}</textarea>
  19. </div>
  20. <div class="form-group">
  21. <label for="id_new_sign">新签名</label>
  22. <span style="color: red" id="error_sign"></span>
  23. <textarea name="new_sign" id="id_new_sign" cols="81" rows="5"></textarea>
  24. </div>
  25. <button class="btn btn-primary" id="set_sign">修改</button>
  26. <button type="button" class="btn btn-default" data-dismiss="modal">取消</button>
  27. </div>
  28. </div>
  29. <br>
  30. </div>
  31. </div>
  32. </div>

js代码:

  1. {#修改签名#}
  2. $("#set_sign").click(function () {
  3. $.ajax({
  4. url: '{% url 'set_sign' %}',
  5. type: 'post',
  6. data: {
  7. new_sign: $('#id_new_sign').val(),
  8. csrfmiddlewaretoken: '{{ csrf_token }}'
  9. },
  10. success: function (data) {
  11. if (data.code === 1000) {
  12. location.href = data.url;
  13. $('#error_sign').text(data.msg)
  14. } else {
  15. $('#error_sign').text(data.msg)
  16. }
  17. }
  18. })
  19. });

后端代码:

urls.py:

  1. # 编辑签名
  2. url(r'^set_sign', views.set_sign, name='set_sign'),

views.py:

  1. # 编辑签名
  2. @login_required
  3. def set_sign(request):
  4. if request.is_ajax():
  5. back_dic = {'code': 1000, 'msg': ''}
  6. site_name = request.user.username
  7. site_title = request.POST.get('new_sign')
  8. if len(site_title) < 5:
  9. back_dic['code'] = 2000
  10. back_dic['msg'] = '(你的学习宣言必须大于5位)'
  11. elif len(site_title) > 15:
  12. back_dic['code'] = 3000
  13. back_dic['msg'] = '(你的学习宣言必须小于于15位)'
  14. else:
  15. back_dic['code'] = 1000
  16. back_dic['url'] = reverse('home')
  17. back_dic['msg'] = '修改成功'
  18. models.Blog.objects.filter(site_name=site_name).update(site_title=site_title)
  19. return JsonResponse(back_dic)

8、注销功能模态框

前端代码:

  1. <li><a href="#" data-toggle="modal" data-target=".bs-example-modal-sm">注销</a></li>
  2. {# 退出确认模态框#}
  3. <div class="modal fade bs-example-modal-sm" tabindex="-1" role="dialog">
  4. <div class="modal-dialog modal-sm" role="document">
  5. <div class="modal-content">
  6. <div class="modal-header">
  7. <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
  8. aria-hidden="true">&times;</span></button>
  9. <h4 class="modal-title">你忍心离开我吗</h4>
  10. </div>
  11. <div class="modal-body">
  12. <p>确定退出?</p>
  13. </div>
  14. <div class="modal-footer">
  15. <button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
  16. <button type="button" class="btn btn-primary" id="exit">确定</button>
  17. </div>
  18. </div><!-- /.modal-content -->
  19. </div>
  20. </div>

js代码:

  1. {#注销#}
  2. $('#exit').click(function () {
  3. location.href = "/logout/"
  4. });

后端代码:

urls.py:

  1. # 注销
  2. url(r'^logout', views.logout, name='logout'),

views.py:

  1. # 注销
  2. @login_required
  3. def logout(request):
  4. auth.logout(request) # 原理删除了对应的session值
  5. return redirect(reverse('home'))

9、用户上传静态文件配置

setting.py文件配置:

配置好之后,文件夹自动创建

  1. # media配置
  2. MEDIA_ROOT = os.path.join(BASE_DIR, 'media') # 用户上传的文件全部保存该文件下

10、图片防盗链

请求头里面有一个referer请求头,用来标识你上一次是从哪一个网址过来的

判断上一次这个网址是否有权限

自己的项目:把图片所在的文件夹暴露,那么只能访问图片。

别人的图片怎么解决防盗链?:

  1. 1.用爬虫将所有的图片资源下载到本地 这是爬虫的价值所在
  2. 2.修改请求头参数 百度搜吧

referer属性:

11、暴露任意文件的配置

urls.py:

注意:千万不要暴露重要文件资源,否则拍屁股走人

MEDIA_ROOT,一定不要暴露关键文件

  1. from django.views.static import serve
  2. # 暴露任意后端资源配置
  3. url(r'^media/(?P<path>.*)', serve, {"document_root": settings.MEDIA_ROOT}),

图片文件地址:

  1. <img class="media-object" src="/media/{{ article_obj.blog.userinfo.avatar }}"
  2. style="width: 60px" alt="这是你的头像" width="60px;">

12、分页器的使用

分页器:新建py文件,把代码复制过来

代码:

  1. class Pagination(object):
  2. def __init__(self,current_page,all_count,per_page_num=2,pager_count=11):
  3. """
  4. 封装分页相关数据
  5. :param current_page: 当前页
  6. :param all_count: 数据库中的数据总条数
  7. :param per_page_num: 每页显示的数据条数
  8. :param pager_count: 最多显示的页码个数
  9. 用法:
  10. queryset = model.objects.all()
  11. page_obj = Pagination(current_page,all_count)
  12. page_data = queryset[page_obj.start:page_obj.end]
  13. 获取数据用page_data而不再使用原始的queryset
  14. 获取前端分页样式用page_obj.page_html
  15. """
  16. try:
  17. current_page = int(current_page)
  18. except Exception as e:
  19. current_page = 1
  20. if current_page <1:
  21. current_page = 1
  22. self.current_page = current_page
  23. self.all_count = all_count
  24. self.per_page_num = per_page_num
  25. # 总页码
  26. all_pager, tmp = divmod(all_count, per_page_num)
  27. if tmp:
  28. all_pager += 1
  29. self.all_pager = all_pager
  30. self.pager_count = pager_count
  31. self.pager_count_half = int((pager_count - 1) / 2)
  32. @property
  33. def start(self):
  34. return (self.current_page - 1) * self.per_page_num
  35. @property
  36. def end(self):
  37. return self.current_page * self.per_page_num
  38. def page_html(self):
  39. # 如果总页码 < 11个:
  40. if self.all_pager <= self.pager_count:
  41. pager_start = 1
  42. pager_end = self.all_pager + 1
  43. # 总页码 > 11
  44. else:
  45. # 当前页如果<=页面上最多显示11/2个页码
  46. if self.current_page <= self.pager_count_half:
  47. pager_start = 1
  48. pager_end = self.pager_count + 1
  49. # 当前页大于5
  50. else:
  51. # 页码翻到最后
  52. if (self.current_page + self.pager_count_half) > self.all_pager:
  53. pager_end = self.all_pager + 1
  54. pager_start = self.all_pager - self.pager_count + 1
  55. else:
  56. pager_start = self.current_page - self.pager_count_half
  57. pager_end = self.current_page + self.pager_count_half + 1
  58. page_html_list = []
  59. # 添加前面的nav和ul标签
  60. page_html_list.append('''
  61. <nav aria-label='Page navigation>'
  62. <ul class='pagination'>
  63. ''')
  64. first_page = '<li><a href="?page=%s">首页</a></li>' % (1)
  65. page_html_list.append(first_page)
  66. if self.current_page <= 1:
  67. prev_page = '<li class="disabled"><a href="#">上一页</a></li>'
  68. else:
  69. prev_page = '<li><a href="?page=%s">上一页</a></li>' % (self.current_page - 1,)
  70. page_html_list.append(prev_page)
  71. for i in range(pager_start, pager_end):
  72. if i == self.current_page:
  73. temp = '<li class="active"><a href="?page=%s">%s</a></li>' % (i, i,)
  74. else:
  75. temp = '<li><a href="?page=%s">%s</a></li>' % (i, i,)
  76. page_html_list.append(temp)
  77. if self.current_page >= self.all_pager:
  78. next_page = '<li class="disabled"><a href="#">下一页</a></li>'
  79. else:
  80. next_page = '<li><a href="?page=%s">下一页</a></li>' % (self.current_page + 1,)
  81. page_html_list.append(next_page)
  82. last_page = '<li><a href="?page=%s">尾页</a></li>' % (self.all_pager,)
  83. page_html_list.append(last_page)
  84. # 尾部添加标签
  85. page_html_list.append('''
  86. </nav>
  87. </ul>
  88. ''')
  89. return ''.join(page_html_list)

使用方法:

后端代码:

  1. from app01.utils.mypagenation import Pagination # 分页器导
  2. # 首页
  3. def home(request):
  4. # 将网站的所有文章展示到前端
  5. article_list = models.Article.objects.all()
  6. # 分页处理
  7. page_obj = Pagination(current_page=request.GET.get('page',1),all_count=article_list.count())
  8. article_list = article_list[page_obj.start:page_obj.end]
  9. return render(request, 'home.html', locals())

前端代码:

  1. {#分页器 #}
  2. <div class="text-center">{{ page_obj.page_html|safe }}</div>

13、每个用户拥有自己的css

1.在注册的时候把用户的css文件的名字固定写好,写进数据库

2.在用户编辑CSS的时候,再通过文件操作,创建用户固定的CSS文件

3.再应用导入自己的CSS文件

  1. {#引用自己的css#}
  2. <link rel="stylesheet" href="/media/css/{{ user_obj.blog.site_theme }}">

前端代码:

  1. <a href="{% url 'blog_css' %}">个人站点CSS设置</a>

urls.py:

  1. # 个人站点CSS设置
  2. url(r'^blog_css/', views.blog_css, name='blog_css'),

views.py:

  1. # 个人站点CSS设置
  2. @login_required
  3. def blog_css(request):
  4. username = request.user.username
  5. site_theme = models.Blog.objects.filter(site_name=username).first().site_theme
  6. css_dir = f'media/css/{site_theme}'
  7. if request.method == 'POST':
  8. new_css = request.POST.get('new_css')
  9. with open(css_dir, 'w', encoding='utf-8')as f:
  10. for line in new_css:
  11. res = line.replace('\n', '')
  12. f.write(res)
  13. f.close()
  14. return redirect('/blog_css/')
  15. if request.method == 'GET':
  16. # 先判断用户css文件是否存在,不存在就创建。存在就读取
  17. isfile = os.path.exists(css_dir)
  18. # 不存在创建空的css文件
  19. if not isfile:
  20. with open(css_dir, 'w')as f:
  21. f.close()
  22. # 存在就读取
  23. with open(css_dir, 'r')as f:
  24. old_css = f.read()
  25. return render(request, 'backend/blog_css.html', locals())

backend/blog_css.html:

  1. {% extends 'backend/backend_base.html' %}
  2. {% block article %}
  3. <form action="" method="post">
  4. {% csrf_token %}
  5. <h2>页面定制 CSS 代码</h2>
  6. <textarea name="new_css" id="" cols="100" rows="30">{{ old_css }}</textarea>
  7. <p>推荐客户端: <a href="">Open Live Writer</a></p>
  8. <p>MetaWeblog访问地址: <a href="http://127.0.0.1:8000/home">http://127.0.0.1:8000/home</a>/</p>
  9. <input type="submit" class="btn btn-primary">
  10. </form>
  11. {% endblock %}

14、分组,按年月等。官方推荐

-官方提供

from django.db.models.functions import TruncMonth

Article.objects

.annotate(month=TruncMonth('timestamp')) # Truncate to month and add to select list

.values('month') # Group By month

.annotate(c=Count('id')) # Select the count of the grouping

.values('month', 'c') # (might be redundant, haven't tested) select month and count

  1. # 3.按照文章的年月分组
  2. date_list = models.Article.objects.filter(blog=blog).\
  3. annotate(month=TruncMonth('create_time')).values(
  4. 'month').annotate(c=Count('pk')).values('c', 'month')
  1. {% for date in date_list %}
  2. <p>
  3. <a href="/{{ username }}/archive/{{ date.month|date:'Y-m' }}/">
  4. {{ date.month|date:'Y年m月' }}({{ date.c }})</a>
  5. </p>
  6. {% endfor %}

15、侧边栏筛选(自定义过滤器方法)

新建文件夹和py文件:

mytag.py代码:

  1. from django.template import Library
  2. from app01 import models
  3. from django.db.models import Count
  4. from django.db.models.functions import TruncMonth
  5. register = Library()
  6. # 侧边栏渲染,自定义过滤器方法
  7. @register.inclusion_tag('left_menu.html', name='my_left')
  8. def index(username):
  9. # 提供left_menu所需要的所有数据
  10. user_obj = models.UserInfo.objects.filter(username=username).first()
  11. blog = user_obj.blog
  12. # 1.查询当前用户的分类及每个分类下的文章数
  13. category_list = models.Category.objects.all().filter(blog=blog).annotate(article_sum=Count('article__pk')).values(
  14. 'article_sum', 'name', 'pk')
  15. # 2.查询当前用户的标签,及每个标签下的文章数
  16. tag_list = models.Tag.objects.all().filter(blog=blog).annotate(tag_sum=Count('article__pk')).values('tag_sum',
  17. 'name', 'pk')
  18. # 3.按照文章的年月分组
  19. date_list = models.Article.objects.filter(blog=blog).\
  20. annotate(month=TruncMonth('create_time')).values(
  21. 'month').annotate(c=Count('pk')).values('c', 'month')
  22. return locals()

left_menu.html:

  1. <div class="panel panel-primary">
  2. <div class="panel-heading">
  3. <h3 class="panel-title">文章分类</h3>
  4. </div>
  5. <div class="panel-body">
  6. {% for category in category_list %}
  7. <p><a href="/{{ username }}/category/{{ category.pk }}">{{ category.name }}({{ category.article_sum }})</a>
  8. </p>
  9. {% endfor %}
  10. </div>
  11. </div>
  12. <div class="panel panel-danger">
  13. <div class="panel-heading">
  14. <h3 class="panel-title">文章标签</h3>
  15. </div>
  16. <div class="panel-body">
  17. {% for tag in tag_list %}
  18. <p><a href="/{{ username }}/tag/{{ tag.pk }}">{{ tag.name }}({{ tag.tag_sum }})</a></p>
  19. {% endfor %}
  20. </div>
  21. </div>
  22. <div class="panel panel-warning">
  23. <div class="panel-heading">
  24. <h3 class="panel-title">日期归档</h3>
  25. </div>
  26. <div class="panel-body">
  27. {% for date in date_list %}
  28. <p>
  29. <a href="/{{ username }}/archive/{{ date.month|date:'Y-m' }}/">
  30. {{ date.month|date:'Y年m月' }}({{ date.c }})</a>
  31. </p>
  32. {% endfor %}
  33. </div>
  34. </div>

16、点赞点踩

前端样式:可以直接去别人网站拷贝html代码,改改自己用

  1. {# 点赞点踩前端样式#}
  2. <div class="clearfix">
  3. <div id="div_digg">
  4. <div class="diggit jeff">
  5. <span class="diggnum" id="digg_count">{{ article_obj.up_num }}</span>
  6. </div>
  7. <div class="buryit jeff">
  8. <span class="burynum" id="bury_count">{{ article_obj.down_num }}</span>
  9. </div>
  10. <div class="clear"></div>
  11. <div class="diggword" id="digg_tips" style="color: red">
  12. </div>
  13. </div>
  14. </div>

js代码:

  1. <script>
  2. {#点赞点踩JS代码#}
  3. $('.jeff').click(function () {
  4. var $divEle = $(this);
  5. $.ajax({
  6. url: '{% url 'updown' %}',
  7. type: 'post',
  8. data: {
  9. 'article_id':{{ article_obj.pk }},
  10. 'is_up': $(this).hasClass('diggit'),
  11. 'csrfmiddlewaretoken': '{{ csrf_token }}'
  12. },
  13. success: function (data) {
  14. if (data.code === 1000) {
  15. $('#digg_tips').text(data.msg);
  16. $divEle.children().text(Number($divEle.children().text()) + 1)
  17. } else {
  18. $('#digg_tips').html(data.msg)
  19. }
  20. }
  21. })
  22. });
  23. </script>

后端:

urls.py:

  1. # 点赞点踩
  2. url(r'^up_or_down/', views.up_or_down, name='updown'),

views.py:

  1. # 点赞点踩
  2. import json
  3. from django.contrib import auth
  4. from django.db.models import F
  5. def up_or_down(request):
  6. bank_dic = {'code': 1000, 'msg': ''}
  7. if request.is_ajax():
  8. article_id = request.POST.get('article_id')
  9. # 注意:前端返回来的bool值是str形式。拿到是点赞还是点踩 赞True 踩false
  10. is_up = request.POST.get('is_up')
  11. is_up = json.loads(is_up) # 转成python形式的bool值
  12. '''
  13. 1.必须是登录的用户才能点赞点踩,判断用户是否登录
  14. 2.判断当前文章是否是用户自己写的,自己不能给自己点赞点踩
  15. 3.当前用户是否已经给文章点过赞或踩了
  16. 4.操作数据库---操作两张表,优化表字段
  17. '''
  18. # 1.判断用户是否已登录
  19. if request.user.is_authenticated():
  20. # 2.拿到当前文章,从文章里拿到当前用户,和登录的用户比较。如果用户一样,则证明是自己写的文章,不能点赞踩
  21. article_obj = models.Article.objects.filter(pk=article_id).first()
  22. if not article_obj.blog.userinfo.pk == request.user.pk:
  23. # 3.判断当前用户是否已经给当前文章点过赞或踩了。到点赞点踩表中查询是否有当前用户的记录,如果有,则证明当前用户已经点过了
  24. is_click = models.UpAndDown.objects.filter(user=request.user.pk, article=article_id)
  25. if not is_click:
  26. # 用户没电点过,操作表数据.第一张表
  27. # 点赞给点赞字段+1
  28. if is_up:
  29. models.Article.objects.filter(pk=article_id).update(up_num=F('up_num') + 1)
  30. bank_dic['msg'] = '点赞成功'
  31. # 点踩给点踩字段+1
  32. else:
  33. models.Article.objects.filter(pk=article_id).update(down_num=F('down_num') + 1)
  34. bank_dic['msg'] = '点踩成功'
  35. # 操作表数据,第二张表
  36. models.UpAndDown.objects.create(user=request.user, article=article_obj, is_up=is_up)
  37. else:
  38. bank_dic['code'] = 2000
  39. bank_dic['msg'] = '你已经点过了'
  40. else:
  41. bank_dic['code'] = 3000
  42. bank_dic['msg'] = '不能给自己点'
  43. else:
  44. bank_dic['code'] = 4000
  45. bank_dic['msg'] = '请先<a href="/login/">登录</a>'
  46. return JsonResponse(bank_dic)

17、模板字符串

文章评论零时渲染:

  1. //定义全局变量
  2. var parentId = null;
  3. // 文章评论js代码
  4. $('#id_comment').click(function () {
  5. var conTent = $('#id_content').val();
  6. // 如果是根评论不处理,如果是子评论需要处理,将@jeff 切割
  7. // @jeff 萨尔
  8. if (parentId) {
  9. //切割方式 获取第一个\n对应的索引
  10. var indexN = conTent.indexOf('\n') + 1 //顾头不顾尾
  11. // 按照获取的索引切割
  12. conTent = conTent.slice(indexN) //将indexN之前的全部切除,中保留之后的
  13. }
  14. $.ajax({
  15. url: '{% url "comment" %}',
  16. type: 'post',
  17. data: {
  18. "article_id":{{ article_obj.pk }},
  19. "content": conTent,
  20. "csrfmiddlewaretoken": '{{ csrf_token }}',
  21. "parent_id": parentId
  22. },
  23. success: function (data) {
  24. if (data.code === 1000) {
  25. // 临时渲染评论内容
  26. var UserName = '{{ request.user.username }}';
  27. var conTent = $('#id_content').val();
  28. // 将内容临时渲染到ul标签内
  29. var temp = `
  30. <li class="list-group-item">
  31. <span><span class="glyphicon glyphicon-comment"></span><a href="/${UserName}/">${UserName}</a></span>
  32. <div>
  33. ${conTent}
  34. </div>
  35. </li>
  36. `;
  37. $('.list-group').append(temp);
  38. // 将获取用户输入评论的内容框清空
  39. $('#id_content').val('');
  40. // 将全局的parentId清空,否则parentId后续一直有值,就一直是子评论
  41. parentId = null
  42. }
  43. }
  44. })
  45. });

18、KindEditor编辑器使用

看官方文档

前端内容:

  1. {% extends 'backend/backend_base.html' %}
  2. {% block article %}
  3. <h2>添加文章</h2>
  4. <form action="" method="post">
  5. {% csrf_token %}
  6. <p>标题</p>
  7. <p>
  8. <input type="text" name="title" class="form-control">
  9. </p>
  10. <p>内容(使用kindeditor编辑器)</p>
  11. <p>
  12. <textarea name="content" id="id_content" cols="60" rows="20"></textarea>
  13. </p>
  14. <div>
  15. <p>文章标签</p>
  16. <p>
  17. {% for tag in tag_list %}
  18. {{ tag.name }} <input type="checkbox" name="tag" value="{{ tag.pk }}">
  19. {% endfor %}
  20. </p>
  21. </div>
  22. <div>
  23. <p>文章分类</p>
  24. <p>
  25. {% for category in category_list %}
  26. {{ category.name }} <input type="radio" name="category" value="{{ category.pk }}">
  27. {% endfor %}
  28. </p>
  29. </div>
  30. <input type="submit" class="btn btn-primary" value="添加">
  31. </form>
  32. <script charset="utf-8" src="/static/kindeditor/kindeditor-all-min.js"></script>
  33. <script>
  34. KindEditor.ready(function(K) {
  35. window.editor = K.create('#id_content',{
  36. width:'100%',
  37. height:'500px',
  38. resizeType:0,
  39. uploadJson : '/upload_image/', //控制用户写文章上传文件的后端地址
  40. extraFileUploadParams : {
  41. 'csrfmiddlewaretoken':'{{ csrf_token }}',
  42. }
  43. });
  44. });
  45. </script>
  46. {% endblock %}

后端代码:

urls.py:

  1. # 添加文章
  2. url(r'^add_article/', views.add_article, name='add_article'),

views.py:

  1. # 添加随笔
  2. from bs4 import BeautifulSoup
  3. @login_required
  4. def add_article(request):
  5. if request.method == 'POST':
  6. # 获取从前端页面传来的文章数据
  7. title = request.POST.get('title')
  8. content = request.POST.get('content')
  9. tag_list = request.POST.get('tag')
  10. category_id = request.POST.get('category')
  11. # 先生成一个该模块beautifulsoup4的对象
  12. soup = BeautifulSoup(content, 'html.parser')
  13. for tag in soup.find_all():
  14. # 筛选除script标签直接删除,避免XSS攻击
  15. if tag.name == 'script':
  16. tag.decompose() # 删除该标签
  17. # desc = content[0:150] # 截取文章简介,错误示范。会从html代码截取
  18. desc = soup.text[0:150] # 通过模块处理,直接从内容截取
  19. # 写入数据
  20. article_obj = models.Article.objects.create(title=title, desc=desc, content=str(soup), category_id=category_id, blog=request.user.blog)
  21. # 手动操作文章与标签的第三张表
  22. # 用批量插入数据 bulk_create
  23. b_list = []
  24. for tag_id in tag_list:
  25. b_list.append(models.Article2Tag(article=article_obj, tag_id=tag_id))
  26. models.Article2Tag.objects.bulk_create(b_list)
  27. return redirect(reverse('backend'))
  28. # 获取文章分类、文章标签列表,让用户选择添加文章的分类与标签
  29. category_list = models.Category.objects.filter(blog=request.user.blog)
  30. tag_list = models.Tag.objects.filter(blog=request.user.blog)
  31. return render(request, 'backend/add_article.html', locals())

19、Django时区及国际化设置

  1. LANGUAGE_CODE = 'zh-hans' # 更改国际化翻译,中文
  2. TIME_ZONE = 'Asia/Shanghai' # 更改东八区时间
  3. USE_TZ = False # 表示数据库的同步时间,使用上面的东八区时间

20、models.py代码

  1. from django.db import models
  2. from django.contrib.auth.models import AbstractUser
  3. # Create your models here.
  4. # 用户表
  5. class UserInfo(AbstractUser):
  6. phone = models.BigIntegerField(null=True, blank=True) # blank=True 告诉后台管理该字段可以为空
  7. # 存用户头像的地址
  8. avatar = models.FileField(upload_to='avatar/', default='avatar/default.jpg')
  9. create_time = models.DateField(auto_now_add=True) # 创建时间自动
  10. # 一个用户只能有一个站点,一个站点给一个用户用。一对一
  11. blog = models.OneToOneField(to='Blog', null=True)
  12. # admin后台管理页面展示的表名
  13. class Meta:
  14. verbose_name_plural = '用户表'
  15. # 给前端便于展示
  16. def __str__(self):
  17. return self.username
  18. # 个人站点表
  19. class Blog(models.Model):
  20. site_name = models.CharField(max_length=32)
  21. site_title = models.CharField(max_length=64)
  22. site_theme = models.CharField(max_length=64) # 站点样式
  23. class Meta:
  24. verbose_name_plural = '个人站点表'
  25. # 便于前端展示
  26. def __str__(self):
  27. return self.site_name
  28. # 分类表
  29. class Category(models.Model):
  30. name = models.CharField(max_length=32)
  31. # 一个站点有多个类,一个类中只有一个站点。一对多,外键在多的一张表中
  32. blog = models.ForeignKey(to='Blog', null=True)
  33. class Meta:
  34. verbose_name_plural = '分类表'
  35. def __str__(self):
  36. return self.name
  37. # 标签表
  38. class Tag(models.Model):
  39. name = models.CharField(max_length=32) # 标签名
  40. blog = models.ForeignKey(to='Blog', null=True) # 一对多,外键在多的一张表中
  41. class Meta:
  42. verbose_name_plural = '标签表'
  43. def __str__(self):
  44. return self.name
  45. # 文章表
  46. class Article(models.Model):
  47. title = models.CharField(max_length=64) # 标题
  48. desc = models.CharField(max_length=254) # 摘要
  49. content = models.TextField() # 文章内容
  50. create_time = models.DateTimeField('Edit the date', auto_now_add=True) # 创建时间自动
  51. # 这里考虑到复杂度,我们使用简单的版本。一篇文章只能分到一个类中。一对多的关系
  52. # 一对多,分类字段
  53. category = models.ForeignKey(to='Category', null=True)
  54. # 多对多,标签字段
  55. tags = models.ManyToManyField(to='Tag', through='Article2Tag', through_fields=('article', 'tag'))
  56. # 一对多,个人站点字段。一个站点拥有多篇文章,一个文章只有一个站点
  57. blog = models.ForeignKey(to='Blog', null=True)
  58. # 数据库优化设计,把这三个字段加到文章表中,时时更新就行了。
  59. # 不用再到下面这几张表中查询,减少了查询的次数
  60. comment_num = models.BigIntegerField(null=True, default=0) # 评论人数
  61. up_num = models.BigIntegerField(null=True, default=0) # 点赞人数
  62. down_num = models.BigIntegerField(null=True, default=0) # 点踩人数
  63. class Meta:
  64. verbose_name_plural = '文章表'
  65. def __str__(self):
  66. return self.title
  67. # 文章和标签的第三张关系表
  68. class Article2Tag(models.Model):
  69. article = models.ForeignKey(to='Article')
  70. tag = models.ForeignKey(to='Tag')
  71. class Meta:
  72. verbose_name_plural = '文章标签多对多关系表'
  73. # 点赞点踩表
  74. class UpAndDown(models.Model):
  75. user = models.ForeignKey(to='UserInfo') # 放用户名
  76. article = models.ForeignKey(to='Article') # 放文章
  77. is_up = models.BooleanField() # 标识赞或踩,0,1
  78. class Meta:
  79. verbose_name_plural = '点赞点踩表'
  80. # 评论表
  81. class Comment(models.Model):
  82. user = models.ForeignKey(to='UserInfo')
  83. article = models.ForeignKey(to='Article') # 放文章
  84. content = models.CharField(max_length=254)
  85. comment_time = models.DateTimeField('Edit the date', auto_now_add=True) # 评论时间
  86. # 该字段存的是父评论的主键值
  87. # 如果有值 说明当前评论是子评论 如果没有值 说明当前评论是根评论
  88. parent = models.ForeignKey(to='self', null=True)
  89. class Meta:
  90. verbose_name_plural = '评论表'

21、urls.py代码

  1. """BBS URL Configuration
  2. The `urlpatterns` list routes URLs to views. For more information please see:
  3. https://docs.djangoproject.com/en/1.11/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: url(r'^$', 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: url(r'^$', Home.as_view(), name='home')
  11. Including another URLconf
  12. 1. Import the include() function: from django.conf.urls import url, include
  13. 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls'))
  14. """
  15. from django.conf.urls import url
  16. from django.contrib import admin
  17. from app01 import views
  18. from django.views.static import serve
  19. from BBS import settings
  20. urlpatterns = [
  21. url(r'^admin/', admin.site.urls),
  22. # 注册
  23. url(r'^register/', views.register, name='register'),
  24. # 登录
  25. url(r'^login/', views.login, name='login'),
  26. # 获取图片验证码
  27. url(r'^get_code/', views.get_code, name='get_code'),
  28. # 首页
  29. url(r'^home/', views.home, name='home'),
  30. url(r'^$', views.home, name='home'),
  31. # 修改密码
  32. url(r'^set_password', views.set_password, name='set_password'),
  33. # 编辑签名
  34. url(r'^set_sign', views.set_sign, name='set_sign'),
  35. # 修改用户头像
  36. url(r'^set_avatar/', views.set_avatar, name='set_avatar'),
  37. # 注销
  38. url(r'^logout', views.logout, name='logout'),
  39. # 暴露任意后端资源配置
  40. url(r'^media/(?P<path>.*)', serve, {"document_root": settings.MEDIA_ROOT}),
  41. # 点赞点踩
  42. url(r'^up_or_down/', views.up_or_down, name='updown'),
  43. # 文章评论
  44. url(r'^comment/', views.comment, name='comment'),
  45. # 后台管理
  46. url(r'^backend/', views.backend, name='backend'),
  47. # 添加文章
  48. url(r'^add_article/', views.add_article, name='add_article'),
  49. # 编辑分类
  50. url(r'^edit_category/', views.edit_category, name='edit_category'),
  51. # 编辑标签
  52. url(r'^edit_tag/', views.edit_tag, name='edit_tag'),
  53. # 添加分类
  54. url(r'^create_category/', views.create_category, name='create_category'),
  55. # 添加标签
  56. url(r'^create_tag/', views.create_tag, name='create_tag'),
  57. # 删除分类
  58. url(r'^delete_category/(?P<del_id>\d+)/', views.delete_category, name='delete_category'),
  59. # 删除标签
  60. url(r'^delete_tag/(?P<del_id>\d+)/', views.delete_tag, name='delete_tag'),
  61. # 编辑分类名
  62. url(r'^edit_category_name/(?P<edit_id>\d+)/', views.edit_category_name, name='edit_category_name'),
  63. # 编辑标签名
  64. url(r'^edit_tag_name/(?P<edit_id>\d+)/', views.edit_tag_name, name='edit_tag_name'),
  65. # 个人站点CSS设置
  66. url(r'^blog_css/', views.blog_css, name='blog_css'),
  67. # 编辑器上传图片
  68. url(r'^upload_image/', views.upload_image, name='upload_image'),
  69. # 个人站点
  70. url(r'^(?P<username>\w+)/$', views.site, name='site'),
  71. # 侧边栏筛选功能
  72. # url(r'^(?P<username>\w+)/category/(\d+)', views.site),
  73. # url(r'^(?P<username>\w+)/tag/(\d+)', views.site),
  74. # url(r'^(?P<username>\w+)/archive/(.*)', views.site),
  75. # 合并3条url
  76. url(r'^(?P<username>\w+)/(?P<condition>category|tag|archive)/(?P<param>.*)/', views.site),
  77. # 文章详情页
  78. url(r'^(?P<username>\w+)/article/(?P<article_id>\d+)/', views.article_detail)
  79. ]

22、mytag代码

  1. from django.template import Library
  2. from app01 import models
  3. from django.db.models import Count
  4. from django.db.models.functions import TruncMonth
  5. register = Library()
  6. # 侧边栏渲染,自定义过滤器方法
  7. @register.inclusion_tag('left_menu.html', name='my_left')
  8. def index(username):
  9. # 提供left_menu所需要的所有数据
  10. user_obj = models.UserInfo.objects.filter(username=username).first()
  11. blog = user_obj.blog
  12. # 1.查询当前用户的分类及每个分类下的文章数
  13. category_list = models.Category.objects.all().filter(blog=blog).annotate(article_sum=Count('article__pk')).values(
  14. 'article_sum', 'name', 'pk')
  15. # 2.查询当前用户的标签,及每个标签下的文章数
  16. tag_list = models.Tag.objects.all().filter(blog=blog).annotate(tag_sum=Count('article__pk')).values('tag_sum',
  17. 'name', 'pk')
  18. # 3.按照文章的年月分组
  19. date_list = models.Article.objects.filter(blog=blog).\
  20. annotate(month=TruncMonth('create_time')).values(
  21. 'month').annotate(c=Count('pk')).values('c', 'month')
  22. return locals()

DjangoBBS项目功能拆分的更多相关文章

  1. Maven 通过maven对项目进行拆分、聚合(重点)

    对现在已有maven ssh项目进行拆分,拆分思路:将dao层的代码已经配置文件全体提取出来到一个表现上独立的工程中.同样service.action拆分. ssh-parent: 父工程 ssh-d ...

  2. Maven项目的拆分与聚合

    ---------------------siwuxie095                                     Maven 项目的拆分与聚合         1.对已有的 Ma ...

  3. 【原】公司P2P平台的功能拆分

    银行回调:由原来写在PC门户项目中拆分开来,作为一个专门处理回调的项目,配置多个数据源,实时写入数据库. 定时回查:由原来写在PC后台管理项目中拆分开来,作为一个专门回查银行网关的项目. 请求银行:由 ...

  4. Vue项目功能插件

    项目功能插件 vue-router { path: '/', name: 'home', // 路由的重定向 redirect: '/home' } { // 一级路由, 在根组件中被渲染, 替换根组 ...

  5. GitHub项目功能理解

    目录 github账号看板使用方式 code issues Pull Requests Projects Insights Settings date: 2019-4-26 author:yangxi ...

  6. 学霸系统UI项目功能说明书 v1.0版本

    发布人员:软件工程实践小队. 发布内容:学霸系统UI项目说明书. 版本:学霸v1.0版本. 学霸系统UI项目说明书 v1.0版本分为以下部分: Part 1:用户须知: Part 2:功能实现: Pa ...

  7. Django 项目配置拆分独立

    目录 一.创建配置目录 二.创建基础配置文件 三.创建各个环境的配置 四.调整settings.py 五.程序使用 六.目录结构 Django 项目中,我们默认的配置是都在 settings.py 文 ...

  8. 企业nginx应用实例(功能拆分记录)

    一.默认访问协议强制跳转(http--->https) server { listen ; server_name dannylinux.top www.dannylinux.top; # re ...

  9. iOS- xib(nib) 的重用(在有些情况下有利于加快项目功能的实现)

    0.前言 在项目开发中,我们经常会碰到,某些视图View 内部基本空间都一样,只是数据不同,这时,我们可以用xib来将这个视图封装起来多次重用, (例如,大小固定 控件固定的TableViewCell ...

随机推荐

  1. 【题解】P1712 [NOI2016]区间(贪心+线段树)

    [题解]P1712 [NOI2016]区间(贪心+线段树) 一个observe是,对于一个合法的方案,将其线段长度按照从大到小排序后,他极差的来源是第一个和最后一个.或者说,读入的线段按照长度分类后, ...

  2. 洛谷$P$3327 约数个数和 $[SDOI2015]$ 莫比乌斯反演

    正解:莫比乌斯反演 解题报告: 传送门! 先考虑证明一个结论,$d_{i\cdot j}=\sum_{p|i}\sum_{q|j}[gcd(p,q)==1]$ 看起来就很对的样子,但还是证下趴$QwQ ...

  3. POJ2186 Popular Cows 题解 强连通分量

    题目链接:http://poj.org/problem?id=2186 题目大意: 每头牛都想成为牛群中的红人. 给定N头牛的牛群和M个有序对(A, B),(A, B)表示牛A认为牛B是红人: 该关系 ...

  4. Selenium python爬虫

    Selenium + Python3 爬虫 准备工作 Chrome驱动下载地址(可正常访问并下载),根据自己chrome的版本下载 Chrome版本 下载地址 78 https://chromedri ...

  5. KafkaProducer Sender 线程详解(含详细的执行流程图)

    目录 1.Sender 线程详解 2.RecordAccumulator 核心方法详解 温馨提示:本文基于 Kafka 2.2.1 版本. 上文 <源码分析 Kafka 消息发送流程> 已 ...

  6. VS Code配置C/C++环境

    VS Code配置C/C++环境 一.下载和安装VS Code 1.访问VS Code官网下载安装包 2.安装VS Code 3. 安装后, 打开VS Code是英文,按住Ctrl+shift+x进入 ...

  7. windows生成github密钥并推送文件踩坑

    强调官方文档最可靠,百度踩坑很浪费时间,建议去寻找一手数据源头 github官方文档提供了帮助 第一步 查看密钥 如果您还没有 SSH 密钥,则必须生成新 SSH 密钥. 如果您不确定是否已有 SSH ...

  8. vnpy源码阅读学习(2):学习PyQt5

    PyQt5的学习 花费了一个下午把PyQt5大概的学习了下.找了一个教程 PyQt5教程 跟着挨着把上面的案例做了一遍,大概知道PyQt5是如何生成窗体,以及控件的.基本上做到如果有需求要实现,查查手 ...

  9. vue的param和query两种传参方式及URL的显示

    路由配置: // 首页 { path: '/home', name:'home', component:Home }, // 行情 { path: '/markets', name:'market', ...

  10. feign架构 原理解析

    什么是feign? 来自官网的解释:Feign makes writing java http clients easier 在使用feign之前,我们怎么发送请求? 拿okhttp举例: publi ...