zoukankan      html  css  js  c++  java
  • 代码发布3 gitpython模块, 代码发布概述图, 服务器管理, 项目管理, 发布任务管理, ModelForm使用, 重定向

    gitpython模块

    能够python代码操作git仓库

    安装

    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("
    ")
    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("
    ")
            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)

    利用modelform实现服务器表的增删改查

    所有的项目大部分的功能都是由最简单的增删改查组成,是整个业务逻辑的基础

    并且只需要认认真真的写一个增删改查即可,后续所有的直接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')

    直接搬砖操作,CV搞定

    代码的优化

    代码的优化一定是在你把功能实现之后再去优化(先努力实现再考虑优化)

    • 将所有的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.项目表新增远程服务器地址以及关联的服务器
    """
  • 相关阅读:
    基于JavaMail开发邮件发送器工具类
    微服务架构
    图像识别
    Manacher
    左偏树
    虚树
    动态树(Link-Cut Tree)
    Splay
    扩展中国剩余定理(EXCRT)
    K-D树
  • 原文地址:https://www.cnblogs.com/ludingchao/p/12709005.html
Copyright © 2011-2022 走看看