目录

  1. 项目介绍和源码
  2. 拿来即用的bootstrap模板
  3. 服务器SSH服务配置与python中paramiko的使用
  4. 用户登陆与session;
  5. 最简单的实践之修改服务器时间
  6. 查看和修改服务器配置与数据库的路由;
  7. 基于websocket的实时日志实现
  8. 查看服务器中的日志与前端的datatable的利用
  9. 重启服务器进程

前言

  运维过程中,常常希望修改一些配置文件,文章用网站的功能替代登陆服务器修改文件,并不是十全十美,总得来说,实现了功能。文章主要分为两个部分,分别是数据库的路由和服务器配置的处理。这个功能页面如图1所示。

数据库的路由

  一个django项目通常会有多个app,一般每个app的功能差异较大,造成models.py差异也较大,可以为每一个app设置一个单独的存储数据库。这个项目中server就有一个单独的数据库存储它有的一些表(图2 蓝框),其他的功能默认存储在mysql这个默认的数据库中(图2 红框)。要使用该功能需要修改项目的配置(settings.py)文件。

修改settings

  1. # Database 配置
  2. DATABASE_ROUTERS = ['WebTool.database_router.DatabaseAppsRouter']
  3. DATABASE_APPS_MAPPING = {
  4. # example:
  5. # 'app_name':'database_name',
  6. # 为server单独设置一个名字叫做server的数据库
  7. 'server': 'server',
  8. }
  9. DATABASES = {
  10. # 默认的数据库,未指定存放位置的表会建在这个数据库里面,也包含一些django自带的表
  11. 'default': {
  12. 'ENGINE': 'django.db.backends.mysql',
  13. 'NAME': 'mysql',
  14. 'USER': 'root',
  15. 'PASSWORD': 'root',
  16. 'HOST': '127.0.0.1',
  17. 'PORT': '',
  18. },
  19. # server的数据库
  20. 'server': {
  21. 'ENGINE': 'django.db.backends.mysql',
  22. 'NAME': 'server',
  23. 'USER': 'root',
  24. 'PASSWORD': 'root',
  25. 'HOST': '127.0.0.1',
  26. 'PORT': '',
  27. },
  28. }

添加database_router.py文件

  在WebTool/WebTool下添加一个py文件用来实现数据库路由功能,文件命名为database_router.py,如图3红框位置。

  1. from django.conf import settings
  2. DATABASE_MAPPING = settings.DATABASE_APPS_MAPPING
  3. class DatabaseAppsRouter(object):
  4. """
  5. A router to control all database operations on models for different
  6. databases.
  7. In case an app is not set in settings.DATABASE_APPS_MAPPING, the router
  8. will fallback to the `default` database.
  9. Settings example:
  10. DATABASE_APPS_MAPPING = {'app1': 'db1', 'app2': 'db2'}
  11. """
  12. def db_for_read(self, model, **hints):
  13. """"Point all read operations to the specific database."""
  14. if model._meta.app_label in DATABASE_MAPPING:
  15. return DATABASE_MAPPING[model._meta.app_label]
  16. return None
  17. def db_for_write(self, model, **hints):
  18. """Point all write operations to the specific database."""
  19. if model._meta.app_label in DATABASE_MAPPING:
  20. return DATABASE_MAPPING[model._meta.app_label]
  21. return None
  22. def allow_relation(self, obj1, obj2, **hints):
  23. """Allow any relation between apps that use the same database."""
  24. db_obj1 = DATABASE_MAPPING.get(obj1._meta.app_label)
  25. db_obj2 = DATABASE_MAPPING.get(obj2._meta.app_label)
  26. if db_obj1 and db_obj2:
  27. if db_obj1 == db_obj2:
  28. return True
  29. else:
  30. return False
  31. return None
  32. def allow_syncdb(self, db, model):
  33. """Make sure that apps only appear in the related database."""
  34. if db in DATABASE_MAPPING.values():
  35. return DATABASE_MAPPING.get(model._meta.app_label) == db
  36. elif model._meta.app_label in DATABASE_MAPPING:
  37. return False
  38. return None
  39. def allow_migrate(self, db, app_label, model=None, **hints):
  40. """
  41. Make sure the auth app only appears in the 'auth_db'
  42. database.
  43. """
  44. if db in DATABASE_MAPPING.values():
  45. return DATABASE_MAPPING.get(app_label) == db
  46. elif app_label in DATABASE_MAPPING:
  47. return False
  48. return None

在model函数中建立映射

  前篇文章最简单的实践之修改服务器时间中曾经设置过两个model函数分别是taskinbackground和modifytime,app_label就是用来区分该函数用来对应哪个数据库的,app_label = "server"是把表建立在server这个数据库里面。

  1. class taskinbackground(models.Model):
  2. taskname = models.CharField(max_length=50)
  3. taskor = models.CharField(max_length=100)
  4. class Meta:
  5. db_table = 'task'
  6. app_label = "server"
  7. class modifytime(models.Model):
  8. modifyer = models.CharField(max_length=100)
  9. modifytime = models.CharField(max_length=200, default="")
  10. modifyservertime = models.CharField(max_length=200, default="")
  11. class Meta:
  12. db_table = 'modifytime'
  13. app_label = "server"

初始化数据库

  执行python manage.py makemigrationspython manage.py migratepython manage.py migrate --database=server三条指令分别用来更新数据库、刷新默认的数据库和server的数据库。这样,一个数据库的路由就可以了,现在可以不同app对应不同的数据库了。

服务器配置

  这个页面功能可以用下图4概括,其中的函数来自于服务器SSH服务配置与python中paramiko的使用中。实现这个些功能中会遇到一些小细节的处理。

  这里直接给出页面的html代码:

  1. {% extends "./base.html" %}
  2. {% block othercss %}{% endblock %}
  3. {% block title %}{{ title }}{% endblock %}
  4. {% block log %}{{ title }}{% endblock %}
  5. {% block username %}{{ username }}{% endblock %}
  6. {% block mainbody %}
  7. <section class="wrapper site-min-height">
  8. <h3><i class="fa fa-angle-right"></i> 服务器配置 <i class="fa fa-cog"></i></h3>
  9. <div class="row mt">
  10. <div class="form-panel">
  11. <div class="col-lg-12 row mt">
  12. <div class="col-sm-6">
  13. <h4 class="mb" style="float:left;dispaly:block;">服务器配置</h4>
  14. <button type="button" class="btn btn-theme02" id='getconfig' style="float:right;dispaly:block;">更新服务器配置</button>
  15. </div>
  16. <div class="col-sm-6">
  17. <div class="col-sm-12">
  18. <!--onkeyup="searchintable()" 当每次输入键盘弹起后就调用函数-->
  19. <input type="text" class="form-control" onkeyup="searchintable()" id="search" placeholder="配置搜索">
  20. </div>
  21. </div>
  22. <div class="col-sm-12">
  23. <!-- 获取配置的时候出现的加载图标 -->
  24. <div class="progress progress-striped active" style="display:none" id="loading">
  25. <div class="progress-bar" role="progressbar" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100" style="width: 100%"></div>
  26. </div>
  27. </div>
  28. </div>
  29. <table class="table table-striped table-advance table-hover" id="configtable">
  30. <thead>
  31. <tr>
  32. <th style="width:15%;"><i class="fa fa-cog"></i> 配置文件</th>
  33. <th style="width:55%;" class="hidden-phone">&nbsp;&nbsp;&nbsp;&nbsp;<i class="fa fa-question-circle"></i> 配置描述</th>
  34. <th><i class=" fa fa-edit"></i> 操作</th>
  35. </tr>
  36. </thead>
  37. <tbody>
  38. {% for index,name,detail in name_list %}
  39. <tr>
  40. <td style="vertical-align:middle;">{{ name }}</td>
  41. {% if detail == '' %}
  42. <td tyle="vertical-align:middle;">
  43. <div class="col-sm-8">
  44. <div class="input-group">
  45. <input type="text" class="form-control" placeholder='此处可以添加配置描述'>
  46. <span class="input-group-btn">
  47. <button class="btn btn-default" onclick="write_detail(this, &quot;{{name}}&quot;)" type="button">添加</button>
  48. </span>
  49. </div>
  50. </div>
  51. </td>
  52. {% else %}
  53. <td style="vertical-align:middle;">
  54. <div class="col-sm-8">
  55. <div class="input-group" style="display:none;">
  56. <input type="text" class="form-control" placeholder='此处可以添加配置描述'>
  57. <span class="input-group-btn">
  58. <button class="btn btn-default" onclick="write_detail(this, &quot;{{name}}&quot;)" type="button">添加</button>
  59. </span>
  60. </div>
  61. <div>
  62. {{ detail }}&nbsp;&nbsp;<button onclick="modify_detail(this)" style="border:0;background:transparent;"><i class="fa fa-pencil"></i></button>
  63. </div>
  64. </div>
  65. </td>
  66. {% endif %}
  67. <!-- 每一行配置的三个操作按钮 -->
  68. <td style="vertical-align:middle;">
  69. <button class="btn btn-success btn-sm" data-toggle="modal" data-target="#readModal" onclick="readbutton(&quot;{{name}}&quot;)"><i class="fa fa-eye"></i></button>
  70. <button class="btn btn-primary btn-sm" data-toggle="modal" data-target="#writeModal" onclick="writebutton(&quot;{{name}}&quot;)"><i class="fa fa-pencil"></i></button>
  71. <button class="btn btn-danger btn-sm" onclick="deletebutton(&quot;{{name}}&quot;)"><i class="fa fa-trash-o"></i></button>
  72. </td>
  73. </tr>
  74. {% endfor %}
  75. </tbody>
  76. </table>
  77. </div>
  78. </div>
  79. </section>
  80. <!-- 查看配置模态框 -->
  81. <div class="modal fade" id="readModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
  82. <div class="modal-dialog">
  83. <input type="hidden" name='modal' value=''>
  84. <div class="modal-content">
  85. <div class="modal-header">
  86. <button type="button" class="close" data-dismiss="modal" aria-hidden="true">
  87. &times;
  88. </button>
  89. <h4 class="modal-title" id="myModalLabelread">
  90. 模态框(Modal)标题
  91. </h4>
  92. </div>
  93. <!--style="cursor:default" 设置只读状态-->
  94. <textarea type="text" class="form-control modal-body-read" rows="35" placeholder="" readonly="readonly" style="cursor:default">
  95. 在这里添加一些文本
  96. </textarea>
  97. <div class="modal-footer">
  98. <button type="button" class="btn btn-theme02" data-dismiss="modal">关闭
  99. </button>
  100. </div>
  101. </div>
  102. </div>
  103. </div>
  104. <!-- 修改配置模态框 -->
  105. <div class="modal fade" id="writeModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
  106. <div class="modal-dialog">
  107. <input type="hidden" id='configname' name='modal' value=''>
  108. <div class="modal-content">
  109. <div class="modal-header">
  110. <button type="button" class="close" id="closebtn1" data-dismiss="modal" aria-hidden="true">
  111. &times;
  112. </button>
  113. <h4 class="modal-title" id="myModalLabelwrite">
  114. 模态框(Modal)标题
  115. </h4>
  116. </div>
  117. <div class="progress progress-striped active" style="display:none;" id="writeloading">
  118. <div class="progress-bar" role="progressbar" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100" style="width: 100%"></div>
  119. </div>
  120. <textarea type="text" class="form-control modal-body-write" rows="35" placeholder=""></textarea>
  121. <div class="modal-footer">
  122. <button type="button" class="btn btn-theme03" id="putconfigbtn" onclick="putconfig()">提交</button>
  123. <button type="button" class="btn btn-theme02" id="closebtn2" data-dismiss="modal">关闭</button>
  124. </div>
  125. </div>
  126. </div>
  127. </div>
  128. {% endblock %}

  页面使用到的javascript函数:

  1. {% block scripts %}
  2. <script>
  3. // 提交修改后的配置
  4. function putconfig(){
  5. swal({
  6. title: '提交新的配置?',
  7. type: 'warning',
  8. confirmButtonColor: '#DD6B55',
  9. confirmButtonText:"是的",
  10. cancelButtonText:"不用",
  11. showLoaderOnConfirm: true, //加载按钮是否可见
  12. showCancelButton: true,
  13. preConfirm: function() {
  14. return new Promise(function(resolve) {
  15. setTimeout(function(){
  16. $("#putconfigbtn").hide();
  17. $("#closebtn1").hide();
  18. $("#closebtn2").hide();
  19. $("#writeloading").show();
  20. resolve();
  21. }, 3000);
  22. });
  23. },
  24. allowOutsideClick: false, //弹框外是否可点
  25. }).then(function(res){
  26. if(res) {
  27. $.ajax({
  28. url:"writeconfig",
  29. type:'POST',
  30. data:{'name':$("#configname").val(), 'content':$(".modal-body-write").val()},
  31. success: function(arg){
  32. ret = eval(arg);
  33. if(ret.status){
  34. swal({
  35. type: 'success',
  36. title: '设置修改成功!',
  37. confirmButtonText: '确定',
  38. confirmButtonColor: '#4cd964',
  39. allowOutsideClick: false,
  40. }).then(function(){
  41. window.location.reload();
  42. });
  43. }else{
  44. if(ret.error == '1'){
  45. swal({
  46. type: 'error',
  47. title: 'json格式错误,请重新修改!',
  48. confirmButtonText: '确定',
  49. confirmButtonColor: '#4cd964',
  50. allowOutsideClick: false,
  51. }).then(function(){
  52. window.location.reload();
  53. });
  54. }else{
  55. swal({
  56. type: 'error',
  57. title: '设置修改失败!',
  58. confirmButtonText: '确定',
  59. confirmButtonColor: '#4cd964',
  60. allowOutsideClick: false,
  61. }).then(function(){
  62. window.location.reload();
  63. });
  64. }
  65. }
  66. }});
  67. }
  68. });
  69. }
  70. // 只读按钮
  71. function readbutton(configname){
  72. $("#myModalLabelread").html("<b>查看"+configname+"配置</b>");
  73. $.ajax({
  74. url:"readconfig",
  75. type:'POST',
  76. data:{'configname':configname},
  77. success: function(arg){
  78. ret = eval(arg);
  79. content = ret.content;
  80. var json = JSON.parse(content);
  81. $(".modal-body-read").html(JSON.stringify(json,null,4));
  82. }
  83. });
  84. }
  85. // 修改按钮
  86. function writebutton(configname){
  87. $("#myModalLabelwrite").html("<b>修改"+configname+"配置</b>");
  88. // 模态框中添加一个属性用来记录配置的名字,方便提交配置取配置的名字
  89. $("#configname").val(configname);
  90. $.ajax({
  91. url:"readconfig",
  92. type:'POST',
  93. data:{'configname':configname},
  94. success: function(arg){
  95. ret = eval(arg);
  96. content = ret.content;
  97. var json = JSON.parse(content);
  98. // JSON.stringify(json,null,4)函数可以将字符串格式化成json格式
  99. $(".modal-body-write").html(JSON.stringify(json,null,4));
  100. }
  101. });
  102. }
  103. // 删除配置
  104. function deletebutton(configname){
  105. swal({
  106. title: '删除'+configname+'这个配置?',
  107. type: 'warning',
  108. confirmButtonColor: '#DD6B55',
  109. confirmButtonText:"是的",
  110. cancelButtonText:"不用",
  111. showLoaderOnConfirm: true, //加载按钮是否可见
  112. showCancelButton: true,
  113. preConfirm: function() {
  114. return new Promise(function(resolve) {
  115. setTimeout(function(){
  116. resolve();
  117. }, 6000);
  118. });
  119. },
  120. allowOutsideClick: false, //弹框外是否可点
  121. }).then(function(res){
  122. if(res) {
  123. $.ajax({
  124. url:"deleteconfig",
  125. type:'POST',
  126. data:{'name':configname },
  127. success: function(arg){
  128. ret = eval(arg);
  129. if(ret.status){
  130. if(ret.status){
  131. swal({
  132. type: 'success',
  133. title: '删除完成!',
  134. confirmButtonText: '确定',
  135. confirmButtonColor: '#4cd964'
  136. }).then(function(){
  137. window.location.reload();
  138. });
  139. }else{
  140. swal({
  141. type: 'error',
  142. title: '删除失败!',
  143. confirmButtonText: '确定',
  144. confirmButtonColor: '#4cd964'
  145. }).then(function(){
  146. window.location.reload();
  147. });
  148. }
  149. }
  150. }});
  151. }
  152. });
  153. }
  154. // 为配置添加描述
  155. function write_detail(obj, name){
  156. var father_span = obj.parentNode;
  157. var input = $(father_span).prev();
  158. var detail = input.val();
  159. $.ajax({
  160. url:"configdetail",
  161. type:'POST',
  162. data:{'name':name, 'detail':detail},
  163. success: function(arg){
  164. window.location.reload();
  165. }});
  166. }
  167. function modify_detail(obj){
  168. $(obj).parent().prev().show();
  169. $(obj).parent().hide();
  170. }
  171. </script>
  172. <script>
  173. // 查询函数
  174. function searchintable(){
  175. input = document.getElementById("search");
  176. filter = input.value.toUpperCase();
  177. table = document.getElementById("configtable");
  178. tr = table.getElementsByTagName("tr");
  179. for(i = 0; i < tr.length; i++){
  180. td = tr[i].getElementsByTagName("td")[0];
  181. if (td){
  182. if (td.innerHTML.toUpperCase().indexOf(filter) > -1){
  183. tr[i].style.display = "";
  184. }else{
  185. tr[i].style.display = "none";
  186. }
  187. }
  188. }
  189. }
  190. </script>
  191. <script>
  192. $(document).ready(function(){
  193. //从服务器更新配置到数据库
  194. $("#getconfig").click(function(){
  195. swal({
  196. title: '您确定要重新获取游戏配置吗?',
  197. type: 'warning',
  198. confirmButtonColor: '#DD6B55',
  199. confirmButtonText:"是的!",
  200. cancelButtonText:"让我再考虑一下…",
  201. showLoaderOnConfirm: true, //加载按钮是否可见
  202. showCancelButton: true,
  203. preConfirm: function() {
  204. return new Promise(function(resolve){
  205. setTimeout(function(){
  206. $("#getconfig").hide();
  207. $("#search").hide();
  208. $("#loading").show();
  209. $('table > tbody').remove();
  210. resolve();
  211. }, 3000);
  212. });
  213. },
  214. allowOutsideClick: false, //弹框外是否可点
  215. }).then(function(res){
  216. if (res){
  217. $.ajax({
  218. url:"getconfig",
  219. type:'GET',
  220. success: function(arg){
  221. ret = eval(arg);
  222. if(ret.status){
  223. swal({
  224. type: 'success',
  225. title: '更新完成!',
  226. confirmButtonText: '确定',
  227. confirmButtonColor: '#4cd964'
  228. }).then(function(){
  229. window.location.reload();
  230. });
  231. }else{
  232. swal({
  233. type: 'error',
  234. title: '更新失败!',
  235. confirmButtonText: '确定',
  236. confirmButtonColor: '#4cd964'
  237. }).then(function(){
  238. window.location.reload();
  239. });
  240. }
  241. }});
  242. }})
  243. });
  244. });
  245. </script>
  246. {% endblock %}

  下面具体说下这些功能的交互。

显示界面

  • 创建配置相关的model函数
  1. # -*- coding: utf-8 -*-
  2. from __future__ import unicode_literals
  3. from django.db import models
  4. class serverconfig(models.Model):
  5. id = models.AutoField(primary_key=True)
  6. # 配置的名字
  7. config_name = models.CharField(max_length=100)
  8. # 配置的内容
  9. content = models.TextField()
  10. # 配置的描述
  11. detail = models.CharField(max_length=200, default="")
  12. class Meta:
  13. # 别名(存储在数据库中的table名)
  14. db_table = 'serverconfig'
  15. # 使用server数据库
  16. app_label = "server"

  依然,创建好之后需要更新django的数据表,执行python manage.py migrate --database=server

  • 添加渲染函数serverconfig的url(server/urls.py)

  除了给出渲染函数serverconfig,这里的urls.py还写了所有后文中需要用到的相关功能url:获得配置、读取配置、修改配置、删除配置、添加配置的描述。

  1. from django.conf.urls import url
  2. import views
  3. urlpatterns = [
  4. url(r'^$', views.homepage),
  5. url(r'^home', views.homepage),
  6. url(r'^servertime', views.servertime),
  7. # 服务器配置的渲染函数
  8. url(r'^serverconfig', views.serverconfig),
  9. # 相关功能函数
  10. # 获得配置
  11. url(r'^getconfig', views.getconfig),
  12. # 读取配置
  13. url(r'^readconfig', views.readconfig),
  14. # 修改配置
  15. url(r'^writeconfig', views.writeconfig),
  16. # 删除配置
  17. url(r'^deleteconfig', views.deleteconfig),
  18. # 添加配置的描述
  19. url(r'^configdetail', views.configdetail),
  20. # 以下的url在前面的文章已经实现
  21. url(r'^settime', views.settime),
  22. url(r'^usingserver', views.usingserver),
  23. url(r'^restartserver', views.restartserver),
  24. url(r'^getservertime', views.getservertime),
  25. url(r'^recoverlocaltime', views.recoverlocaltime),
  26. url(r'^userlogout', views.userlogout),
  27. ]
  • 在views.py中(server/views.py)添加渲染函数servertime

  页面渲染函数会将数据库中的配置通过字典传递给前端渲染,值得注意的是,这里传递给前端的只有配置的名字和它的相关描述。每个配置的展示交给前端的javascript中的getconfig单独通过ajax获取。上面给出的html中,前端页面通过模板语言,利用for循环添加到table中(tr元素)。

  1. # -*- coding: utf-8 -*-
  2. from __future__ import unicode_literals
  3. from django.contrib.auth import logout
  4. from django.shortcuts import render_to_response
  5. from django.http import JsonResponse
  6. from django.contrib.auth.decorators import login_required
  7. import json
  8. import time
  9. # 服务器的名字
  10. htmltitle = '服务器工具'
  11. @login_required(login_url='/loginpage')
  12. def serverconfig(request):
  13. from server import models
  14. username = request.session.get('username')
  15. name_list = []
  16. config_name = models.serverconfig.objects.all().values_list('id', 'config_name', 'detail')
  17. for name in config_name:
  18. name_list.append(name)
  19. pagedict = {'name_list': name_list, 'title': htmltitle, 'username': username}
  20. return render_to_response("servermaterial/serverconfig.html", pagedict)

  添加这些功能后,就能够通过http://127.0.0.1:8888/server/serverconfig.html访问这个页面了,但是我们看到的表格中没有配置,是因为网站后台还没有从服务器读取相关的配置。

配置相关操作

获得/更新配置

  要获得这些配置需要添加相关的view函数(server/views.py),这个view函数会对比服务器中最新的配置文件和mysql中存储的配置文件的差别进行增、删、改,这个函数是通过html中的id=getconfig的按钮触发的,它的javascript函数可以在上面找到,为$("#getconfig").click(function(){...}),url也已经在上面给出,其对应前端页面红框中的按钮,如图5。

  1. # 获得服务器配置
  2. def getconfig(request):
  3. from server import models
  4. if request.method == 'GET':
  5. ret = {'status': False}
  6. from WebTool.functions import get_serverconfig_lists, read_serverconfig
  7. # 获得服务器中最新的配置文件名组成的列表
  8. newconfigs = get_serverconfig_lists()
  9. # 获得数据库中记录的未更新的老配置文件名列表
  10. name_list = models.serverconfig.objects.all().values('config_name')
  11. oldconfigs = []
  12. for name in name_list:
  13. oldconfigs.append(str(name['config_name']))
  14. # 服务器和数据库中配置名相同的文件名,对其更新一下配置内容
  15. common = [name for name in newconfigs if name in oldconfigs]
  16. for config in common:
  17. configcontent = read_serverconfig(config)
  18. models.serverconfig.objects.filter(config_name=config).update(content=configcontent)
  19. # 服务器中增加的配置文件名,数据库中增加一份
  20. add_con = [name for name in newconfigs if name not in oldconfigs]
  21. for config in add_con:
  22. configcontent = read_serverconfig(config)
  23. models.serverconfig.objects.create(config_name=config, content=configcontent)
  24. # 服务器已经不存在的配置文件名,数据库删除一份
  25. delete_con = [name for name in oldconfigs if name not in newconfigs]
  26. for config in delete_con:
  27. models.serverconfig.objects.filter(config_name=config).delete()
  28. ret['status'] = True
  29. return JsonResponse(ret)

  所有的配置文件都放在如下图6所示的服务器目录中,网站后台通过调用funtions.py中的函数(这些paramiko函数在服务器SSH服务配置与python中paramiko的使用文章中已经封装好了)获得这些配置的名字。

  • 前端实现配置搜索

  如果要实现键盘弹起就进行搜索可以参考这里,在input中加入onkeyup这个性质,图7中红色的搜索框的html代码如下:

  <input type="text" class="form-control" onkeyup="searchintable()" id="search" placeholder="配置搜索">

  searchintable()函数如下,加入函数之后便可以实现在搜索框中一边输入一边搜索配置。

  1. <script>
  2. // 查询函数
  3. function searchintable(){
  4. input = document.getElementById("search");
  5. filter = input.value.toUpperCase();
  6. table = document.getElementById("configtable");
  7. tr = table.getElementsByTagName("tr");
  8. for(i = 0; i < tr.length; i++){
  9. td = tr[i].getElementsByTagName("td")[0];
  10. if (td){
  11. if (td.innerHTML.toUpperCase().indexOf(filter) > -1){
  12. tr[i].style.display = "";
  13. }else{
  14. tr[i].style.display = "none";
  15. }
  16. }
  17. }
  18. }
  19. </script>

前端读取配置

  读取、修改、删除的按钮在图8的红框中。

  点击绿色的查看按钮会弹出只读的模态框,如图9所示。

  读取配置的模态框,配置文件写在textarea中,readonly="readonly"可将其设置为只读模式:

  1. <div class="modal fade" id="readModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
  2. <div class="modal-dialog">
  3. <input type="hidden" name='modal' value=''>
  4. <div class="modal-content">
  5. <div class="modal-header">
  6. <button type="button" class="close" data-dismiss="modal" aria-hidden="true">
  7. &times;
  8. </button>
  9. <h4 class="modal-title" id="myModalLabelread">
  10. 模态框(Modal)标题
  11. </h4>
  12. </div>
  13. <!--style="cursor:default" 设置只读状态-->
  14. <textarea type="text" class="form-control modal-body-read" rows="35" placeholder="" readonly="readonly" style="cursor:default">
  15. 在这里添加一些文本
  16. </textarea>
  17. <div class="modal-footer">
  18. <button type="button" class="btn btn-theme02" data-dismiss="modal">关闭
  19. </button>
  20. </div>
  21. </div>
  22. </div>
  23. </div>

  读取配置的view函数,函数直接在数据库中按名字查找配置的具体内容。

  1. # get config content
  2. def readconfig(request):
  3. ret = {'status': False, 'content': ''}
  4. if request.method == 'POST':
  5. from server import models
  6. name = request.POST.get('configname')
  7. content = models.serverconfig.objects.get(config_name=name).content
  8. ret['status'] = True
  9. ret['content'] = content
  10. return JsonResponse(ret)
  11. return JsonResponse(ret)

前端修改配置

  点击蓝色的修改按钮会弹出修改配置的模态框,如下图10。

  读取配置的模态框,配置文件写在textarea中,并为其添加一个提交按钮:

  1. <div class="modal fade" id="writeModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
  2. <div class="modal-dialog">
  3. <input type="hidden" id='configname' name='modal' value=''>
  4. <div class="modal-content">
  5. <div class="modal-header">
  6. <button type="button" class="close" id="closebtn1" data-dismiss="modal" aria-hidden="true">
  7. &times;
  8. </button>
  9. <h4 class="modal-title" id="myModalLabelwrite">
  10. 模态框(Modal)标题
  11. </h4>
  12. </div>
  13. <div class="progress progress-striped active" style="display:none;" id="writeloading">
  14. <div class="progress-bar" role="progressbar" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100" style="width: 100%"></div>
  15. </div>
  16. <textarea type="text" class="form-control modal-body-write" rows="35" placeholder=""></textarea>
  17. <div class="modal-footer">
  18. <button type="button" class="btn btn-theme03" id="putconfigbtn" onclick="putconfig()">提交</button>
  19. <button type="button" class="btn btn-theme02" id="closebtn2" data-dismiss="modal">关闭</button>
  20. </div>
  21. </div>
  22. </div>
  23. </div>

  点击提交按钮会出现swal风格(插件在文章用户登陆与session中介绍过)的二次确认框,如上图9。ajax请求经过server/urls.py中的url找到server/views.py中的writeconfig函数。因为文中的配置都是json格式的,如果格式不符合json要求会无法修改。这里有个缺点,修改服务器配置的函数generate_config_upload_file实际上只是在本地生成一个字符串然后上传覆盖掉服务器的同文件名的配置,并不是局部修改,所以对于大的配置文件修改效率低,但是为了方便就直接这样做了。

  1. # write config
  2. def writeconfig(request):
  3. ret = {'status': False, 'error': '', 'oldcontent': ''}
  4. if request.method == 'POST':
  5. from server import models
  6. from WebTool.functions import generate_config_upload_file
  7. name = request.POST.get('name')
  8. newcontent = request.POST.get('content')
  9. try:
  10. json.loads(newcontent)
  11. except ValueError:
  12. oldcontent = models.serverconfig.objects.get(config_name=name).content
  13. ret['oldcontent'] = oldcontent
  14. ret['error'] = '1'
  15. return JsonResponse(ret)
  16. rtn = generate_config_upload_file(name, newcontent)
  17. if rtn == 'Successful Upload':
  18. models.serverconfig.objects.filter(config_name=name).update(content=newcontent)
  19. ret['status'] = True
  20. return JsonResponse(ret)
  21. else:
  22. oldcontent = models.serverconfig.objects.get(config_name=name).content
  23. ret['oldcontent'] = oldcontent
  24. ret['error'] = '2'
  25. return JsonResponse(ret)

删除配置配置

  删除配置就更简单了,点击红色的按钮可以唤出二次确认框,如图11,然后ajax请求经过server/urls.py中的url找到server/views.py中的deleteconfig函数执行删除。

  1. # delete config
  2. def deleteconfig(request):
  3. ret = {'status': False}
  4. if request.method == 'POST':
  5. from server import models
  6. from WebTool.functions import delete_config
  7. name = request.POST.get('name')
  8. try:
  9. models.serverconfig.objects.filter(config_name=name).delete()
  10. delete_config(name)
  11. ret['status'] = True
  12. return JsonResponse(ret)
  13. except Exception:
  14. ret['status'] = False
  15. return JsonResponse(ret)

添加描述

  每个配置都需要添加响应的描述,如下图12的红框中的input框和描述。

  关于该行表格是显示描述还是input框是由数据库serverconfig表中detail字段是否有内容决定的。

  1. {% if detail == '' %}
  2. <td tyle="vertical-align:middle;">
  3. <div class="col-sm-8">
  4. <div class="input-group">
  5. <input type="text" class="form-control" placeholder='此处可以添加配置描述'>
  6. <span class="input-group-btn">
  7. <button class="btn btn-default" onclick="write_detail(this, &quot;{{name}}&quot;)" type="button">添加</button>
  8. </span>
  9. </div>
  10. </div>
  11. </td>
  12. {% else %}
  13. <td style="vertical-align:middle;">
  14. <div class="col-sm-8">
  15. <div class="input-group" style="display:none;">
  16. <input type="text" class="form-control" placeholder='此处可以添加配置描述'>
  17. <span class="input-group-btn">
  18. <button class="btn btn-default" onclick="write_detail(this, &quot;{{name}}&quot;)" type="button">添加</button>
  19. </span>
  20. </div>
  21. <div>
  22. {{ detail }}&nbsp;&nbsp;<button onclick="modify_detail(this)" style="border:0;background:transparent;"><i class="fa fa-pencil"></i></button>
  23. </div>
  24. </div>
  25. </td>
  26. {% endif %}

  把javascript代码单独拿出来,write_detail函数是添加配置中的按钮,点击按钮之后需要获得前面input框中的值,这里是分别通过javascript和jquery的parentNodeprev()这些节点关系函数来拿到,modify_detail函数是描述后面的修改笔$(obj).parent().prev().show();是让描述的字消失,$(obj).parent().hide();是让input框重新出现然后修改描述。

  1. <script>
  2. function write_detail(obj, name){
  3. var father_span = obj.parentNode;
  4. var input = $(father_span).prev();
  5. var detail = input.val();
  6. $.ajax({
  7. url:"configdetail",
  8. type:'POST',
  9. data:{'name':name, 'detail':detail},
  10. success: function(arg){
  11. window.location.reload();
  12. }});
  13. }
  14. function modify_detail(obj){
  15. $(obj).parent().prev().show();
  16. $(obj).parent().hide();
  17. }
  18. </script>

  ajax请求经过server/urls.py中的url找到server/views.py中的configdetail函数执行添加描述到数据库。

  1. # 添加配置描述
  2. def configdetail(request):
  3. ret = {'status': False}
  4. if request.method == 'POST':
  5. detail = request.POST.get('detail')
  6. name = request.POST.get('name')
  7. from server import models
  8. models.serverconfig.objects.filter(config_name=name).update(detail=detail)
  9. ret['status'] = True
  10. return JsonResponse(ret)

结语

  服务器配置文件修改基本上就实现了,下篇文章会说说websocket原理以及怎么利用websocket执行实时日志的查看。

django搭建一个小型的服务器运维网站-查看和修改服务器配置与数据库的路由的更多相关文章

  1. django搭建一个小型的服务器运维网站-查看服务器中的日志与前端的datatable的利用

    目录 项目介绍和源码: 拿来即用的bootstrap模板: 服务器SSH服务配置与python中paramiko的使用: 用户登陆与session; 最简单的实践之修改服务器时间: 查看和修改服务器配 ...

  2. django搭建一个小型的服务器运维网站-拿来即用的bootstrap模板

    目录 项目介绍和源码: 拿来即用的bootstrap模板: 服务器SSH服务配置与python中paramiko的使用: 用户登陆与session; 最简单的实践之修改服务器时间: 查看和修改服务器配 ...

  3. django搭建一个小型的服务器运维网站-用户登陆与session

    目录 项目介绍和源码: 拿来即用的bootstrap模板: 服务器SSH服务配置与python中paramiko的使用: 用户登陆与session; 最简单的实践之修改服务器时间: 查看和修改服务器配 ...

  4. django搭建一个小型的服务器运维网站-重启服务器的进程

    目录 项目介绍和源码: 拿来即用的bootstrap模板: 服务器SSH服务配置与python中paramiko的使用: 用户登陆与session; 最简单的实践之修改服务器时间: 查看和修改服务器配 ...

  5. django搭建一个小型的服务器运维网站

    前言   不管是运维还是开发抑或是测试,工作中不免会和Linux服务器打交道,常见的操作譬如:查看CPU或内存状态.查看和修改服务器时间.查看或者修改服务器配置文件.实时查看或回看系统的日志.重启服务 ...

  6. 10分钟搭建一个小型网页(python django)(hello world!)

    10分钟搭建一个小型网页(python django)(hello world!) 1.安装django pip install django 安装成功后,在Scripts目录下存在django-ad ...

  7. 初学django搭建一个通讯录应用

    ---恢复内容开始--- django搭建一个通讯录应用 一.环境介绍 window10 64位 Django-1.5.12 python 2.7 Sqlite3 二.基本安装 python2.7安装 ...

  8. 搭建一个webpack微服务器

    [前言]:因为最近在vue2.0的时候用到了webpack的externals,才发现我之前都只是用webpack做一些搭建完项目后的“收尾工作”——即打包,而没有把它纳入到项目开发的“主体过程”中来 ...

  9. 【日记】搭建一个node本地服务器

    用node搭建一个本地http服务器.首先了解htpp服务器原理 HTTP协议定义Web客户端如何从Web服务器请求Web页面,以及服务器如何把Web页面传送给客户端.HTTP协议采用了请求/响应模型 ...

随机推荐

  1. 【C++ STL 优先队列priority_queue】

    https://www.cnblogs.com/fzuljz/p/6171963.html

  2. Ubuntu C/C++的编译环境

    Ubuntu缺省情况下,并没有提供C/C++的编译环境,因此还需要手动安装.但是如果单独安装gcc以及g++比较麻烦,幸运的是,Ubuntu提供了一个build-essential软件包.查看该软件包 ...

  3. USB转换PS2接线原理

    https://blog.csdn.net/dfyy88/article/details/4540170 USB转换PS2接线原理 2009年09月10日 18:36:00 阅读数:13285 USB ...

  4. IDEA反编译jar包源码

    1.maven 项目查看jar源码 如何在idea中查看jar包源码   文章目录 准备jar包 idea打开文件夹 最后一步 准备jar包 例如,我准备看resin的jar,在桌面准备了一份 ide ...

  5. 网页上预览pdf文件的几种方案

    网页上查看pdf的方案: 1.使用adobe reader的插件 2.使用在线office控件 3.使用火狐开源项目pdf.js(浏览器需支持html5) 4.将pdf转换为swf文件 5.使用pdf ...

  6. Git配置用户名、邮箱

    当安装完 Git 应该做的第一件事就是设置你的用户名称与邮件地址. 这样做很重要,因为每一个 Git 的提交都会使用这些信息,并且它会写入到你的每一次提交中,不可更改. 否则,用户名会显示为unkno ...

  7. HTML5 列表、表格、媒体元素

    无序列表 <ul> <li>范冰冰演藏族女孩</li> <li>拍集体合影后自拍</li> <li>诗隆甜蜜出游</li& ...

  8. Java中字母大小写的转换

    例:String str = "AbC"; 把字符串所有字母变成小写: System.out.println(str.toLowerCase()); 把字符串所有字母大写: Sys ...

  9. centos 7 里如何判断IP是否合法

    ip=123.23.2.32; [[ $ip =~ ^(([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9 ...

  10. JavaWeb返回Json格式数据JQuery Ajax无法解析的问题

    今天在写实验室的傻逼Java Web小项目的时候,有一个需要发布内容的地方,因为想做的让用户感觉优雅一点 所以就是用了Ajax来做,本来很简单的一个小玩意,竟然花了半个多小时的时间,主要是将时间花在了 ...