概述

  通过自己写的博客后台代码、思路,来与武sir的代码进行一个差异化的比较,记录之间的差距,改善以后写代码的思路

  博客后台这个项目,对之前Django学习的各个知识点都有涉及到,非常重要

用户登录验证

数据库表:

  1. from django.db import models
  2.  
  3. # 除了主键其他默认可以为空
  4. # max_length在CharField中必填
  5.  
  6. class UserInfo(models.Model):
  7. """
  8. 用户表
  9. """
  10. nid = models.BigAutoField(primary_key=True) # 主键自增 8位数
  11. username = models.CharField(verbose_name='用户名', max_length=32, unique=True) # unique 唯一性
  12. password = models.CharField(verbose_name='密码', max_length=64) # verbose_name ModeForm验证时显示名,
  13. nickname = models.CharField(verbose_name='昵称', max_length=32) # 等同于Form类里面的label
  14. email = models.EmailField(verbose_name='邮箱', unique=True) # unique 唯一性
  15. avatar = models.ImageField(verbose_name='头像')
  16.  
  17. create_time = models.DateTimeField(verbose_name='创建时间', auto_now_add=True) # auto_now_add 更新时,自动更新为当前时间
  18.  
  19. fans = models.ManyToManyField(verbose_name='粉丝们', to='UserInfo', through='UserFans',
  20. through_fields=('user', 'follower'))
  21.  
  22. class Blog(models.Model):
  23. """
  24. 博客信息
  25. """
  26. nid = models.BigAutoField(primary_key=True)
  27. title = models.CharField(verbose_name='个人博客标题', max_length=64)
  28. site = models.CharField(verbose_name='个人博客前缀', max_length=32, unique=True)
  29. theme = models.CharField(verbose_name='博客主题', max_length=32)
  30.  
  31. user = models.OneToOneField(to='UserInfo', to_field='nid')
  32.  
  33. class UserFans(models.Model):
  34. """
  35. 互粉关系表
  36. """
  37. user = models.ForeignKey(verbose_name='博主', to='UserInfo', to_field='nid', related_name='users')
  38. follower = models.ForeignKey(verbose_name='粉丝', to='UserInfo', to_field='nid', related_name='followers')
  39.  
  40. # 联合唯一索引 索引本身目的就是加快查询速度
  41. class Meta:
  42. unique_together = [
  43. ('user', 'follower'),
  44. ]
  45.  
  46. class Category(models.Model):
  47. """
  48. 博主个人文章分类表,自创建
  49. """
  50. nid = models.AutoField(primary_key=True)
  51. title = models.CharField(verbose_name='分类标题', max_length=32)
  52.  
  53. blog = models.ForeignKey(verbose_name='所属博客', to='Blog', to_field='nid')
  54.  
  55. class ArticleDetail(models.Model):
  56. """
  57. 文章详细表
  58. """
  59. content = models.TextField(verbose_name='文章内容', )
  60.  
  61. article = models.OneToOneField(verbose_name='所属文章', to='Article', to_field='nid')
  62.  
  63. class UpDown(models.Model):
  64. """
  65. 文章顶或踩
  66. """
  67. article = models.ForeignKey(verbose_name='文章', to='Article', to_field='nid')
  68. user = models.ForeignKey(verbose_name='赞或踩用户', to='UserInfo', to_field='nid')
  69. up = models.BooleanField(verbose_name='是否赞')
  70.  
  71. class Meta:
  72. unique_together = [
  73. ('article', 'user'),
  74. ]
  75.  
  76. class Comment(models.Model):
  77. """
  78. 评论表
  79. """
  80. nid = models.BigAutoField(primary_key=True)
  81. content = models.CharField(verbose_name='评论内容', max_length=255)
  82. create_time = models.DateTimeField(verbose_name='创建时间', auto_now_add=True)
  83.  
  84. reply = models.ForeignKey(verbose_name='回复评论', to='self', related_name='back', null=True)
  85. article = models.ForeignKey(verbose_name='评论文章', to='Article', to_field='nid')
  86. user = models.ForeignKey(verbose_name='评论者', to='UserInfo', to_field='nid')
  87.  
  88. class Tag(models.Model):
  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')
  92.  
  93. class Article(models.Model):
  94. '''
  95. 文章简介表
  96. '''
  97. nid = models.BigAutoField(primary_key=True)
  98. title = models.CharField(verbose_name='文章标题', max_length=128)
  99. summary = models.CharField(verbose_name='文章简介', max_length=255)
  100. read_count = models.IntegerField(default=0)
  101. comment_count = models.IntegerField(default=0)
  102. up_count = models.IntegerField(default=0)
  103. down_count = models.IntegerField(default=0)
  104. create_time = models.DateTimeField(verbose_name='创建时间', auto_now_add=True)
  105.  
  106. blog = models.ForeignKey(verbose_name='所属博客', to='Blog', to_field='nid')
  107. category = models.ForeignKey(verbose_name='文章类型', to='Category', to_field='nid', null=True)
  108.  
  109. type_choices = [
  110. (1, "Python"),
  111. (2, "Linux"),
  112. (3, "OpenStack"),
  113. (4, "GoLang"),
  114. ]
  115.  
  116. article_type_id = models.IntegerField(choices=type_choices, default=None)
  117.  
  118. tags = models.ManyToManyField(
  119. to="Tag",
  120. through='Article2Tag',
  121. through_fields=('article', 'tag'),
  122. )
  123.  
  124. class Article2Tag(models.Model):
  125. '''
  126. 文章跟标签对应关系
  127. '''
  128. article = models.ForeignKey(verbose_name='文章', to="Article", to_field='nid')
  129. tag = models.ForeignKey(verbose_name='标签', to="Tag", to_field='nid')
  130.  
  131. class Meta:
  132. unique_together = [
  133. ('article', 'tag'),
  134. ]

models.py

我的代码:

  1. from django import forms
  2. from django.forms import fields
  3. from django.forms import widgets
  4.  
  5. from repository import models
  6. from django.core.exceptions import ValidationError
  7.  
  8. class LoginForm(forms.Form):
  9. username = fields.CharField(
  10. max_length=12,
  11. widget=widgets.Input(attrs={'class':'form-control','placeholder':"请输入用户名"}),
  12. error_messages={'required': '用户名不能为空',
  13. 'max_length': '密码长度不能大于12位'}
  14. )
  15. password = fields.CharField(
  16. max_length=12,
  17. min_length=6,
  18. widget=widgets.PasswordInput(attrs={'class':'form-control','placeholder':"请输入密码"}),
  19. error_messages={'required': '密码不能为空', 'min_length': '密码长度不能小于6位',
  20. 'max_length': '密码长度不能大于12位'}
  21. )
  22. check_code = fields.CharField(
  23. error_messages={'required': '验证码不能为空', }
  24. )
  25.  
  26. def clean(self):
  27. user_obj = models.UserInfo.objects.filter(
  28. username=self.cleaned_data.get('username'),password=self.cleaned_data.get('password')
  29. ).first()
  30. if user_obj:
  31. return self.cleaned_data['username']
  32. else:
  33. raise ValidationError(message='用户名或密码错误')
  34.  
  35. def clean_check_code(self):
  36. code = self.request.POST.get('check_code')
  37. if code.upper() == self.request.session['CheckCode'].upper():
  38. return self.cleaned_data['check_code']
  39. else:
  40. raise ValidationError(message='验证码错误')
  41.  
  42. def __init__(self,*args,**kwargs):
  43. super().__init__(*args,**kwargs)
  44. if args:
  45. self.request = args[1]

from.py

  1. from io import BytesIO
  2. from django.shortcuts import HttpResponse
  3. from django.shortcuts import render
  4. from django.shortcuts import redirect
  5. from utils.check_code import create_validate_code
  6. from web.views.form import LoginForm
  7. from web.views.form import RegisterForm
  8. from repository import models
  9.  
  10. import json
  11.  
  12. def check_code(request):
  13. """
  14. 验证码
  15. :param request:
  16. :return:
  17. """
  18. # 1. 创建一张图片 pip3 install Pillow
  19. # 2. 在图片中写入随机字符串
  20. # obj = object()
  21. # 3. 将图片写入到制定文件
  22. # 4. 打开制定目录文件,读取内容
  23. # 5. HttpResponse(data)
  24.  
  25. stream = BytesIO() #在内存中生成一个文件对象
  26. img, code = create_validate_code() #生成图片img和字符串code
  27. img.save(stream,'PNG') #把验证图片存放到内存中以PNG名存放
  28. request.session['CheckCode'] = code #把生成的字符串code存放到session中
  29. # print('验证码',code)
  30. return HttpResponse(stream.getvalue()) #stream.getvalue()返回图片的内容
  31.  
  32. def login(request):
  33. """
  34. 登陆
  35. """
  36. if request.method == 'GET':
  37. if request.session.get('is_login',None):
  38. return redirect('/index/')
  39. else:
  40. obj = LoginForm()
  41. return render(request, 'login.html',{'obj':obj})
  42. elif request.method == 'POST':
  43. data = {'status': True, 'error': None,}
  44. obj = LoginForm(request.POST,request)
  45. result = obj.is_valid()
  46. if result:
  47. print('验证通过')
  48. username = request.POST.get('username')
  49. user_dict = models.UserInfo.objects.filter(username=username).values('nid','username','nickname','email','blog__site',
  50. 'blog__title','blog__theme')[0]
  51. for key in user_dict:
  52. request.session[key] = user_dict[key]
  53.  
  54. request.session['is_login']=True
  55. if request.POST.get('rmb') == '':
  56. request.session.set_expiry(60*60*24*30)
  57. else:
  58. print(obj.errors.as_json)
  59. data['status'] = False
  60. data['error'] = obj.errors
  61.  
  62. return HttpResponse(json.dumps(data))

views.py

  1. <!DOCTYPE html>
  2. <html>
  3. <head lang="en">
  4. <meta charset="UTF-8">
  5. <title></title>
  6. <link rel="stylesheet" href="/static/plugins/bootstrap/css/bootstrap.css"/>
  7. <link rel="stylesheet" href="/static/plugins/font-awesome/css/font-awesome.css"/>
  8. <link rel="stylesheet" href="/static/css/edmure.css"/>
  9. <link rel="stylesheet" href="/static/css/commons.css"/>
  10. <link rel="stylesheet" href="/static/css/account.css"/>
  11. <style>
  12. </style>
  13. </head>
  14. <body>
  15. <div class="login">
  16. <div style="font-size: 25px; font-weight: bold;text-align: center;">
  17. 用户登陆
  18. </div>
  19. <form id='login_form' role="form" onsubmit = "return false" > <!--不进行跳转-->
  20. {% csrf_token %}
  21. <div class="form-group">
  22. <label for="username">用户名</label>
  23. {# <input type="text" class="form-control" placeholder="请输入用户名">#}
  24. {{ obj.username }}
  25. </div>
  26. <div class="form-group">
  27. <label for="password">密码</label>
  28. {# <input type="password" class="form-control" placeholder="请输入密码">#}
  29. {{ obj.password }}
  30. </div>
  31. <div class="form-group">
  32. <label for="password">验证码</label>
  33.  
  34. <div class="row">
  35. <div class="col-xs-7">
  36. <input type="text" class="form-control" placeholder="请输入验证码" name="check_code">
  37. </div>
  38. <div class="col-xs-5">
  39. <img id='changecheckcode' src="/check_code.html" onclick="changeCheckCode();"> <!--点击更换验证码-->
  40. </div>
  41. </div>
  42.  
  43. </div>
  44. <div class="checkbox">
  45. <label>
  46. <input type="checkbox" name="rmb" value=""> 一个月内自动登陆
  47. </label>
  48. <div class="right">
  49. <a href="/register.html" style="margin-right: 10px">注册</a>
  50. <a href="#">忘记密码?</a>
  51. </div>
  52. </div>
  53. <button type="submit" id="loginsubmit" class="btn btn-default">登 陆</button>
  54. <div class="error_message"></div>
  55. </form>
  56. </div>
  57. <script src="/static/js/jquery-1.12.4.js"></script>
  58. <script src="/static/js/account.js"></script>
  59. <script src="/static/js/account_login.js"></script>
  60. </body>
  61. </html>
  62.  
  63. function changeCheckCode(){
  64. var img = $('#changecheckcode')[0];
  65. img.src = img.src + '?'; //刷新验证码
  66. }
  67.  
  68. function ShowError(error) {
  69. $('.error_message').text(error)
  70. }
  71.  
  72. function EmptyError() {
  73. $('.error_message').text('')
  74. }
  75.  
  76. /**
  77. * Created by L on 2017/2/17.
  78. */
  79.  
  80. $('#loginsubmit').click(function () {
  81. EmptyError() ; //清空错误
  82. $.ajax({
  83. url:'/login.html',
  84. type:'POST',
  85. data:$('#login_form').serialize(),
  86. dataType:'JSON',
  87. success:function (data) {
  88. if(data['status']){
  89. location.href = '/'; //成功跳转
  90.  
  91. }else {
  92. var error_message = DateHandel(data);
  93. console.log(error_message)
  94. var error_message = '**' + error_message;
  95.  
  96. ShowError(error_message)
  97. }
  98. },error:function () {
  99.  
  100. }
  101. })
  102. });
  103.  
  104. function DateHandel(data) {
  105. var error = data['error'];
  106. if(error['username']){ //用户名格式输入错误
  107. var error_message = error['username'][0]
  108. }else {
  109. if(error['password']){ //密码格式输入错误
  110. var error_message = error['password'][0]
  111. }else {
  112. if(error['check_code']){ //验证码为空
  113. changeCheckCode();
  114. var error_message = error['check_code'][0]
  115. }else {
  116. if(error['__all__']){
  117. var error_message = error['__all__'][0]
  118. }
  119. }
  120. }
  121. }
  122. return error_message
  123. }

login.html

武sir的代码:

  1. from django.core.exceptions import ValidationError
  2. from django import forms as django_forms
  3. from django.forms import fields as django_fields
  4. from django.forms import widgets as django_widgets
  5.  
  6. from repository import models
  7.  
  8. from .base import BaseForm
  9.  
  10. class LoginForm(BaseForm, django_forms.Form):
  11. username = django_fields.CharField(
  12. min_length=6,
  13. max_length=20,
  14. error_messages={'required': '用户名不能为空.', 'min_length': "用户名长度不能小于6个字符", 'max_length': "用户名长度不能大于32个字符"}
  15. )
  16. password = django_fields.RegexField(
  17. '^(?=.*[0-9])(?=.*[a-zA-Z])(?=.*[!@#$\%\^\&\*\(\)])[0-9a-zA-Z!@#$\%\^\&\*\(\)]{8,32}$',
  18. min_length=12,
  19. max_length=32,
  20. error_messages={'required': '密码不能为空.',
  21. 'invalid': '密码必须包含数字,字母、特殊字符',
  22. 'min_length': "密码长度不能小于8个字符",
  23. 'max_length': "密码长度不能大于32个字符"}
  24. )
  25. rmb = django_fields.IntegerField(required=False)
  26.  
  27. check_code = django_fields.CharField(
  28. error_messages={'required': '验证码不能为空.'}
  29. )
  30.  
  31. def clean_check_code(self):
  32. if self.request.session.get('CheckCode').upper() != self.request.POST.get('check_code').upper():
  33. raise ValidationError(message='验证码错误', code='invalid')

from.py

  1. from io import BytesIO
  2. from django.shortcuts import HttpResponse
  3. from django.shortcuts import render
  4. from django.shortcuts import redirect
  5. from utils.check_code import create_validate_code
  6. from repository import models
  7. from ..form.accout import LoginForm
  8.  
  9. def check_code(request):
  10. """
  11. 验证码
  12. :param request:
  13. :return:
  14. """
  15. stream = BytesIO()
  16. img, code = create_validate_code()
  17. img.save(stream, 'PNG')
  18. request.session['CheckCode'] = code
  19. return HttpResponse(stream.getvalue())
  20.  
  21. def login(request):
  22. """
  23. 登陆
  24. :param request:
  25. :return:
  26. """
  27. if request.method == 'GET':
  28. return render(request, 'login.html')
  29. elif request.method == 'POST':
  30. result = {'status': False, 'message': None, 'data': None}
  31. form = LoginForm(request=request, data=request.POST)
  32. if form.is_valid():
  33. username = form.cleaned_data.get('username')
  34. password = form.cleaned_data.get('password')
  35. user_info = models.UserInfo.objects. \
  36. filter(username=username, password=password). \
  37. values('nid', 'nickname',
  38. 'username', 'email',
  39. 'avatar',
  40. 'blog__nid',
  41. 'blog__site').first()
  42.  
  43. if not user_info:
  44. # result['message'] = {'__all__': '用户名或密码错误'}
  45. result['message'] = '用户名或密码错误'
  46. else:
  47. result['status'] = True
  48. request.session['user_info'] = user_info
  49. if form.cleaned_data.get('rmb'):
  50. request.session.set_expiry(60 * 60 * 24 * 7)
  51. else:
  52. print(form.errors)
  53. if 'check_code' in form.errors:
  54. result['message'] = '验证码错误或者过期'
  55. else:
  56. result['message'] = '用户名或密码错误'
  57. return HttpResponse(json.dumps(result))

views.py

  1. <!DOCTYPE html>
  2. <html>
  3. <head lang="en">
  4. <meta charset="UTF-8">
  5. <title></title>
  6. <link rel="stylesheet" href="/static/plugins/bootstrap/css/bootstrap.css"/>
  7. <link rel="stylesheet" href="/static/plugins/font-awesome/css/font-awesome.css"/>
  8. <link rel="stylesheet" href="/static/css/edmure.css"/>
  9. <link rel="stylesheet" href="/static/css/commons.css"/>
  10. <link rel="stylesheet" href="/static/css/account.css"/>
  11. </head>
  12. <body>
  13. <div class="login">
  14. <div style="font-size: 25px; font-weight: bold;text-align: center;">
  15. 用户登陆
  16. </div>
  17. <form id="fm" method="POST" action="/login.html">
  18. {% csrf_token %}
  19. <div class="form-group">
  20. <label for="username">用户名</label>
  21. <input type="text" class="form-control" name="username" id="username" placeholder="请输入用户名">
  22. </div>
  23. <div class="form-group">
  24. <label for="password">密码</label>
  25. <input type="password" class="form-control" name="password" id="password" placeholder="请输入密码">
  26. </div>
  27. <div class="form-group">
  28. <label for="password">验证码</label>
  29.  
  30. <div class="row">
  31. <div class="col-xs-7">
  32. <input type="text" class="form-control" name="check_code" id="check_code" placeholder="请输入验证码">
  33. </div>
  34. <div class="col-xs-5">
  35. <img id="check_code_img" src="/check_code.html">
  36. </div>
  37. </div>
  38.  
  39. </div>
  40. <div class="checkbox">
  41. <label>
  42. <input type="checkbox" value="" name="rmb"> 一个月内自动登陆
  43. </label>
  44.  
  45. <div class="right">
  46. <a href="#">忘记密码?</a>
  47. </div>
  48. </div>
  49. <div class="row">
  50. <div class="col-xs-3">
  51. <a id="submit" class="btn btn-default">登 陆</a>
  52. </div>
  53. <div class="col-xs-9" style="padding-left: 0;">
  54. <div class="alert alert-danger hide">
  55. <span style="padding: 0 5px 0 5px;display: inline-block;font-size: 14px">
  56. <i class="fa fa-minus-circle" aria-hidden="true"></i>
  57. </span>
  58. <span id="error_msg" style="font-size: 12px;"></span>
  59. </div>
  60. </div>
  61. </div>
  62.  
  63. </form>
  64. <script src="/static/js/jquery-1.12.4.js"></script>
  65. <script type="text/javascript">
  66. $(function () {
  67. bindLogin();
  68. });
  69. function bindLogin() {
  70. $('#submit').click(function () {
  71. var $msg = $('#error_msg');
  72. $msg.parent().addClass('hide');
  73. $.ajax({
  74. url: '/login.html',
  75. type: 'POST',
  76. data: $('#fm').serialize(),
  77. dataType: 'JSON',
  78. success: function (arg) {
  79. if(arg.status){
  80. location.href = '/'
  81. }else{
  82. $msg.parent().removeClass('hide');
  83. $msg.text(arg.message);
  84. var img = $('#check_code_img')[0];
  85. img.src = img.src + '?';
  86. $('#password,#check_code').val('');
  87. }
  88.  
  89. }
  90. })
  91.  
  92. })
  93. }
  94. </script>
  95. </div>
  96. </body>
  97. </html>

login.html

区别:

①、前后端交互

  前后端交互这块,自己没有活学活用,上课时老师讲课时讲到直接把obj.errors传到前端,然后就固执的这么用了,导致前端js要写很多的if进行判断(我的错误提示很完善,从不能为空,到用户错误,武sir这方面写的比较简单);武sir是直接向前端传输一个错误的字符串(result['message'] = '用户名或密码错误'),前端直接打印即可,js无需多的判断,如果想加多点的错误提示,可以在后台上多做写判断亦可

②、form验证

  我from验证这一块,直接受到后台与前端传输数据为obj.errors影响,由于所有错误信息必须包含到obj.errors里面,导致用户密码验证必须写到form里面进行验证,获取用户名密码必须要把request传送到form,这个当时困住了好长时间,好算最后解决了;用户密码验证,武sir放到了处理函数里面,很机智

③、session信息

  把要存的信息,key、value分别对应进行存储;武sir直接存了一个‘use_info’字段,包含了所有的信息

 

 

用户注册

下面的代码都是整合后的代码了:

  1. class RegisterForm(forms.Form):
  2. username = fields.CharField(
  3. max_length=12,
  4. widget=widgets.Input(attrs={'class': 'form-control', 'placeholder': "请输入用户名"}),
  5. error_messages={'required': '用户名不能为空',
  6. 'max_length': '密码长度不能大于12位'}
  7. )
  8. email = fields.EmailField(
  9. widget=widgets.Input(attrs={'class': 'form-control', 'placeholder': "请输入邮箱"}),
  10. error_messages={'required': '邮箱不能为空', 'invalid':'邮箱格式不正确'}
  11. )
  12. password = fields.CharField(
  13. max_length=12,
  14. min_length=6,
  15. widget=widgets.PasswordInput(attrs={'class': 'form-control', 'placeholder': "请输入密码"}),
  16. error_messages={'required': '密码不能为空', 'min_length': '密码长度不能小于6位',
  17. 'max_length': '密码长度不能大于12位'}
  18. )
  19. confirm_password = fields.CharField(
  20. max_length=12,
  21. min_length=6,
  22. widget=widgets.PasswordInput(attrs={'class': 'form-control', 'placeholder': "请重新输入密码"}),
  23. error_messages={'required': '确认密码不能为空', 'min_length': '确认密码长度不能小于6位',
  24. 'max_length': '确认密码长度不能大于12位'}
  25. )
  26. check_code = fields.CharField(
  27. error_messages={'required': '验证码不能为空',}
  28. )
  29.  
  30. def clean_check_code(self):
  31. print(self.request.POST.get('check_code').upper())
  32. print(self.request.session['CheckCode'].upper())
  33. if self.request.POST.get('check_code').upper() == self.request.session['CheckCode'].upper():
  34. return self.cleaned_data['check_code']
  35. else:
  36. raise ValidationError(message='验证码错误')
  37.  
  38. def clean(self):
  39. confirm_password = self.cleaned_data.get('confirm_password')
  40. password = self.cleaned_data.get('password')
  41. if confirm_password == password:
  42. return self.cleaned_data
  43. else:
  44. raise ValidationError(message='两次密码输入的不一致')
  45.  
  46. def __init__(self, request, *args, **kwargs):
  47. self.request = request
  48. super().__init__(*args, **kwargs)

form.py

  1. from django.db.models import Q
  2. def register(request):
  3. """
  4. 注册
  5. """
  6. if request.method == 'GET':
  7. return render(request, 'register.html')
  8. elif request.method == 'POST':
  9. message = {'status': False, 'error': None}
  10. form = RegisterForm(request,request.POST)
  11. result = form.is_valid()
  12. if result: # 验证通过
  13. # 开始用户名、邮箱是否唯一
  14. username = request.POST.get('username')
  15. email = request.POST.get('email')
  16.  
  17. user_obj = models.UserInfo.objects.filter(Q(username=username)|Q(email=email)).first()
  18. if user_obj:
  19. message['error'] = '用户名或邮箱已经注册过'
  20. else:
  21. print(form.cleaned_data)
  22. form.cleaned_data.pop('confirm_password')
  23. form.cleaned_data.pop('check_code')
  24. # print(form.cleaned_data)
  25. models.UserInfo.objects.create(**form.cleaned_data)
  26. user_dict = models.UserInfo.objects.filter(username=username).values('nid','username','email').first()
  27. # print(type(user_dict))
  28. request.session['user_info'] = user_dict
  29. message['status'] = True
  30.  
  31. else:
  32. print(form.errors)
  33. if 'username' in form.errors: # 按照顺序进行验证,先用户名、邮箱、密码、确实密码、密码一致、验证码,用户名邮箱唯一
  34. message['error'] = form.errors['username']
  35. else:
  36. if 'email' in form.errors:
  37. message['error'] = form.errors['email']
  38. else:
  39. if 'password' in form.errors:
  40. message['error'] = form.errors['password']
  41. else:
  42. if 'confirm_password' in form.errors:
  43. message['error'] = form.errors['confirm_password']
  44. else:
  45. if '__all__' in form.errors:
  46. message['error'] = form.errors['__all__']
  47. else:
  48. if 'check_code' in form.errors:
  49. message['error'] = form.errors['check_code']
  50. # print(message)
  51. return HttpResponse(json.dumps(message))

views.py

  1. <!DOCTYPE html>
  2. <html>
  3. <head lang="en">
  4. <meta charset="UTF-8">
  5. <title></title>
  6. <link rel="stylesheet" href="/static/plugins/bootstrap/css/bootstrap.css"/>
  7. <link rel="stylesheet" href="/static/plugins/font-awesome/css/font-awesome.css"/>
  8. <link rel="stylesheet" href="/static/css/edmure.css"/>
  9. <link rel="stylesheet" href="/static/css/commons.css"/>
  10. <link rel="stylesheet" href="/static/css/account.css"/>
  11. <style>
  12.  
  13. </style>
  14. </head>
  15. <body>
  16. <div class="register">
  17. <div style="font-size: 25px; font-weight: bold;text-align: center;">
  18. 用户注册
  19. </div>
  20. <form role="form" id="reg_form">
  21. {% csrf_token %}
  22. <div class="form-group">
  23. <label for="username">用户名</label>
  24. <input name="username" class="form-control" placeholder="请输入用户名">
  25. </div>
  26. <div class="form-group">
  27. <label for="email">邮箱</label>
  28. <input name="email" class="form-control" placeholder="请输入邮箱">
  29. </div>
  30. <div class="form-group">
  31. <label for="password">密码</label>
  32. <input name="password" class="form-control" type="password" placeholder="请输入密码">
  33. </div>
  34. <div class="form-group">
  35. <label for="confirm_password">确认密码</label>
  36. <input name="confirm_password" class="form-control" type="password" placeholder="请重新输入密码">
  37. </div>
  38.  
  39. <div class="form-group">
  40. <label for="password">验证码</label>
  41.  
  42. <div class="row">
  43. <div class="col-xs-7">
  44. <input type="text" class="form-control" id="password" placeholder="请输入验证码" name="check_code">
  45. </div>
  46. <div class="col-xs-5">
  47. <img id='changecheckcode' src="/check_code.html" onclick="changeCheckCode();"> <!--点击更换验证码-->
  48. </div>
  49. </div>
  50. </div>
  51. <div class="row">
  52. <div class="col-xs-3">
  53. <a id="submit" class="btn btn-default">下一步</a>
  54. </div>
  55.  
  56. <div class="col-xs-9" style="padding-left: 0;">
  57. <div class="alert alert-danger hide">
  58. <span style="padding: 0 5px 0 5px;display: inline-block;font-size: 14px">
  59. <i class="fa fa-minus-circle" aria-hidden="true"></i>
  60. </span>
  61. <span id="error_msg" style="font-size: 12px;"></span>
  62. </div>
  63. </div>
  64. </div>
  65. {# <input type="button" id="regsubmit" class="btn btn-default" value="下一步"/>#}
  66. {# <div class="error_message"></div>#}
  67. </form>
  68. </div>
  69. <script src="/static/js/jquery-1.12.4.js"></script>
  70. <script src="/static/js/account.js"></script>
  71. <script src="/static/js/account_register.js"></script>
  72.  
  73. </body>
  74. </html>

register.html

代码有意思的地方:

form验证中__init__传入request参数

  1. class RegisterForm(forms.Form):
  2. def __init__(self, request, *args, **kwargs):
  3. self.request = request
  4. super().__init__(*args, **kwargs)
  5.  
  6. def register(request):
  7. """
  8. 注册
  9. """
  10. elif request.method == 'POST':
  11. message = {'status': False, 'error': None}
  12. form = RegisterForm(request,request.POST) # 传参

model检索Q或请求:

  1. from django.db.models import Q
  2. def register(request):
  3. user_obj = models.UserInfo.objects.filter(Q(username=username)|Q(email=email)).first()

所有的验证错误提示信息在后端处理:

  1. def register(request):
  2. else:
  3. print(form.errors)
  4. if 'username' in form.errors: # 按照顺序进行验证,先用户名、邮箱、密码、确实密码、密码一致、验证码,用户名邮箱唯一
  5. message['error'] = form.errors['username']
  6. else:
  7. if 'email' in form.errors:
  8. message['error'] = form.errors['email']
  9. else:
  10. if 'password' in form.errors:
  11. message['error'] = form.errors['password']
  12. else:
  13. if 'confirm_password' in form.errors:
  14. message['error'] = form.errors['confirm_password']
  15. else:
  16. if '__all__' in form.errors:
  17. message['error'] = form.errors['__all__']
  18. else:
  19. if 'check_code' in form.errors:
  20. message['error'] = form.errors['check_code']
  21. # print(message)
  22. return HttpResponse(json.dumps(message))

首页文章展示: 

  1. def index(request,*args,**kwargs):
  2. print('innnnidex')
  3. """
  4. 博客首页,展示全部博文
  5. :param request:
  6. :return:
  7. """
  8.  
  9. if kwargs:
  10. article_type_id = int(kwargs.get('article_type_id'))
  11. kwargs['article_type_id'] = article_type_id
  12. article_list = models.Article.objects.filter(article_type_id=article_type_id).prefetch_related('blog').order_by('-nid')
  13. else:
  14. article_list = models.Article.objects.all().prefetch_related('blog').order_by('-nid')
  15.  
  16. type_choices = models.Article.type_choices
  17.  
  18. return render(request, 'index.html', {'article_list': article_list,
  19. 'type_choices':type_choices,
  20. 'kwargs':kwargs})

views.py

  1. <!DOCTYPE html>
  2. <html>
  3. <head lang="en">
  4. <meta charset="UTF-8">
  5. <title></title>
  6. <link rel="stylesheet" href="/static/plugins/bootstrap/css/bootstrap.css"/>
  7. <link rel="stylesheet" href="/static/plugins/font-awesome/css/font-awesome.css"/>
  8. <link rel="stylesheet" href="/static/css/edmure.css"/>
  9. <link rel="stylesheet" href="/static/css/commons.css"/>
  10. <link rel="stylesheet" href="/static/css/row-avatar.css"/>
  11.  
  12. <script type="text/javascript" src="/static/js/jquery-1.12.4.js"></script>
  13. <script type="text/javascript" src="/static/plugins/bootstrap/js/bootstrap.js"></script>
  14. </head>
  15. <body>
  16. {% include 'include/header.html' %}
  17.  
  18. <div class="container">
  19. <div>
  20. <div class="col-md-8">
  21. <div class="article-list">
  22. {% for item in article_list %}
  23. <div class="article-item clearfix">
  24. <h3><a href="/{{ item.blog.site }}/{{ item.nid }}.html">{{ item.title }}</a>
  25. {# <small>{{ item.type_choices }}</small>#}
  26. <small>{{ item.article_type_id}}</small>
  27. </h3>
  28. <div class="clearfix">
  29. <a class="avatar left" href="#">
  30. <img src="/{{ item.blog.user.avatar }}">
  31. </a>
  32. {{ item.summary}}
  33. </div>
  34. <div class="footers">
  35. <a href="/{{ item.blog.site }}/index.html">
  36. <i class="fa fa-user-o" aria-hidden="true"></i>
  37. <span>{{ item.blog.user.username }}</span>
  38. </a>
  39. <span>发布于 {{ item.create_time|date:"Y-m-d H:i:s" }}</span>
  40. <a href="/{{ item.blog.site }}/{{ item.nid }}.html" class="ele">
  41. <i class="fa fa-commenting-o" aria-hidden="true"></i>
  42. <span>{{ item.read_count }}</span>
  43. </a>
  44. <a href="#" class="ele">
  45. <i class="fa fa-thumbs-o-up" aria-hidden="true"></i>
  46. <span>{{ item.comment_count }}</span>
  47. </a>
  48. </div>
  49.  
  50. </div>
  51. {% endfor %}
  52.  
  53. </div>
  54.  
  55. <div class="clearfix">
  56.  
  57. <ul class="pagination">
  58. <li><a href="#">&laquo;</a></li>
  59. <li><a href="#">1</a></li>
  60. <li><a href="#">2</a></li>
  61. <li><a href="#">3</a></li>
  62. <li><a href="#">4</a></li>
  63. <li><a href="#">5</a></li>
  64. <li><a href="#">&raquo;</a></li>
  65. </ul>
  66.  
  67. </div>
  68.  
  69. </div>
  70. <div class="col-md-4">
  71. <div class="panel panel-default hot-recommend">
  72. <div class="panel-heading">吐血推荐</div>
  73. <div class="panel-body">
  74. <ul class="list-unstyled">
  75. <li>Lorem ipsum dolor sit amet</li>
  76. <li>Consectetur adipiscing elit</li>
  77. <li>Integer molestie lorem at massa</li>
  78. <li>Facilisis in pretium nisl aliquet</li>
  79. <li>Nulla volutpat aliquam velit
  80. </li>
  81. <li>Faucibus porta lacus fringilla vel</li>
  82. <li>Aenean sit amet erat nunc</li>
  83. <li>Eget porttitor lorem</li>
  84. </ul>
  85. </div>
  86. </div>
  87. <div class="panel panel-default hot-comment">
  88. <div class="panel-heading">评论最多</div>
  89. <div class="panel-body">
  90. <ul class="list-unstyled">
  91. <li>Lorem ipsum dolor sit amet</li>
  92. <li>Consectetur adipiscing elit</li>
  93. <li>Integer molestie lorem at massa</li>
  94. <li>Facilisis in pretium nisl aliquet</li>
  95. <li>Nulla volutpat aliquam velit
  96. </li>
  97. <li>Faucibus porta lacus fringilla vel</li>
  98. <li>Aenean sit amet erat nunc</li>
  99. <li>Eget porttitor lorem</li>
  100. </ul>
  101. </div>
  102. </div>
  103.  
  104. </div>
  105. </div>
  106. </div>
  107.  
  108. </body>
  109. </html>

index.html

关键的几段代码:

前端对时间进行处理:

  1. <span>发布于 {{ item.create_time|date:"Y-m-d H:i:s" }}</span>

 

后台个人信息修改

  1. @check_login
  2. def base_info(request):
  3. """博主个人信息"""
  4. if request.method == 'GET':
  5. blogTheme = [
  6. {'id': '', 'name': '默认主题'},
  7. {'id': '', 'name': '黑不溜秋'},
  8. {'id': '', 'name': '乌七八啦'},
  9. {'id': '', 'name': '红色火焰'},
  10. {'id': '', 'name': '哈哈哈嘿哈'},
  11. ]
  12. print(request.session['user_info'])
  13. return render(request, 'backend_base_info.html',{'blogTheme':blogTheme})
  14.  
  15. elif request.method == 'POST':
  16. message = {'status':False,'error':None}
  17.  
  18. site = request.session['user_info'].get('blog__site') # session中查找博客地址
  19.  
  20. if site: # 博客地址之前已经创建,需要更新内容
  21. # print('------------',request.POST)
  22. nickname = request.POST.get('nickname')
  23. theme = request.POST.get('theme')
  24. title = request.POST.get('title')
  25.  
  26. models.Blog.objects.filter(site=site).update(theme=theme,title=title)
  27. models.UserInfo.objects.filter(nid=request.session['user_info']['nid']).update(nickname=nickname)
  28.  
  29. user_info_dict = request.session['user_info']
  30. user_info_dict['nickname']=nickname
  31. user_info_dict['blog__theme']=theme
  32. user_info_dict['blog__title']=title
  33. request.session['user_info']=request.session['user_info']
  34. print(request.session['user_info'])
  35.  
  36. message['status'] = True
  37.  
  38. else:
  39. site = request.POST.get('site')
  40. if site: # 博客地址提交
  41. blog_obj = models.Blog.objects.filter(site=site).first()
  42. if blog_obj:
  43. message['error'] = '博客地址已被占用'
  44. else:
  45. nickname = request.POST.get('nickname')
  46. theme = request.POST.get('theme')
  47. title = request.POST.get('title')
  48.  
  49. models.Blog.objects.create(site=site,
  50. theme=theme,
  51. title=title,
  52. user_id=request.session['user_info']['nid'])
  53. models.UserInfo.objects.filter(nid=request.session['user_info']['nid']).update(nickname=nickname)
  54. user_info_dict = request.session['user_info']
  55. user_info_dict['nickname'] = nickname
  56. user_info_dict['blog__theme'] = theme
  57. user_info_dict['blog__title'] = title
  58. user_info_dict['blog__site'] = site
  59. request.session['user_info'] = request.session['user_info']
  60. message['status'] = True
  61. else:
  62. message['error'] = '博客地址不能为空'
  63.  
  64. return HttpResponse(json.dumps(message))
  65.  
  66. @check_login
  67. def upload_avatar(request): # 更新头像
  68. message = {'status': False, 'data': None}
  69. if request.method == 'POST':
  70. files = request.FILES.get('avatar_img')
  71. if files: # 省略判断文件格式的过程
  72. img_dir = 'static/imgs/savatar/%s'%(request.session['user_info']['username'])
  73. if not os.path.exists(img_dir):
  74. os.makedirs(img_dir)
  75. img_path = os.path.join(img_dir,'avatar.png')
  76. print(img_path)
  77.  
  78. with open(img_path,'wb') as f:
  79. for item in files.chunks():
  80. f.write(item)
  81.  
  82. models.UserInfo.objects.filter(nid=request.session['user_info']['nid']).update(avatar=img_path)
  83. user_info_dict = request.session['user_info']
  84. user_info_dict['avatar'] = img_path
  85. request.session['user_info'] = user_info_dict
  86. print(request.session['user_info'])
  87. message['data'] = img_path
  88. message['status'] = True
  89. print(message)
  90. return HttpResponse(json.dumps(message))

view.py

  1. {% extends 'backend_layout.html' %}
  2. {% block css %}
  3. <style>
  4. .form-horizontal .control-label {
  5. padding-top: 7px;
  6. margin-bottom: 0;
  7. text-align: right;
  8. }
  9. .avatar-container{
  10. height: 200px;
  11. width: 200px;
  12. padding: 2px;
  13. border: 1px solid #dddddd;
  14. position: relative;
  15. }
  16. .avatar-container img{
  17. height: 198px;
  18. width: 198px;
  19. border: 0;
  20. overflow: hidden;
  21. }
  22. .avatar-container .text{
  23. text-align: center;
  24. }
  25. .avatar-container .img-file{
  26. top:0;
  27. left: 0;
  28. right: 0;
  29. bottom: 0;
  30. opacity: 0;
  31. position: absolute;
  32. z-index: 102;
  33. }
  34. </style>
  35. {% endblock %}
  36. {% block conent %}
  37. <ol class="breadcrumb">
  38. <li><a href="#">用户管理</a></li>
  39. <li class="active">用户信息</li>
  40. </ol>
  41. <div>
  42.  
  43. <div class="row" style="position: relative;">
  44. <form class="form-horizontal" id="baseinfo_form">
  45. {% csrf_token %}
  46. <div class="col-xs-12">
  47. <div class="form-group">
  48. <label class="col-xs-2 control-label">用户名</label>
  49.  
  50. <div class="col-xs-5">
  51. <p class="form-control-static">{{ request.session.user_info.username }}</p>
  52. </div>
  53. </div>
  54. <div class="form-group">
  55. <label class="col-xs-2 control-label">邮箱</label>
  56.  
  57. <div class="col-xs-5">
  58. <p class="form-control-static">{{ request.session.user_info.email }}</p>
  59. </div>
  60. </div>
  61. <div class="form-group">
  62. <label for="nickname" class="col-xs-2 control-label">昵称</label>
  63.  
  64. <div class="col-xs-5">
  65. {% if request.session.user_info.nickname %}
  66. <input type="text" class="form-control" name="nickname" value="{{ request.session.user_info.nickname }}">
  67.  
  68. {% else %}
  69. <input type="text" class="form-control" name="nickname" placeholder="请输入昵称">
  70. {% endif %}
  71. </div>
  72. </div>
  73. <div class="form-group">
  74. <label for="blogUrl" class="col-xs-2 control-label">博客地址</label>
  75.  
  76. <div class="col-xs-5">
  77. {% if request.session.user_info.blog__site %}
  78. <p class="form-control-static">{{ request.session.user_info.blog__site }}</p>
  79. {# <p class="form-control" readonly>{{ request.session.user_info.blog__site }}</p>#}
  80. {% else %}
  81. <input type="text" class="form-control" id="blogUrl" name="site"
  82. placeholder="如:wupeiqi,则个人博客为http://www.xxx.com/wupeiqi.html">
  83. {% endif %}
  84. </div>
  85. </div>
  86. <div class="form-group">
  87. <label for="blogTheme" class="col-xs-2 control-label">博客主题</label>
  88.  
  89. <div class="col-xs-5">
  90. <select id="blogTheme" class="form-control" name="theme" >
  91. {% for item in blogTheme %}
  92. {% if item.id == request.session.user_info.blog__theme %}
  93. <option value="{{ item.id }}" selected="selected">{{ item.name }}</option>
  94. {% else %}
  95. <option value="{{ item.id }}">{{ item.name }}</option>
  96. {% endif%}
  97. {% endfor %}
  98. </select>
  99. </div>
  100. </div>
  101. <div class="form-group">
  102. <label for="blogTitle" class="col-xs-2 control-label">博客标题内容</label>
  103.  
  104. <div class="col-xs-8">
  105. {% if request.session.user_info.blog__title %}
  106. <textarea id="blogTitle" style="min-height: 100px" class="form-control"
  107. name="title">{{ request.session.user_info.blog__title }}</textarea>
  108. {% else %}
  109. <textarea id="blogTitle" style="min-height: 100px" class="form-control"
  110. placeholder="来一杯鸡汤..." name="title"></textarea>
  111. {% endif %}
  112. </div>
  113. </div>
  114.  
  115. <div class="form-group">
  116. <div class="col-xs-offset-2 col-xs-10">
  117. <button type="button" id='baseinfo_save' class="btn btn-primary">保 存</button>
  118. <div class="error_message"></div>
  119. </div>
  120. </div>
  121.  
  122. </div>
  123. </form>
  124. <div style="position: absolute;" class="col-xs-offset-7 col-xs-5">
  125. <div class="avatar-container">
  126. <iframe style="display: none;" id="upload_iframe" name="upload_iframe"></iframe>
  127. <form method="POST" action="/backend/upload-avatar.html" enctype="multipart/form-data"
  128. target="upload_iframe" id="form1">
  129. {% csrf_token %}
  130. {% if request.session.user_info.avatar %}
  131. <img id='previewImg' origin="/static/imgs/avatar/default.png" src='/{{ request.session.user_info.avatar }}'
  132. style="border-radius: 50%;" >
  133. {% else %}
  134. <img id='previewImg' origin="/static/imgs/avatar/default.png" src="/static/imgs/avatar/default.png"
  135. style="border-radius: 50%;width: 198px;">
  136. {% endif %}
  137. <div class="text">点击图片更换(<a href="#">撤销</a>)</div>
  138. <input id="avatarImg" name="avatar_img" type="file" class="img-file" onchange="ChangeAvatar();"/>
  139. </form>
  140. </div>
  141. </div>
  142. </div>
  143. </div>
  144. <script src="/static/js/jquery-1.12.4.js"></script>
  145. <script>
  146. $('#baseinfo_save').click(function () {
  147. $.ajax({
  148. url:'/backend/base-info.html',
  149. type:'POST',
  150. data:$('#baseinfo_form').serialize(),
  151. dataType:'JSON',
  152. success:function (data) {
  153.  
  154. if(data['status']){
  155. console.log('ok');
  156. location.reload()
  157. }else {
  158. var error_message ='**' + data['error'];
  159. ShowError(error_message)
  160. }
  161. },
  162. error:function () {
  163. }
  164. })
  165. });
  166.  
  167. function ShowError(error) {
  168. $('.error_message').text(error)
  169. }
  170.  
  171. function ChangeAvatar() {
  172. {# $('#avatarImg').change(function () {#}
  173. {# $(this).submit();#}
  174. $('#form1').submit();
  175. $('#upload_iframe').load(function () {
  176. var iframeContents = this.contentWindow.document.body.innerText;
  177. iframeContents = JSON.parse(iframeContents);
  178. console.log(iframeContents);
  179. if (iframeContents.status) {
  180. $('#previewImg').attr('src', '/' + iframeContents.data +'?');
  181. }
  182. })
  183. }
  184. </script>
  185. {% endblock %}
  186.  
  187. {% block js %}
  188.  
  189. {% endblock %}

backend_base_info.html

里面包含了图片的点击上传,更新 非常重要

文章列表+组合检索

  1. @check_login
  2. def article(request,*args, **kwargs):
  3. """
  4. 博主个人文章管理
  5. """
  6. blog_id = request.session['user_info']['blog__nid']
  7. condition = {}
  8. for k, v in kwargs.items():
  9. if v == '':
  10. pass
  11. else:
  12. condition[k] = v
  13. condition['blog_id'] = blog_id
  14. data_count = models.Article.objects.filter(**condition).count()
  15. page = Pagination(request.GET.get('p', 1), data_count)
  16. result = models.Article.objects.filter(**condition).order_by('-nid').only('nid', 'title','blog').select_related('blog')[page.start:page.end]
  17. page_str = page.page_str(reverse('article', kwargs=kwargs))
  18. category_list = models.Category.objects.filter(blog_id=blog_id).values('nid', 'title')
  19. type_list = map(lambda item: {'nid': item[0], 'title': item[1]}, models.Article.type_choices)
  20. kwargs['p'] = page.current_page
  21. return render(request,
  22. 'backend_article.html',
  23. {'result': result,
  24. 'page_str': page_str,
  25. 'category_list': category_list,
  26. 'type_list': type_list,
  27. 'arg_dict': kwargs,
  28. 'data_count': data_count
  29. }
  30. )

views.py

  1. {% extends 'backend_layout.html' %}
  2. {% load search %}
  3. {% block css %}
  4. <style>
  5. .conditions a{
  6. display: inline-block;
  7. padding: 2px 5px;
  8. margin-left: 5px;
  9. }
  10. .conditions a.active{
  11. background-color: #b35215;
  12. color: #ffffff;
  13. }
  14. </style>
  15. {% endblock %}
  16. {% block conent %}
  17. <ol class="breadcrumb" style="margin-bottom: 0;">
  18. <li><a href="#">文章管理</a></li>
  19. <li class="active">文章列表</li>
  20. </ol>
  21. <div>
  22.  
  23. <div style="border: 1px dashed #dddddd;padding: 8px;border-left: 3px solid #337ab7;">
  24. <i class="fa fa-search" aria-hidden="true"></i> 搜索条件
  25. </div>
  26. <div style="padding: 10px">
  27. <div class="conditions row clearfix" style="margin: 0;padding: 8px 0;">
  28. <div class="col-xs-1" style="text-align: right">
  29. {% category_all arg_dict %}
  30. </div>
  31. <div class="col-xs-11">
  32. {% category_combine category_list arg_dict %}
  33. </div>
  34. </div>
  35. <div class="conditions row clearfix" style="margin: 0;padding: 8px 0;">
  36. <div class="col-xs-1" style="text-align: right">
  37. {% article_type_all arg_dict %}
  38. </div>
  39. <div class="col-xs-11">
  40. {% article_type_combine type_list arg_dict %}
  41. </div>
  42. </div>
  43. </div>
  44. <div class="clearfix"
  45. style="height: 36px;line-height: 35px;padding: 0 15px;border-top: 1px solid #dddddd;background-color: #f1f0f0">
  46. <i class="fa fa-table" aria-hidden="true"></i>
  47. 搜索文章({{ data_count }}篇)
  48. <a target="_blank" href="/backend/add-article.html" class="right"
  49. style="display: inline-block;padding:0 10px;background-color: #428bca;color: #ffffff;">
  50. <i class="fa fa-plus-circle" aria-hidden="true"></i>
  51. 创建新文章
  52. </a>
  53. </div>
  54.  
  55. <table class="table table-bordered">
  56. <thead>
  57. <tr>
  58. <th>文章标题</th>
  59. <th>操作</th>
  60. </tr>
  61. </thead>
  62. <tbody>
  63. {% for row in result %}
  64. <tr nid="{{ row.nid }}">
  65. <td><a href="/{{ row.blog.site }}/{{ row.nid }}.html">{{ row.title }}</a></td>
  66. <td>
  67. <a class="btn btn-danger btn-xs" href="/backend/del-article-{{ row.nid }}.html">
  68. <i class="fa fa-times" aria-hidden="true"></i>
  69. 删除
  70. </a>
  71. |
  72. <a class="btn btn-primary btn-xs" href="/backend/edit-article-{{ row.nid }}.html">
  73. <i class="fa fa-pencil-square-o" aria-hidden="true"></i>
  74. 编辑
  75. </a>
  76. </td>
  77. </tr>
  78. {% endfor %}
  79.  
  80. </tbody>
  81. </table>
  82. <div class="clearfix">
  83. <ul class="pagination right" style="margin-top: 0">
  84. {{ page_str }}
  85. </ul>
  86. </div>
  87. </div>
  88.  
  89. {% endblock %}
  90.  
  91. {% block js %}
  92.  
  93. {% endblock %}

backend_article.html

组合搜索-跳转

套路之新建文章和编辑文章

  1. @check_login
  2. def add_article(request):
  3. """
  4. 添加文章
  5. """
  6. if request.method == 'GET':
  7. form = ArticleForm(request=request)
  8. return render(request, 'backend_add_article.html', {'form': form})
  9. elif request.method == 'POST':
  10. form = ArticleForm(request=request, data=request.POST) # 传参request 当然也可以用之前自己的方式进行上传
  11. if form.is_valid():
  12. with transaction.atomic(): # 固定用法,下面操作多表进行添加数据,如果有一个数据添加数据,那么其他刚刚添加的数据进行回滚
  13. #dict格式cleaned_data 包含的字段{'tags' 'article_type' 'category_id' 'summary' 'title' 'content'}
  14. print(form.cleaned_data)
  15. tags = form.cleaned_data.pop('tags') # 移出 tags需要在第三张Article2Tag表上手动添加
  16. content = form.cleaned_data.pop('content') # 移出 content需要在表ArticleDetail上手动添加、关联Article
  17. content = XSSFilter().process(content) # 对content进行数据过滤 过滤到script等标签
  18. form.cleaned_data['blog_id'] = request.session['user_info']['blog__nid'] # 把博客id添加到cleande_data中
  19.  
  20. # dict格式cleaned_data 包含的字段{ 'blog_id' 'article_type' 'category_id' 'summary' 'title' }
  21. obj = models.Article.objects.create(**form.cleaned_data) # Article表添加cleaned_data里的内容
  22. # ****直接关联obj
  23. models.ArticleDetail.objects.create(content=content, article=obj) # ArticleDetail添加数据、关联
  24.  
  25. # 第一种写法
  26. # tag_list = [] # 准备添加第三张Article2Tag表
  27. # for tag_id in tags: # tags ['1'] 是个列表
  28. # tag_id = int(tag_id)
  29. # tag_list.append(models.Article2Tag(article_id=obj.nid, tag_id=tag_id))
  30. # # models.Article2Tag(article_id=obj.nid, tag_id=tag_id) 创建Article2Tag object对象
  31. # print(tag_list)
  32. # models.Article2Tag.objects.bulk_create(tag_list) # 直接添加对象 类型[obj1,obj2]
  33.  
  34. # 第二种写法
  35. for tag_id in tags: # tags ['1'] 是个列表
  36. tag_id = int(tag_id)
  37. models.Article2Tag.objects.create(article_id=obj.nid,tag_id=tag_id)
  38.  
  39. return redirect('/backend/article-0-0.html')
  40. else:
  41. return render(request, 'backend_add_article.html', {'form': form})
  42. else:
  43. return redirect('/')
  44.  
  45. def edit_article(request,nid):
  46. """
  47. 编辑文章
  48. :param request:
  49. :return:
  50. """
  51. print('编辑')
  52. blog_id = request.session['user_info']['blog__nid']
  53. if request.method == 'GET':
  54. obj = models.Article.objects.filter(nid=nid, blog_id=blog_id).first()
  55. if not obj:
  56. return render(request, 'backend_no_article.html')
  57. tags = obj.tags.values_list('nid')
  58. if tags:
  59. tags = list(zip(*tags))[0]
  60. init_dict = {
  61. 'nid': obj.nid,
  62. 'title': obj.title,
  63. 'summary': obj.summary,
  64. 'category_id': obj.category_id,
  65. 'article_type_id': obj.article_type_id,
  66. 'content': obj.articledetail.content,
  67. 'tags': tags
  68. }
  69. form = ArticleForm(request=request, data=init_dict)
  70. return render(request, 'backend_edit_article.html', {'form': form, 'nid': nid})
  71. elif request.method == 'POST':
  72. form = ArticleForm(request=request, data=request.POST)
  73. if form.is_valid():
  74. obj = models.Article.objects.filter(nid=nid, blog_id=blog_id).first()
  75. if not obj:
  76. return render(request, 'backend_no_article.html')
  77. with transaction.atomic():
  78. content = form.cleaned_data.pop('content')
  79. content = XSSFilter().process(content)
  80. tags = form.cleaned_data.pop('tags')
  81. models.Article.objects.filter(nid=obj.nid).update(**form.cleaned_data)
  82. models.ArticleDetail.objects.filter(article=obj).update(content=content)
  83. models.Article2Tag.objects.filter(article=obj).delete()
  84. tag_list = []
  85. for tag_id in tags:
  86. tag_id = int(tag_id)
  87. tag_list.append(models.Article2Tag(article_id=obj.nid, tag_id=tag_id))
  88. models.Article2Tag.objects.bulk_create(tag_list)
  89. return redirect('/backend/article-0-0.html')
  90. else:
  91. return render(request, 'backend_edit_article.html', {'form': form, 'nid': nid})

views.py

  1. {% extends 'backend_layout.html' %}
  2.  
  3. {% block css %}
  4. <link rel="stylesheet" href="/static/plugins/kindeditor/themes/default/default.css"/>
  5. <style>
  6. .kind-content {
  7. width: 100%;
  8. min-height: 500px;
  9. }
  10. </style>
  11. {% endblock %}
  12.  
  13. {% block conent %}
  14. <ol class="breadcrumb" style="margin-bottom: 0;">
  15. <li><a href="#">文章管理</a></li>
  16. <li class="active">添加文章</li>
  17. </ol>
  18. <div style="padding: 5px 8px;">
  19. <form method="POST" action="/backend/add-article.html" novalidate>
  20. {% csrf_token %}
  21. <div class="form-group">
  22. <label for="{{ form.title.id_for_label }}">标题 <span>{{ form.title.errors.0 }}</span></label>
  23. {{ form.title }}
  24. </div>
  25. <div class="form-group">
  26. <label for="summary">简介 <span>{{ form.summary.errors.0 }}</span></label>
  27. {{ form.summary }}
  28. </div>
  29. <div class="form-group">
  30. <label for="content">内容 <span>{{ form.content.errors.0 }}</span></label>
  31. {{ form.content }}
  32. </div>
  33. <div class="form-group">
  34. <label>类型 <span>{{ form.article_type.errors.0 }}</span></label>
  35.  
  36. <div>
  37. {{ form.article_type_id }}
  38. </div>
  39.  
  40. </div>
  41. <div class="form-group">
  42. <label>分类 <span>{{ form.category_id.errors.0 }}</span></label>
  43.  
  44. <div>
  45. {{ form.category_id }}
  46. </div>
  47. </div>
  48. <div class="form-group">
  49. <label>标签 <span>{{ form.tags.errors.0 }}</span></label>
  50.  
  51. <div>
  52. {{ form.tags }}
  53. </div>
  54. </div>
  55. <div class="form-group">
  56. <input type="submit" class="btn btn-primary" value="保 存">
  57. </div>
  58. </form>
  59. </div>
  60.  
  61. {% endblock %}
  62.  
  63. {% block js %}
  64. <script charset="utf-8" src="/static/plugins/kindeditor/kindeditor-min.js"></script>
  65. <script charset="utf-8" src="/static/plugins/kindeditor/lang/zh_CN.js"></script>
  66. <script>
  67. KindEditor.ready(function (K) {
  68. var editor = K.create('textarea[name="content"]', {
  69. resizeType: 1
  70. });
  71. });
  72. </script>
  73. {% endblock %}

backend_article.html

  1. {% extends 'backend_layout.html' %}
  2.  
  3. {% block css %}
  4. <link rel="stylesheet" href="/static/plugins/kindeditor/themes/default/default.css"/>
  5. <style>
  6. .kind-content {
  7. width: 100%;
  8. min-height: 500px;
  9. }
  10. </style>
  11. {% endblock %}
  12.  
  13. {% block conent %}
  14. <ol class="breadcrumb" style="margin-bottom: 0;">
  15. <li><a href="#">文章管理</a></li>
  16. <li class="active">修改文章</li>
  17. </ol>
  18. <div style="padding: 5px 8px;">
  19. <form method="POST" action="/backend/edit-article-{{ nid }}.html">
  20. {% csrf_token %}
  21. <div class="form-group">
  22. <label for="{{ form.title.id_for_label }}">标题 <span>{{ form.title.errors.0 }}</span></label>
  23. {{ form.title }}
  24. </div>
  25. <div class="form-group">
  26. <label for="summary">简介 <span>{{ form.summary.errors.0 }}</span></label>
  27. {{ form.summary }}
  28. </div>
  29. <div class="form-group">
  30. <label for="content">内容 <span>{{ form.content.errors.0 }}</span></label>
  31. {{ form.content }}
  32. </div>
  33. <div class="form-group">
  34. <label>类型 <span>{{ form.article_type.errors.0 }}</span></label>
  35.  
  36. <div>
  37. {{ form.article_type_id }}
  38. </div>
  39.  
  40. </div>
  41. <div class="form-group">
  42. <label>分类 <span>{{ form.category_id.errors.0 }}</span></label>
  43.  
  44. <div>
  45. {{ form.category_id }}
  46. </div>
  47. </div>
  48. <div class="form-group">
  49. <label>标签 <span>{{ form.tags.errors.0 }}</span></label>
  50.  
  51. <div>
  52. {{ form.tags }}
  53. </div>
  54. </div>
  55. <div class="form-group">
  56. <input type="submit" class="btn btn-primary" value="保 存">
  57. </div>
  58. </form>
  59. </div>
  60.  
  61. {% endblock %}
  62.  
  63. {% block js %}
  64. <script charset="utf-8" src="/static/plugins/kindeditor/kindeditor-min.js"></script>
  65. <script charset="utf-8" src="/static/plugins/kindeditor/lang/zh_CN.js"></script>
  66. <script>
  67. KindEditor.ready(function (K) {
  68. var editor = K.create('textarea[name="content"]', {
  69. resizeType: 1
  70. });
  71. });
  72. </script>
  73. {% endblock %}

backend_edit_article.html

最重要的是生成编辑框:

  1. {% block js %}
  2. <script charset="utf-8" src="/static/plugins/kindeditor/kindeditor-min.js"></script>
  3. <script charset="utf-8" src="/static/plugins/kindeditor/lang/zh_CN.js"></script>
  4. <script>
  5. KindEditor.ready(function (K) {
  6. var editor = K.create('textarea[name="content"]', {
  7. resizeType: 1
  8. });
  9. });
  10. </script>
  11. {% endblock %}

显示具体的文章页

  1. from django.utils.safestring import mark_safe
  2. def detail(request, site, nid):
  3. """
  4. 博文详细页
  5. :param request: http://127.0.0.1:8000/lzl/6.html
  6. :param site: 博客地址名
  7. :param nid: 文章ID
  8. :return:
  9. """
  10. # print(site,nid)
  11. blog_obj = models.Blog.objects.filter(site = site).prefetch_related('user').first() # 当前用户对应的博客对象
  12. user_obj = blog_obj.user
  13. # print(user_obj)
  14. article_obj = models.Article.objects.filter(nid=nid,blog=blog_obj).first() # 当前访问的文章对象
  15. content_obj = models.Comment.objects.filter(article=article_obj)
  16.  
  17. if article_obj:
  18. detail_obj = models.ArticleDetail.objects.filter(article=article_obj).first() # 访问文章的内容
  19. content = mark_safe(detail_obj.content) # 标记安全
  20. return render(request, 'home_detail.html',{'article_obj':article_obj,
  21. 'content':content,
  22. 'user_obj':user_obj,
  23. 'blog_obj':blog_obj,
  24. 'content_obj':content_obj})
  25. else:
  26.  
  27. return HttpResponse('文章不存在')
  28.  
  29. import json
  30. @check_login
  31. def update_comment(request):
  32. data = {'status':True,'message':None}
  33. user_id = request.session['user_info']['nid']
  34. print(user_id)
  35. if request.method == 'POST':
  36. print(request.POST)
  37. content = request.POST.get('content')
  38. article_id = request.POST.get('article_id')
  39. reply_id = request.POST.get('reply_id')
  40. nickname, new_content = content_handle(content)
  41.  
  42. if reply_id:
  43. comment_obj = models.Comment.objects.filter(article_id=article_id,nid=reply_id).first()
  44. models.Comment.objects.create(user_id=user_id, content=new_content, article_id=article_id,reply=comment_obj)
  45. else:
  46. models.Comment.objects.create(user_id=user_id, content=content, article_id=article_id)
  47. return HttpResponse(json.dumps(data))
  48.  
  49. import re
  50. def content_handle(content): #对评论内容进行处理
  51. obj = re.match('@.+\s', content)
  52. if obj:
  53. print(obj.group())
  54. nickname = re.sub('@', '', obj.group()).strip() # 用户名
  55. print(nickname)
  56. new_content = content.split(nickname)[1].strip() # 评论内容
  57. print(new_content)
  58. else:
  59. nickname = None
  60. new_content = content
  61. return nickname,new_content

views.py

  1. {% extends 'home_layout.html' %}
  2.  
  3. {% block css %}
  4. <link rel="stylesheet" href="/static/plugins/kindeditor/themes/default/default.css"/>
  5. {% endblock %}
  6.  
  7. {% block content %}
  8. <div class="art-title">
  9. <a>{{ article_obj.title }}</a>
  10. </div>
  11. <div class="art-content">
  12. {{ content }}
  13. </div>
  14. <div class="art-recommend clearfix">
  15. <div class="recommend">
  16. <a href="#" class="up"
  17. style="margin: 5px 10px;display: inline-block;padding: 5px 15px;border: 1px solid #dddddd;text-align: center;">
  18. <i class="fa fa-thumbs-o-up fa-3" aria-hidden="true" style="font-size: 25px"></i>
  19.  
  20. <div>0</div>
  21. </a>
  22. <a href="#" class="down"
  23. style="margin: 5px 30px 5px 10px;display: inline-block;padding: 5px 15px;border: 1px solid #dddddd;text-align: center;">
  24. <i class="fa fa-thumbs-o-down fa-3" aria-hidden="true" style="font-size: 25px"></i>
  25.  
  26. <div>0</div>
  27. </a>
  28. </div>
  29. </div>
  30. <div class="art-tips clearfix">
  31. <div class="tips">
  32. <span class="ctime">{{ article_obj.create_time }}</span>
  33. <a class="author">{{ user_obj.nickname }}</a>
  34. <span class="comment-count">评论(0)</span>
  35. <span class="read-count">阅读(0)</span>
  36. </div>
  37. </div>
  38. <div id="AllanboltSignature">
  39. <div style="border-bottom: #e0e0e0 1px dashed; border-left: #e0e0e0 1px dashed; padding: 10px; font-family: 微软雅黑; font-size: 11px; border-top: #e0e0e0 1px dashed; border-right: #e0e0e0 1px dashed; "
  40. id="PSignature">
  41. <div style="float:left;width:70px;">
  42. <img src="/static/imgs/o_Warning.png" style="width:65px;height:65px">
  43. </div>
  44. <div style="float:left;padding-top:10px;">
  45.  
  46. <div style="padding: 1px">作者:<a href="#" target="_blank">{{ user_obj.nickname }}</a></div>
  47. <div style="padding: 1px">出处:<a href="#" target="_blank">http://http://127.0.0.1:8000/{{ blog_obj.site }}/</a>
  48. </div>
  49. <div style="padding: 1px">本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接</div>
  50. </div>
  51. <div style="clear:both;"></div>
  52. </div>
  53. </div>
  54. <div class="art-comment">
  55. <div class="comment-title">
  56. 评论列表
  57. </div>
  58. <div class="comment-list">
  59. {% for item in content_obj %}
  60. <div class="comment-item">
  61. <div class="reply-title clearfix">
  62. <div class="user-info">
  63. <span style="color: #399ab2;">#{{ forloop.counter }}</span>
  64. <span>{{ item.create_time }}</span>
  65. <span id="nickname"style="color: #399ab2;"> {{ item.user.nickname }}</span>
  66. </div>
  67. <div class="reply">
  68. <a nid="{{ item.nid }}" onclick="Reply(this);">回复</a>
  69. </div>
  70. </div>
  71. <div class="reply-body" style="font-size: 12px;color:#888">
  72. {% if item.reply_id %}
  73. <div class="reply-user">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@{{ item.reply.user.nickname }}</div>
  74. {% endif %}
  75. <div class="content">
  76. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{{ item.content }}
  77. </div>
  78. <div style="margin-top: 30px"> </div>
  79. </div>
  80. </div>
  81. {% endfor %}
  82. </div>
  83. <div class="comment-list-pager">
  84. <ul class="pagination">
  85. <li><a href="#">&laquo;</a></li>
  86. <li><a href="#">1</a></li>
  87. <li><a href="#">2</a></li>
  88. <li><a href="#">3</a></li>
  89. <li><a href="#">4</a></li>
  90. <li><a href="#">5</a></li>
  91. <li><a href="#">&raquo;</a></li>
  92. </ul>
  93. </div>
  94. <div class="comment-area">
  95. <div class="replay-comment-user"></div>
  96. <div class="reply-area" style="position: relative;">
  97. {% if not request.session.user_info %}
  98. <div style="text-align:center;line-height:200px;position: absolute;top:0;left:0;right:0;bottom: 0;background-color: rgba(255,255,255,.6)">
  99. 您需要登录后才可以回帖 <a href="/login.html">登录</a> | <a href="/register.html">立即注册</a>
  100. </div>
  101. {% endif %}
  102. <textarea name="content" style="width: 100%;height:200px;visibility:hidden;"></textarea>
  103. </div>
  104. <div class="reply-btn">
  105. <span><span>21</span>/255字</span>
  106. <a onclick="CommentSub();">发表回复</a>
  107. <div id="reply_id"></div>
  108. </div>
  109. </div>
  110. </div>
  111. {% endblock %}
  112.  
  113. {% block js %}
  114. <script charset="utf-8" src="/static/plugins/kindeditor/kindeditor-min.js"></script>
  115. <script charset="utf-8" src="/static/plugins/kindeditor/lang/zh_CN.js"></script>
  116. <script src="/static/js/jquery.cookie.js"></script>
  117. <script>
  118. var editor;
  119. KindEditor.ready(function (K) {
  120. editor = K.create('textarea[name="content"]', {
  121. resizeType: 1,
  122. allowPreviewEmoticons: false,
  123. allowImageUpload: false,
  124. items: [
  125. 'fontname', 'fontsize', '|', 'forecolor', 'hilitecolor', 'bold', 'italic', 'underline',
  126. 'removeformat', '|', 'justifyleft', 'justifycenter', 'justifyright', 'insertorderedlist',
  127. 'insertunorderedlist', '|', 'emoticons', 'image', 'link']
  128. });
  129. });
  130.  
  131. function CommentSub() {
  132. var content = $('iframe.ke-edit-iframe').contents().find('body').text();
  133. var reply_id = $('#reply_id').attr('reply_id');
  134. $.ajax({
  135. url:'/update_comment.html',
  136. type:'POST',
  137. data:{'content':content,'article_id':{{article_obj.nid}},'reply_id':reply_id},
  138. headers:{'X-CSRFtoken':$.cookie('csrftoken')},
  139. success:function (data) {
  140. var data = JSON.parse(data);
  141. if(data['status']){
  142. location.reload()
  143. }
  144. },error:function () {
  145.  
  146. }
  147.  
  148. })
  149. }
  150.  
  151. function Reply(ths) {
  152. var name = $(ths).parent().prev().find('span#nickname').text();
  153. var nickname ='@'+name+ " \n\r ";
  154. console.log(nickname);
  155. $('iframe.ke-edit-iframe').contents().find('body').text(nickname);
  156. var nid = $(ths).attr('nid');
  157. console.log(nid);
  158. $('#reply_id').attr('reply_id',nid);
  159. console.log($('#reply_id')[0])
  160. }
  161.  
  162. </script>
  163. {% endblock %}

home_detail.html

最重要的是评论功能!...

  

代码-》跳转

Python开发【项目】:博客后台的更多相关文章

  1. 使用react全家桶制作博客后台管理系统 网站PWA升级 移动端常见问题处理 循序渐进学.Net Core Web Api开发系列【4】:前端访问WebApi [Abp 源码分析]四、模块配置 [Abp 源码分析]三、依赖注入

    使用react全家桶制作博客后台管理系统   前面的话 笔者在做一个完整的博客上线项目,包括前台.后台.后端接口和服务器配置.本文将详细介绍使用react全家桶制作的博客后台管理系统 概述 该项目是基 ...

  2. 基于 abp vNext 和 .NET Core 开发博客项目 - 博客接口实战篇(三)

    系列文章 基于 abp vNext 和 .NET Core 开发博客项目 - 使用 abp cli 搭建项目 基于 abp vNext 和 .NET Core 开发博客项目 - 给项目瘦身,让它跑起来 ...

  3. 基于 abp vNext 和 .NET Core 开发博客项目 - 博客接口实战篇(五)

    系列文章 基于 abp vNext 和 .NET Core 开发博客项目 - 使用 abp cli 搭建项目 基于 abp vNext 和 .NET Core 开发博客项目 - 给项目瘦身,让它跑起来 ...

  4. 基于.NetCore开发博客项目 StarBlog - (6) 页面开发之博客文章列表

    系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 基于.NetC ...

  5. 基于 abp vNext 和 .NET Core 开发博客项目 - 博客接口实战篇(二)

    系列文章 基于 abp vNext 和 .NET Core 开发博客项目 - 使用 abp cli 搭建项目 基于 abp vNext 和 .NET Core 开发博客项目 - 给项目瘦身,让它跑起来 ...

  6. 基于 abp vNext 和 .NET Core 开发博客项目 - 博客接口实战篇(四)

    系列文章 基于 abp vNext 和 .NET Core 开发博客项目 - 使用 abp cli 搭建项目 基于 abp vNext 和 .NET Core 开发博客项目 - 给项目瘦身,让它跑起来 ...

  7. 有哪些关于 Python 的技术博客?

    Python是一种动态解释型的编程语言,它可以在Windows.UNIX.MAC等多种操作系统以及Java..NET开发平台上使用.不过包含的内容很多,加上各种标准库.拓展库,乱花渐欲迷人眼.因此如何 ...

  8. 《全栈营销之如何制作个人博客》之二:php环境安装及个人博客后台搭建 让你的博客跑起来

    上一节我们讲了个人博客用什么开发语言,用什么CMS系统,从这一节我们就开始真正的干货,这一节我们讨论一下PHP环境的安装,及个人博客后台的搭建,让你的博客在正常的PHP环境中运行起来,你就可以进行后台 ...

  9. 使用react全家桶制作博客后台管理系统

    前面的话 笔者在做一个完整的博客上线项目,包括前台.后台.后端接口和服务器配置.本文将详细介绍使用react全家桶制作的博客后台管理系统 概述 该项目是基于react全家桶(React.React-r ...

随机推荐

  1. Xcode 5.0 编译低版本app

    Xcode 5.0 默认的编译环境是iOS7,编译出来的app,安装到iOS7.0版本以上的手机上,会表现出iOS7.0的风格.兼容不太好的应用,布局上可能会因此乱八七糟. 如果还不想让app升级到i ...

  2. c++ mktime()

    今天联系写一个日历的程序,需要算出月份中的第一天是星期几,用到了mktime()这个函数,感觉这个函数挺有用的,分享给大家. 原型:time_t mktime(struct tm *) 其中的tm结构 ...

  3. protobuf语法

    是什么? 目前市面上的unity手游开发主流数据通讯协议的解决方案.protobuf是google提供的一个开源序列化框架,类似于XML,JSON这样的数据表示语言,其最大的特点是基于二进制,因此比传 ...

  4. SVN目录权限设置

    ---恢复内容开始--- 如图,这里我建的项目库为myRepositories,其下边又有许多文件,现在要分别对每个文件进行svn权限配置. 配置 进入上面生成的文件夹conf下,进行配置.有以下几个 ...

  5. 什么是集群(Cluster)技术

    什么是集群(Cluster)技术Cluster集群技术可如下定义:一组相互独立的服务器在网络中表现为单一的系统,并以单一系统的模式加以管理.此单一系统为客户工作站提供高可*性的服务.大多数模式下,集群 ...

  6. [Scikit-learn] Dynamic Bayesian Network - HMM

    Warning The sklearn.hmm module has now been deprecated due to it no longer matching the scope and th ...

  7. VS------修改项目命名空间

    1.以文本形式打开此文件 2.修改一下部分 3.vs会自动提示,选择“放弃”即可

  8. 7 -- Spring的基本用法 -- 3... Spring 的核心机制 : 依赖注入

    7.3 Spring 的核心机制 : 依赖注入 Spring 框架的核心功能有两个. Spring容器作为超级大工厂,负责创建.管理所有的Java对象,这些Java对象被称为Bean. Spring容 ...

  9. ref 属性使用eslint报错

    react 使用 ref 报错 ,[eslint] Using string literals in ref attributes is deprecated. (react/no-string-re ...

  10. js 小数取整,js 小数向上取整,js小数向下取整

    js 小数取整,js 小数向上取整,js小数向下取整 >>>>>>>>>>>>>>>>>>& ...