代码发布3 gitpython模块, 代码发布概述图, 服务器管理, 项目管理, 发布任务管理, ModelForm使用, 重定向
pip3 install gitpython # 好用的模块:pandas numpy 处理excel表格 openpyxl...
基本使用
import os from git.repo import Repo # 下载远程仓库的代码可以怎么搞 clone pull # 先定义代码的存放位置 download_path = os.path.join('jason','NB') Repo.clone_from('https://github.com/DominicJi/TeachTest.git',to_path=download_path,branch='master') # 默认branch为master
更多操作
# ############## 2. pull最新代码 ############## import os from git.repo import Repo local_path = os.path.join('jason', 'NB') repo = Repo(local_path) repo.git.pull() # ############## 3. 获取所有分支 ############## import os from git.repo import Repo local_path = os.path.join('jason', 'NB') repo = Repo(local_path) branches = repo.remote().refs for item in branches: print(item.remote_head) # ############## 4. 获取所有版本 ############## import os from git.repo import Repo local_path = os.path.join('jason', 'NB') repo = Repo(local_path) for tag in repo.tags: print(tag.name) # ############## 5. 获取所有commit ############## import os from git.repo import Repo local_path = os.path.join('jason', 'NB') repo = Repo(local_path) # 将所有提交记录结果格式成json格式字符串 方便后续反序列化操作 commit_log = repo.git.log('--pretty={"commit":"%h","author":"%an","summary":"%s","date":"%cd"}', max_count=50, date='format:%Y-%m-%d %H:%M') log_list = commit_log.split("\n") real_log_list = [eval(item) for item in log_list] print(real_log_list) # ############## 6. 切换分支 ############## import os from git.repo import Repo local_path = os.path.join('jason', 'NB') repo = Repo(local_path) before = repo.git.branch() print(before) repo.git.checkout('master') after = repo.git.branch() print(after) repo.git.reset('--hard', '854ead2e82dc73b634cbd5afcf1414f5b30e94a8') # ############## 7. 打包代码 ############## with open(os.path.join('jason', 'NB.tar'), 'wb') as fp: repo.archive(fp)
对模块的诸多功能进行一个封装
import os from git.repo import Repo from git.repo.fun import is_git_dir class GitRepository(object): """ git仓库管理 """ def __init__(self, local_path, repo_url, branch='master'): self.local_path = local_path # 管理本地哪个文件夹 self.repo_url = repo_url # 远程仓库地址 self.repo = None self.initial(repo_url, branch) # 初始化git仓库 def initial(self, repo_url, branch): """ 初始化git仓库 :param repo_url: :param branch: :return: """ if not os.path.exists(self.local_path): # mkdir不能创建多级目录 makedirs可以创建多级目录 os.makedirs(self.local_path) git_local_path = os.path.join(self.local_path, '.git') if not is_git_dir(git_local_path): self.repo = Repo.clone_from(repo_url, to_path=self.local_path, branch=branch) else: self.repo = Repo(self.local_path) def pull(self): """ 从线上拉最新代码 :return: """ self.repo.git.pull() def branches(self): """ 获取所有分支 :return: """ branches = self.repo.remote().refs return [item.remote_head for item in branches if item.remote_head not in ['HEAD', ]] def commits(self): """ 获取所有提交记录 :return: """ commit_log = self.repo.git.log('--pretty={"commit":"%h","author":"%an","summary":"%s","date":"%cd"}', max_count=50, date='format:%Y-%m-%d %H:%M') log_list = commit_log.split("\n") return [eval(item) for item in log_list] def tags(self): # 版本(github网页在branch旁边) """ 获取所有tag :return: """ return [tag.name for tag in self.repo.tags] def change_to_branch(self, branch): """ 切换分值 :param branch: :return: """ self.repo.git.checkout(branch) def change_to_commit(self, branch, commit): """ 切换commit :param branch: :param commit: :return: """ self.change_to_branch(branch=branch) self.repo.git.reset('--hard', commit) def change_to_tag(self, tag): """ 切换tag :param tag: :return: """ self.repo.git.checkout(tag) # 使用 if __name__ == '__main__': local_path = os.path.join('codes', 'luffycity') repo = GitRepository(local_path,remote_path) branch_list = repo.branches() print(branch_list) repo.change_to_branch('dev') repo.pull()
s:当服务器特别多的时候,从同一个地方下载数据回出现压力过大的情况(上传者只有一个,下载者有N多个,上传者压力太大)
如何解决这种问题???
比特流技术
将所有人都变成既可以是上传者也可以是下载者
联想你下载小片片的时候有些速度快游戏速度慢,速度快可能是因为你室友的电脑中就有,你是从你室友的电脑中下载的,速度慢是因为你的周围都没有该资源的提供者
class Server(models.Model): """服务器表""" hostname = models.CharField(verbose_name='主机名',max_length=64)
所有的项目大部分的功能都是由最简单的增删改查组成,是整个业务逻辑的基础
并且只需要认认真真的写一个增删改查即可,后续所有的直接CV大法完事!!!
模版的基础作为模版的html文件上一般情况下,都应该定义三个区域cs区,html
内容区,js区
针对服务器添加数据的功能,需要对提交的数据进行数据校验,还需要展示提示信息
当模型字段非常多的时候前端页面展示代码量书写非常多
如何解决上述问题
""" 标签渲染 数据校验 信息展示 forms组件的功能 modelform组件也可以完成上面的三个要求,并且功能更加的强大简单 """ class ServerModelForm(ModelForm): class Meta: model = models.Server fields = "__all__" # 所有字段 def __init__(self,*args,**kwargs): super().__init__(*args,**kwargs) # print(self.fields) # OrderedDict([('hostname', <django.forms.fields.CharField object at 0x10c99c198>)]) # 给所有的字段加class属性 for k,field_obj in self.fields.items(): field_obj.widget.attrs['class'] = 'form-control'
return redirect('/server/list/') # 可以写路径 return redirect('server_list') # 还可以写别名 但是如果出现有名无名分组的反响解析 则必须使用reverse方法
语言环境
django默认的语言环境是英文,但是它的内部其实支持多个国家的语言,只需要你自己手动配置即可
# LANGUAGE_CODE = 'en-us' LANGUAGE_CODE = 'zh-hans' # 如何查看django到底支持哪些语言环境 from django.conf import global_settings LANGUAGES = [ ('af', gettext_noop('Afrikaans')), ('ar', gettext_noop('Arabic')), ('ast', gettext_noop('Asturian')), ... ]
针对删除功能,我们想做一个二次确认的过程(ajax结合sweetalert实现二次确认弹框)
{% block content %} <h1>项目列表</h1> <a href="{% url 'project_add' %}" class="btn btn-primary" style="margin: 10px 0;">添加数据</a> <table class="table table-hover table-striped"> <thead> <tr> <th>ID</th> <th>项目名</th> <th>仓库地址</th> <th>环境</th> <th>线上地址</th> <th>关联服务器</th> <th>操作</th> </tr> </thead> <tbody> {% for project_obj in project_queryset %} <tr> <td>{{ project_obj.pk }}</td> <td>{{ project_obj.title }}</td> <td>{{ project_obj.repo }}</td> <td>{{ project_obj.get_env_display }}</td> <td>{{ project_obj.path }}</td> <td> {% for server_obj in project_obj.servers.all %} <span style="border:1px solid black;padding: 5px;">{{ server_obj.hostname }}</span> {% endfor %} </td> <td> <a href="{% url 'project_edit' project_obj.pk %}">编辑</a> <a href="#" onclick="removeData(this,{{ project_obj.pk }})">删除</a> {# this是自带,指代当前被操作对象 #} </td> </tr> {% endfor %} </tbody> </table> {% endblock %} {% block js %} <script> function removeData(ths,sid) { var res = confirm('你缺点要删除吗?'); {#alert(res) // 布尔值#} if (res){ // 朝后端发送删除数据的请求 $.ajax({ url:'/server/delete/' + sid + '/', type:'get', success:function (args) { // 删除成功之后 页面应该立刻展示删除之后的效果 // 1 直接刷新 不太好 设计到分页的情况不太好 {#window.location.reload()#} if (args.status){ // 2 利用DOM操作实时删除 $(ths).parent().parent().remove() } } }) } } </script>
class Project(models.Model): """项目表""" title = models.CharField(verbose_name='项目名',max_length=64) repo = models.CharField(verbose_name='仓库地址',max_length=128) env_choices = ( ('prod','正式'), ('test','测试') ) env = models.CharField(verbose_name='环境',max_length=16,choices=env_choices,default='test')
代码的优化
代码的优化一定是在你把功能实现之后再去优化(先努力实现再考虑优化)
-
将所有的modelform单独抽取出来
-
将modelform类中所有公共的部分抽取出来形成基类
""" 什么是类? 类是对象公共的属性和技能的结合体 什么是父类? 父类是类公共的属性和技能的结合体 """ # 父类 from django.forms import ModelForm class BaseModelForm(ModelForm): def __init__(self,*args,**kwargs): super().__init__(*args,**kwargs) # print(self.fields) # OrderedDict([('hostname', <django.forms.fields.CharField object at 0x10c99c198>)]) # 给所有的字段加class属性 for k,field_obj in self.fields.items(): field_obj.widget.attrs['class'] = 'form-control' # 子类 from app01.myforms.base import BaseModelForm from app01 import models class ServerModelForm(BaseModelForm): class Meta: model = models.Server fields = "__all__"
- 当模型表字段特别多的时候,并且并不是所有的字段都需要展示到前端给用户观看
from django.forms import ModelForm class BaseModelForm(ModelForm): # 自定义字段是否需要加额外属性的配置 exclude_bootstrap = [] def __init__(self,*args,**kwargs): super().__init__(*args,**kwargs) # print(self.fields) # OrderedDict([('hostname', <django.forms.fields.CharField object at 0x10c99c198>)]) # 给所有的字段加class属性 for k,field_obj in self.fields.items(): if k in self.exclude_bootstrap: continue # 排除在外不添加样式 field_obj.widget.attrs['class'] = 'form-control'
- 项目表需要额外添加字段
# 线上服务器地址 path = models.CharField(verbose_name='线上地址',max_length=64) # 关联服务器 """ 一个项目可以跑在多个服务器上 一个服务器其实也可以跑多个项目 (公司服务器不够的时候 可以混用) """ servers = models.ManyToManyField(to='Server',verbose_name='关联服务器')
- 项目展示页面额外展示当前两个字段
ModelForm使用
from django.forms import ModelForm class BaseModelForm(ModelForm): class Meta: model = models.Userinfo fields = '__all__' # exclude = ['uid'] # 排除在外 # 展示标签 form_obj = BaseModelForm() # 校验数据 form_obj = BaseModelForm(data=request.POST) form_obj.is_valid() # 新增数据 form_obj.save() # 展示待编辑数据 form_obj = BaseModelForm(instance=edit_obj) # 编辑数据 form_obj = BaseModelForm(data=request.POST,instance=edit_obj) form_obj.is_valid() form_obj.save() """新增和编辑调用的都是save方法,两者通过instance来区分"""
项目示例
# s13_deploy/app01/myforms/base.py from django.forms import ModelForm class BaseModelForm(ModelForm): def __init__(self,*args,**kwargs): super().__init__(*args,**kwargs) for k,field_obj in self.fields.items(): field_obj.widget.attrs['class'] = 'form-control' # s13/_eploy/app01/myforms/server.py from app01.myforms.base import BaseModelForm from app01 import models class ServerModelForm(BaseModelForm): # exclude_bootstrap = ['hostname'] class Meta: model = models.Server fields = '__all__' # 所有字段 # s13_deploy/app01/templates/form.html {% extends 'base.html' %} {% block content %} <form class="form-horizontal" method="post" novalidate> {# 点击按钮为post请求 novalidate禁止前端渲染提示 #} {% csrf_token %} {% for foo in form_obj %} <div class="form-group"> <label for="{{ foo.id_for_label }}" class="col-sm-2 control-label">{{ foo.label }}</label> {# label为verbose_name #} <div class="col-sm-10"> {{ foo }} {# input框,这么写为了对应后端ModelForm类获取数据 #} <span style="color: red">{{ foo.errors.0}}</span> </div> </div> {% endfor %} <div class="form-group"> <div class="col-sm-offset-2 col-sm-10"> <button type="submit" class="btn btn-success">提交</button> </div> </div> </form> {% endblock %} # s13_deploy/app01/views/server.py # 服务器相关逻辑 from django.shortcuts import HttpResponse,render,redirect from app01 import models from django.http import JsonResponse from app01.myforms.server import ServerModelForm def server_add(request): # 1 先生成一个modelform的空对象 form_obj = ServerModelForm() if request.method == 'POST': # 3 检验数据 form_obj = ServerModelForm(data=request.POST) # 判断是否合法 if form_obj.is_valid(): # 保存诗句 form_obj.save() # 跳转到服务器的展示页 # return redirect('/server/list/') # 可以写路径 return redirect('server_list') # 可以写别名 # 2 将该对象传给html文件 return render(request,'form.html',locals()) def server_edit(request,edit_id): edit_obj = models.Server.objects.filter(pk=edit_id).first() # 1 生成待编辑的modelform对象 form_obj = ServerModelForm(instance=edit_obj) if request.method == 'POST': # 编辑操作 如何区分编辑还是新增就看有没有instance参数 form_obj = ServerModelForm(data=request.POST,instance=edit_obj) # 必须加instance,否则为新增 if form_obj.is_valid(): form_obj.save() return redirect('server_list') return render(request,'form.html',locals()) # s13/deploy/app01/models.py from django.db import models class Server(models.Model): # 服务器表 hostname = models.CharField(verbose_name='主机名',max_length=64) # s13_deploy/s13_deploy/urls.pyfrom django.urls import path,re_path from app01.views import server,project urlpatterns = [ # 服务器相关url path('server/list/', server.server_list,name='server_list'), path('server/add/', server.server_add,name='server_add'), re_path('server/edit/(?P<edit_id>\d+)', server.server_edit,name='server_edit'), re_path('server/delete/(?P<delete_id>\d+)', server.server_delete,name='server_delete'), ]
重定向
"""redirect括号内既可以直接书写url也可以写反响解析的别名但是不能有无名和有名分组的情况,如果有则还需要借助于reverse方法""" redirect('/index/') redirect('index')
删除二次确认及页面刷新
二次确认你可以直接使用原生的BOM操作,也可以借助于第三方插件是页面更加的好看,针对删除之后页面的刷新,最好不要直接刷新因为那样没有考虑到分页的情况,简易你使用DOM操作的方式刷新页面,能够保证在分页的情况下也能合理展示
""" 1.将项目中所使用到的modelform单独存储 2.整合所有modelform相同的代码 抽成基类 3.在modelform中自定义一个控制字段是否需要加bootstrap样式的功能 4.项目表新增远程服务器地址以及关联的服务器 """