代碼發布流程四


  • 代碼發布整體工作流程


    代碼發布這個功能可以基於很多方式很多語言來實現

    我們這里主要用的是python相關的知識點來完成的,大體邏輯流程都是大差不差的

    額外補充:p2p(比特流技術),為了減輕服務器的壓力,將所有人即是下載者又是資源的上傳者

  • 服務器表的增刪改查

    我們從頭到位將增刪改查自己實現了一遍,目的是為了搭建項目增刪改查基本業務邏輯,方便后續其他表的操作

    modelform使用

    from django.forms import ModelForm
    
    class MyModelForm(ModelForm):
      class Meta:
        	model = models.UserInfo
          fields = '__all__'  # 前端展示用戶表所有的字段
          exclude = ['id']  # 排除id字段 不展示到前端
    
    # 渲染標簽
    form_obj = MyModelForm()
    # 校驗數據
    form_obj = MyModelForm(data=request.POST)
    # 新增數據
    form_obj.save()
    # 編輯數據 渲染標簽
    form_obj = MyModelForm(instance=edit_obj)
    # 修改數據庫中的數據
    form_obj = MyModelForm(instance=edit_obj,data=request.POST)
    form_obj.save()
    

    針對數據的刪除功能,一般情況下都需要有一個二次確認的操作

    我們是直接利用BOM操作里面的confirm確認框實現的

    你還可以借助於第三方插件效果更好一點比如sweetalert插件

  • 項目表的增刪改查

    直接拷貝服務器表所有的代碼,修改變量名即可

  • 項目優化

    將modelform單獨放到一個文件夾中

    然后再將各個模型表對應的modelform中相同的代碼抽取出來形成基類

    給項目表再增兩個字段

    線上項目地址、關聯服務器

  • 發布任務

    由於發布任務是針對項目的,所以為了之后新增任務的時候不需要自己選擇項目,所以我們將發布任務做成項目表中的一個字段,點擊該字段跳轉到該項目對應的所有發布紀錄中,之后在該發布紀錄頁面上開設新增按鈕,將當前項目的主鍵值傳遞到后端,這樣的話新增任務就無需自己選擇項目了

內容概要

  • 發布任務單新增頁面

  • 發布流程前端實時展示

任務列表的展示為了更加人性化,可以增加當前項目的項目名和環境

# 先簡單的手動處理數據 完成添加功能
from app01.myforms.base import BaseModelForm
from app01 import models


class TaskModelForm(BaseModelForm):
    class Meta:
        model = models.DeployTask
        fields = '__all__'
        # 項目唯一標識 應該是自動生成的無需用戶填寫
        # 項目由於已經帶了主鍵值了 所以也無需用戶填寫
        # 創建的任務單默認狀態就是待發布 所以也無需展示
        exclude = ['uid','project','status']

    def __init__(self,project_id,*args,**kwargs):
        super().__init__(*args,**kwargs)
        self.project_id = project_id

    def save(self, commit=True):
        # 添加數據
        self.instance.uid = 'sadjasdj'
        self.instance.project_id = self.project_id
        # 調用父類的save方法保存數據
        super().save(commit=True)

接下來,我們針對任務的添加頁面,單獨開設一個html

並在該html頁面上划分三塊區域展示不同的信息

  • 當前任務關聯的項目基本信息展示

  • 基本配置

  • 腳本書寫

針對四個鈎子腳本,我們想要實現可以保存的功能

# 初始化字段
    def __init__(self,project_obj,*args,**kwargs):
        super().__init__(*args,**kwargs)
        self.project_obj = project_obj
        # 初始化選擇框內容
        self.init_hook()

    def init_hook(self):
        # 給所有的下拉框先添加一個 請選擇選項
        # <option value="0">請選擇</option>  (0,'請選擇')
        self.fields['before_download_select'].choices = [(0,'請選擇')]
        self.fields['after_download_select'].choices = [(0,'請選擇')]
        self.fields['before_deploy_select'].choices = [(0,'請選擇')]
        self.fields['after_deploy_select'].choices = [(0,'請選擇')]

創建表存儲用戶填寫的想要保存的模版信息

class HookTemplate(models.Model):
    """保存鈎子腳本"""
    title = models.CharField(verbose_name='標題',max_length=32)
    content = models.TextField(verbose_name='腳本內容')
    # 我想實現鈎子與鈎子之間模版互不影響
    hook_type_choices = (
        (2,'下載前'),
        (4,'下載后'),
        (6,'發布前'),
        (8,'發布后')
    )
    hook_type = models.IntegerField(verbose_name='鈎子類型',choices=hook_type_choices)

什么時候需要操作上述表保存數據???

判斷依據是用戶是否點擊了checkbox按鈕

在我們重寫的save方法中 做判斷!!!

# 判斷用戶是否點擊checkbox
        if self.cleaned_data.get("before_download_template"):
            # 獲取模版名稱
            title = self.cleaned_data.get("before_download_title")
            # 獲取腳本內容
            content = self.cleaned_data.get("before_download_script")
            # 保存到表中
            models.HookTemplate.objects.create(
                title=title,
                content=content,
                hook_type=2
            )

        if self.cleaned_data.get("after_download_template"):
            # 獲取模版名稱
            title = self.cleaned_data.get("after_download_title")
            # 獲取腳本內容
            content = self.cleaned_data.get("after_download_script")
            # 保存到表中
            models.HookTemplate.objects.create(
                title=title,
                content=content,
                hook_type=4
            )

        if self.cleaned_data.get("before_deploy_template"):
            # 獲取模版名稱
            title = self.cleaned_data.get("before_deploy_title")
            # 獲取腳本內容
            content = self.cleaned_data.get("before_deploy_script")
            # 保存到表中
            models.HookTemplate.objects.create(
                title=title,
                content=content,
                hook_type=6
            )

        if self.cleaned_data.get("after_deploy_template"):
            # 獲取模版名稱
            title = self.cleaned_data.get("after_deploy_title")
            # 獲取腳本內容
            content = self.cleaned_data.get("after_deploy_script")
            # 保存到表中
            models.HookTemplate.objects.create(
                title=title,
                content=content,
                hook_type=8
            )

數據庫模版名稱前端展示,以及用戶點擊實時獲取模版內容

    def init_hook(self):
        # 給所有的下拉框先添加一個 請選擇選項
        # <option value="0">請選擇</option>  (0,'請選擇')

        before_download = [(0,'請選擇')]
        # 還應該去數據庫中查詢是否有對應的模版名稱
        extra_list = models.HookTemplate.objects.filter(hook_type=2).values_list('pk','title')
        before_download.extend(extra_list)
        self.fields['before_download_select'].choices = before_download

        after_download = [(0,'請選擇')]
        extra_list = models.HookTemplate.objects.filter(hook_type=4).values_list('pk', 'title')
        after_download.extend(extra_list)
        self.fields['after_download_select'].choices = after_download

        before_deploy = [(0,'請選擇')]
        extra_list = models.HookTemplate.objects.filter(hook_type=6).values_list('pk', 'title')
        before_deploy.extend(extra_list)
        self.fields['before_deploy_select'].choices = before_deploy

        after_deploy = [(0,'請選擇')]
        extra_list = models.HookTemplate.objects.filter(hook_type=8).values_list('pk', 'title')
        after_deploy.extend(extra_list)
        self.fields['after_deploy_select'].choices = after_deploy

前端用戶點擊模版動態展示內容

給前端所有的select標簽綁定文本域變化事件(change事件)

<script>
        // 直接給hooks類標簽內所有的select綁定事件
        $('.hooks').find('select').change(function () {
            {#alert($(this).val())  獲取用戶輸入的模版主鍵值 #}
            var $that = $(this);
            // 朝后端發送請求 獲取對應的腳本內容
            $.ajax({
                url:'/hook/template/'+$that.val()+'/',
                type:'get',
                dataType:'JSON',
                success:function (args) {
                    // 獲取腳本內容 渲染到對應下拉框下面的textarea框中
                    {#alert(args.content)#}
                    // 標簽查找
                    $that.parent().parent().next().find('textarea').val(args.content);
                }

            })
        })
    </script>

優化

  • 用戶一旦點擊了checkbox按鈕,那么就必須填寫模版名稱

    # 鈎子函數 全局鈎子 局部鈎子
    # 全局鈎子 
        # 全局鈎子校驗用戶是否點擊checkbox
        def clean(self):
            if self.cleaned_data.get('before_download_template'):
                # 獲取用戶輸入的模版名稱 判斷是否有值
                title = self.cleaned_data.get("before_download_title")
                if not title:
                    # 展示提示信息
                    self.add_error('before_download_title','請輸入模版名稱')
    
            if self.cleaned_data.get('after_download_template'):
                # 獲取用戶輸入的模版名稱 判斷是否有值
                title = self.cleaned_data.get("after_download_title")
                if not title:
                    # 展示提示信息
                    self.add_error('after_download_title','請輸入模版名稱')
    
            if self.cleaned_data.get('before_deploy_template'):
                # 獲取用戶輸入的模版名稱 判斷是否有值
                title = self.cleaned_data.get("before_deploy_title")
                if not title:
                    # 展示提示信息
                    self.add_error('before_deploy_title','請輸入模版名稱')
    
            if self.cleaned_data.get('after_deploy_template'):
                # 獲取用戶輸入的模版名稱 判斷是否有值
                title = self.cleaned_data.get("after_deploy_title")
                if not title:
                    # 展示提示信息
                    self.add_error('after_deploy_title','請輸入模版名稱')
    

    注意,前端需要預留一部分內容展示錯誤信息否則會出現布局錯亂的問題

    <div class="form-group" style="height: 60px">
                                            <div class="col-sm-3">
                                                <div class="checkbox">
    
                                                    <label for="">{{ form_obj.after_deploy_template }}保存模版</label>
                                                </div>
                                            </div>
                                            <div class="col-sm-9">
                                                {{ form_obj.after_deploy_title }}
                                                <span style="color: red">{{ form_obj.after_deploy_title.errors.0 }}</span>
                                            </div>
    
                                        </div>
    

    發布任務

    Ps:靜態文件可以全局也可以在局部

    靜態文件配置

    # 1 配置文件中直接配置
    STATICFILES_DIRS = [
      os.path.join(BASE_DIR,'static1'),
      os.path.join(BASE_DIR,'static2'),
    ]
    
    # 2 模版語法直接配置
    {% load staticfiles %}
    <script src="{% static 'js/go.js' %}"></script>
    
    <script>
            // 由於ws和diagram需要在其他函數內使用 所以定義成全局變量
            var ws;
            var diagram;
    
            function initWebSocket() {
                ws = new WebSocket('ws://127.0.0.1:8000/publish/{{ task_obj.pk }}/');
    
                // 一旦服務端有消息 會自動觸發onmessage方法
                ws.onmessage = function (args) {
                    // args.data
                    var res = JSON.parse(args.data);
                    if (res.code==='init'){
                        // 操作gojs渲染圖表
                        diagram.model = new go.TreeModel(res.data)
                    }
                }
            }
    
            function initTable() {
                var $ = go.GraphObject.make;
                diagram = $(go.Diagram, "diagramDiv", {
                    layout: $(go.TreeLayout, {
                        angle: 0,
                        nodeSpacing: 20,
                        layerSpacing: 70
                    })
                });
                // 生成一個節點模版
                diagram.nodeTemplate = $(go.Node, "Auto",
                    $(go.Shape, {
                        figure: "RoundedRectangle",
                        fill: 'yellow',
                        stroke: 'yellow'
                    }, new go.Binding("figure", "figure"), new go.Binding("fill", "color"), new go.Binding("stroke", "color")),
                    $(go.TextBlock, {margin: 8}, new go.Binding("text", "text"))
                );
                // 生成一個箭頭模版
                diagram.linkTemplate = $(go.Link,
                    {routing: go.Link.Orthogonal},
                    $(go.Shape, {stroke: 'yellow'}, new go.Binding('stroke', 'link_color')),
                    $(go.Shape, {toArrow: "OpenTriangle", stroke: 'yellow'}, new go.Binding('stroke', 'link_color'))
                );
                // 數據集合  以后替換ajax請求   注意使用key和parent來規定箭頭的指向
                {#var nodeDataArray = [#}
                {#    {key: "start", text: '開始', figure: 'Ellipse', color: "lightgreen"},#}
                {#    {key: "download", parent: 'start', text: '下載代碼', color: "lightgreen", link_text: '執行中...'},#}
                {#    {key: "compile", parent: 'download', text: '本地編譯', color: "lightgreen"},#}
                {#    {key: "zip", parent: 'compile', text: '打包', color: "red", link_color: 'red'},#}
                {#    {key: "c1", text: '服務器1', parent: "zip"},#}
                {#    {key: "c11", text: '服務重啟', parent: "c1"},#}
                {#    {key: "c2", text: '服務器2', parent: "zip"},#}
                {#    {key: "c21", text: '服務重啟', parent: "c2"},#}
                {#    {key: "c3", text: '服務器3', parent: "zip"},#}
                {#    {key: "c31", text: '服務重啟', parent: "c3"},#}
                {#];#}
                {#diagram.model = new go.TreeModel(nodeDataArray);#}
                // 動態控制節點顏色變化   后端給一個key值 即可查找圖表並修改
    
                /*
                var node = diagram.model.findNodeDataForKey("zip");
                diagram.model.setDataProperty(node, "color", "lightgreen");
                }
                */
    
            }
        
            // 頁面加載完畢 先自動執行兩個函數 給全局變量賦值
            $(function () {
                initWebSocket();
                initTable()
            });
    
            function createDiagram() {
                ws.send('init')
            }
    
    
    
        </script>
    


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM