快速實現增刪改查組件(起步階段!!!)

来源:http://www.cnblogs.com/haiyan123/archive/2017/12/16/8045303.html
-Advertisement-
Play Games

一、相關知識點回顧 1、什麼是反射? 可以用字元串的方式去訪問對象的屬性 2、反射有四種方法? 3、創建ModelForm的兩種方式 二、具體流程以及相關知識點 1、路由系統 讓url對應視圖,這時的視圖可以是一個元組,元組的裡面放三個參數,第一個是個列表,這兩種表示方式都是一樣的,用那種都行 na ...


一、相關知識點回顧

    1、什麼是反射?

    可以用字元串的方式去訪問對象的屬性

 2、反射有四種方法?

hasattr(object,name):判斷一個對象是不是有name屬性或者方法
getattr:獲取對象的屬性或者方法,  需要註意的是,如果返回的是對象的方法,返回出來的是對象的記憶體地址, 如果需要運行這個方法,可以在後面添加一對()
setattr:給對象的屬性賦值,如果屬性不存在,先創建後賦值
delattr:刪除該對象指定的一個屬性

 3、創建ModelForm的兩種方式

# 方式一定義ModelForm
   class TestModelForm(ModelForm):
         class Meta:
             model = self.model_class
             fields = "__all__"
        
   方式二定義
  Meta = type("Meta", (object,), {"model": self.model_class, "fields": "__all__"})
  TestModelForm = type("TestModelForm", (ModelForm,), {"Meta": Meta})

二、具體流程以及相關知識點

1、路由系統

讓url對應視圖,這時的視圖可以是一個元組,元組的裡面放三個參數,第一個是個列表,這兩種表示方式都是一樣的,用那種都行

namespace的用法如下

v =>  ([],None,None)  namespace(是第三個參數),用於區分相同name的url,通過namespace為url添加一個首碼

 如圖:

namespace

流程:

首先創建三個應用
      app01
      app02
      strak

1、一旦運行的時候都會去執行admin.py ,現在我們讓你開始執行stark.py 文件,加上下麵的這些(參考的是admin的源碼,在每一個admin文件的裡面點擊進入)

from django.utils.module_loading import autodiscover_modules

    class StarkConfig(AppConfig):
        name = 'stark' #應用名稱

        def ready(self):
            autodiscover_modules('stark')   #在應用中創建的py文件和這個名字一樣

切記一定要在sessings中配置一下:

'app02.apps.App02Config',
'stark.apps.StarkConfig',

2、然後再每個應用下麵也創建一個stark.py的文件
       這樣就像admin一樣了,就開始執行site.redister了


3、這時候還沒有site呢,需要自己實例化一個site
       在應用下創建一個service的文件夾,再創建一個v1.py文件,在裡面寫代碼

4、在stark裡面註冊

需要註意的是:

v1.site.register(models.UserInfo)   
->  執行 StackConfig的 changelist_view方法/add_view....
        
        
    
class UserInfoConfig(v1.StarkConfig):
        def changelist_view(self,request,*args,**kwargs):
            return HttpResponse('你猜我是誰?')

v1.site.register(models.UserInfo,UserInfoConfig)

---> 優先查看自己config中是否存在方法,不存在則執行基類 StackConfig的 changelist_view方法/add_view....

如圖:

5、註冊完成之後走urls。仿照admin的urls.。。。v1.site.urls
6、完了在v1.py中寫代碼

class StarkSite(object):
    def __init__(self):
        self._registry ={}  #放置處理請求對應關係
        '''
        _registry = {
                    models.Role: StarkConfig(models.Role,v1.site),
                    models.UserInfo: StarkConfig(models.UserInfo,v1.site)
                    models.UserType: StarkConfig(models.UserType,v1.site)
                    models.Article: StarkConfig(models.Article,v1.site)
                }
        '''
    def register(self,model_class,stark_config_class=None):
        if not stark_config_class:
            '''stark_config_class是類對象,如果沒有這個類就重新賦值,去執行StarkConfig'''
            stark_config_class = StarkConfig
        self._registry[model_class] = stark_config_class(model_class,self)
        #如果用戶自己傳進去類了,就用自己的,自己的需要繼承StarkConfig。如果自己沒有就找基類的,自己有就用自己的

    def get_urls(self):
        url_list = []
        for model_calss,stark_config_obj in self._registry.items():
            app_name = model_calss._meta.app_label#應用名稱
            model_name = model_calss._meta.model_name#表的名稱
            cur_url = url(r'^{0}/{1}/'.format(app_name,model_name),(stark_config_obj.urls,None,None))
            #這是的stark_config_obj是上面StarkConfig的實例對象。stark_config_obj.urls就會去找上面類的urls
            url_list.append(cur_url)
        return url_list
    @property #吧方法當屬性來用
    def urls(self):
        return (self.get_urls(),None,'stark')  #第三個參數是namesapce

 動態生成類名和應用名圖示:

 

在v1裡面有兩個類

- StarkConfig,用於為每一個類生成URL對應關係,並編寫視圖函數處理用戶請求。
            [
                ^$  -> self.changelist_view
                ^add/$  -> self.add_view
                ^delete/$  -> self.delete_view
                ^change/$  -> self.dchange_view
            ]
            
        - StarkSite    
        是一個容器,用於放置處理請求對應關係。
                    {
                        model.UserInfo: UserInfoConfig(model.UserInfo,self),
                        model.UserType: StarkConfig(model.UserType,self),
                    }    

 具體來寫:當然前面的StarkSite類已經寫過了,那我們來看看StarkConfig這個類

以下的功能實現都是在StarkConfig這個類裡面的

功能實現一:展示頁面,讓頁面上動態顯示表格

class StarkConfig(object):
    list_display = []
    def __init__(self, model_class, site):
        self.model_class = model_class
        self.site = site
    def change_list_views(self,request,*args,**kwargs):
        data_list = self.model_class.objects.all()
        '''展示th的信息'''
        head_list = []
        for field_name in self.list_display:
            if isinstance(field_name,str):
                verbose_name = self.model_class._meta.get_field(field_name).verbose_name
            else:
                verbose_name = field_name(self,is_header=True)
            # yield {"verbose_name":verbose_name}
            head_list.append(verbose_name)

        '''展示td的信息'''

        # [["id","name"],["id","name"],["id","name"],]
        new_data_list = []
        for row in data_list:
            temp = []
            for field_name in self.list_display:
                if isinstance(field_name,str):
                    #如果是字元串類型的就是用getattr的方式,因為對象不能.字元串
                    val = getattr(row,field_name)
                else:
                    val = field_name(self,row)
                temp.append(val)
                # yield {"val":val}
            new_data_list.append(temp)
        return render(request, "stark/change_list_views.html", {"data_list":new_data_list,"head_list":head_list})

在stark.py 中

strak.py
    print("sssss6666666")
    from app01 import models
    from stark.service import v1
    from django.utils.safestring import mark_safe
    class UserInfoConfig(v1.StarkConfig):
        def checkbox(self,obj=None,is_header=False):
            if is_header:
                return "選擇"
            return mark_safe("<input type='checkbox' name='zzzz' value='%s'/>"%obj.id)

        def edit(self,obj=None,is_header=False):
            if is_header:
                return "操作"
            return mark_safe("<a href='edit/%s'>編輯</a>"%obj.id)
        list_display = [checkbox,"id","name",edit]

    v1.site.register(models.UserInfo,UserInfoConfig)
    v1.site.register(models.Role,UserInfoConfig)
    v1.site.register(models.UserType)

 功能二:當然我們現在把按鈕是自己定製的,有與編輯,刪除等都是我們很常用的,所以我們可以搞成預設的。在StarkConfig類里寫

 # ===============吧刪除,編輯,覆選框設置預設按鈕==================

    def checkbox(self,obj=None,is_header=False):
        if is_header:
            return "選擇"
        return mark_safe("<input type='checkbox' name='zzzz' value='%s'/>"%obj.id)

    def edit(self,obj=None,is_header=False):
        if is_header:
            return "操作"
        return mark_safe("<a href='%s'>編輯</a>"%(self.get_change_url(obj.id),))

    def delete(self,obj=None,is_header=False):
        if is_header:
            return "刪除"
        #動態跳轉路徑,反向解析,因為每次都要用到,我們可以吧它封裝到一個函數
        return mark_safe("<a href='%s'>刪除</a>"%self.get_delete_url(obj.id))

    #做預設的刪除和編輯。對這個方法重寫的時候可以吧許可權管理加進去,
    # 當它都什麼許可權的時候顯示什麼按鈕。
    def get_list_display(self):
        data = []
        if self.list_display:
            data.extend(self.list_display) #在新的列表裡面吧list_display擴展進來
            data.append(StarkConfig.edit)  #因為是預設的,直接在類裡面去調用edit
            data.append(StarkConfig.delete)
            data.insert(0,StarkConfig.checkbox)
        return data

 功能三:預設顯示添加按鈕

 show_add_btn = True
    # ======這個方法可自定製(如果把show_add_btn設置為False就不會顯示添加按鈕)=====
    def get_show_add_btn(self):
        return self.show_add_btn

 功能四:當點擊編輯,刪除,添加按鈕的時候的跳轉路徑,動態生成

return render(request, "stark/change_list_views.html",{"add_url":self.get_add_url(),"show_add_btn":self.get_show_add_btn()})

 利用反向解析reverse

 # =================url相關,reverse反向解析=============
    def get_change_url(self,nid):
        name = "stark:%s_%s_change"%(self.model_class._meta.app_label,self.model_class._meta.model_name)
        edit_url = reverse(name,args=(nid,))  #反向解析只要找到他的name屬性,就會找到他對應的路徑
        return edit_url

    def get_add_url(self):
        name = "stark:%s_%s_add" % (self.model_class._meta.app_label, self.model_class._meta.model_name)
        edit_url = reverse(name)
        return edit_url

    def get_delete_url(self, nid):
        name = "stark:%s_%s_delete" % (self.model_class._meta.app_label, self.model_class._meta.model_name)
        edit_url = reverse(name,args=(nid,))
        return edit_url

    def get_list_url(self):
        name = "stark:%s_%s_changelist" % (self.model_class._meta.app_label, self.model_class._meta.model_name)
        edit_url = reverse(name)
        return edit_url

 功能五:添加,刪除,編輯功能(利用MOdelForm)

  model_form_class=None
    def get_model_form_class(self):
        if self.model_form_class:   #如果自己定製了就用自己的,在這就什麼也不返回了,如果沒有自己定義就返回預設的這個Form
            return self.model_form_class
        # 方式一定義ModelForm
        # class TestModelForm(ModelForm):
        #     class Meta:
        #         model = self.model_class
        #         fields = "__all__"
        # return TestModelForm
        # 方式二定義
        Meta = type("Meta", (object,), {"model": self.model_class, "fields": "__all__"})
        TestModelForm = type("TestModelForm", (ModelForm,), {"Meta": Meta})
        return TestModelForm
def add_views(self,request,*args,**kwargs): model_form_class = self.get_model_form_class() if request.method=="GET": form = model_form_class() return render(request,"stark/add_view.html",{"form":form}) else: form = model_form_class(request.POST) if form.is_valid(): form.save() return redirect(self.get_list_url()) else: return render(request, "stark/add_view.html", {"form": form}) def delete_view(self, request,nid, *args, **kwargs): self.model_class.objects.filter(pk=nid).delete() return redirect(self.get_list_url()) def change_views(self, request,nid, *args, **kwargs): model_form_class = self.get_model_form_class() obj = self.model_class.objects.filter(pk=nid).first() if not obj: return redirect(self.get_list_url()) if request.method == "GET": form = model_form_class(instance=obj) return render(request, "stark/edit_view.html", {"form": form}) else: form = model_form_class(data=request.POST,instance=obj) if form.is_valid(): form.save() return redirect(self.get_list_url()) else: return render(request, "stark/edit_view.html", {"form": form})

 功能六:額外擴展url

  # =============路由系統,對應相應的視圖函數=====================
    def get_urls(self):
        app_model_name = (self.model_class._meta.app_label,self.model_class._meta.model_name)
        all_url = [
            url(r'^$', self.change_list_views,name="%s_%s_changelist"%app_model_name),
            url(r'^add/$', self.add_views,name="%s_%s_add"%app_model_name),
            url(r'^(\d+)/delete/$', self.delete_view,name="%s_%s_delete"%app_model_name),
            url(r'^(\d+)/change/$', self.change_views,name="%s_%s_change"%app_model_name),
        ]
        all_url.extend(self.extra_urls())
        return all_url

    # ===========額外擴展url(用戶可以進行隨意擴展)==========
    def extra_urls(self):
        return []

    @property
    def urls(self):
        return self.get_urls()

三、使用

#!usr/bin/env python
# -*- coding:utf-8 -*-
print("sssss6666666")
from app01 import models
from django.conf.urls import url
from stark.service import v1
from django.shortcuts import render,HttpResponse,redirect
from django.forms import ModelForm
class UserInfoConfig(v1.StarkConfig):
    # 1、
    list_display = ["id","name","email"]
    # list_display = []
   # 2、
    def extra_urls(self):
        url_list =[
            url(r'^xxxx/$',self.func),
        ]
        return url_list

    def func(self,request):
        return HttpResponse("我是額外添加的路徑哦....")
    # 3、
    # show_add_btn=False   #預設是True的,如果不讓顯示添加按鈕可以自定製

    # 4、
    def get_model_form_class(self):
        class MyModelForm(ModelForm):
            class Meta:
                model = self.model_class
                fields = "__all__"
                error_messages={
                    "name":{"required":"用戶名不能為空"},
                    "email":{"invalid":"郵箱格式不正確"}
                }
        return MyModelForm
    # 5、
    def delete_view(self, request,nid, *args, **kwargs):
        if request.method=="GET":
            return render(request,"stark/delete_view.html",{"quxiao_url":self.get_list_url()})
        else:
            self.model_class.objects.filter(pk=nid).delete()
            return redirect(self.get_list_url())
v1.site.register(models.UserInfo,UserInfoConfig)

===================================================
class RoleConfig(v1.StarkConfig): list_display = ["id","name"] # list_display = [] def extra_urls(self): url_list =[ url(r'^aaaa/$',self.func), ] return url_list def func(self,request): return HttpResponse("我是額外添加的路徑哦....") # show_add_btn=False #預設是True的,如果不讓顯示添加按鈕可以自定製 def get_model_form_class(self): class MyModelForm(ModelForm): class Meta: model = self.model_class fields = "__all__" error_messages={ "name":{"required":"用戶名不能為空"}, } return MyModelForm v1.site.register(models.Role,RoleConfig) v1.site.register(models.UserType)
======================================================
class HostConfig(v1.StarkConfig): def ip_port(self, obj= None,is_header=False): if is_header: #如果是True就返回的是th的,預設就是True return "自定義列" return "%s_%s"%(obj.id,obj.port,) #當是False的時候就返回的是td的 list_display = ["id","name","ip","port",ip_port] # =====擴展一個url路徑====== def extra_urls(self): url_list = [ url(r'^report/$', self.report_view), ] return url_list def report_view(self,request): return HttpResponse("<h3>這是我給報表另外添加的一個路徑</h3>") v1.site.register(models.Host,HostConfig)

四、總結:

註意:如果是在應用裡面建的static文件,是不用再settings裡面配置的,就可以用
    需要知道的知識點
     1、for model_calss,stark_config_obj in self._registry.items():
            app_name = model_calss._meta.app_label#應用名稱
            model_name = model_calss._meta.model_name#表的名稱
            self.model_class._meta.get_field(field_name).verbose_name  #得到欄位的verbose_name
            
    2、   if isinstance(field_name,str):
                    #如果是字元串類型的就是用getattr的方式,因為對象不能.字元串
                    val = getattr(row,field_name)

    3、   for field_name in self.list_display:
                if isinstance(field_name,str):
                    #如果是字元串類型的就是用getattr的方式,因為對象不能.字元串
                    val = getattr(row,field_name)
                else:  #如果不是字元串傳進來的就是函數,所以得加括弧調用函數
                    val = field_name(field_name,row)
                temp.append(val)
            new_data_list.append(temp)  
            
    4、吧方法當屬性來用
    @property
    def urls(self):
        return self.get_urls()

一個小知識:
    1、什麼時候加括弧,什麼時候不加括弧
       當需要一個返回值的時候,就去執行函數,加括弧
       當你不需要返回什麼,直接告訴它函數名,讓他去找這個函數名。就不用加括弧
補充:用bootstrap修改樣式

 1、include:用include直接把單獨的標簽可以引入到html中。目的是減少代碼的冗餘

{% include "stark/form.html" %}

 

stark/form.html
<form method="post"  class="form-horizontal" novalidate>
    {% csrf_token %}
    {% for field in form %}
        <div class="col-sm-6">
            <div class="form-group">
                <label for="inputEmail3" class="col-sm-2 control-label">{{ field.label }}</label>
                <div class="col-sm-10">
                    {{ field }}
                    {{ field.errors.0 }}
                </div>
            </div>
        </div>
    {% endfor %}
    <div class="col-sm-offset-11 col-sm-1">
        <input type="submit" class="btn btn-primary" value="提交">
    </div>
</form>

css樣式

.form-horizontal input[type="text"],input[type='email'],input[type='password'],input[type='checkbox'],input[type='number'],select,textarea{
            display: block;
            width: 100%;
            height: 34px;
            padding: 6px 12px;
            font-size: 14px;
            line-height: 1.42857143;
            color: #555;
            background-color: #fff;
            background-image: none;
            border: 1px solid #ccc;
            border-radius: 4px;
            -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
            box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
            -webkit-transition: border-color ease-in-out .15s, -webkit-box-shadow ease-in-out .15s;
            -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
            transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
        }

補充二:需要優化的導入靜態文件的方式

{% load staticfiles %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width">
    <title>Title</title>
    <link rel="stylesheet" href="{% static '/bootstrap-3.3.7-dist/css/bootstrap.css'%} ">
    <link rel="stylesheet" href="{% static '/css/stark_form.css' %}">
</head>
<body>
<h3>添加頁面</h3>
{% include "stark/form.html" %}
</body>
</html>

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 【學習實踐用】 後臺:nodejs 前臺:vue2 式樣:uiKit 圖表:echarts 存儲:json文件 打包:webpack 功能:調查問卷的添加,修改,投票以及結果查看 ...
  • 在ios或android如果直接用webview在打開H5鏈接例如: 打開:http://localhost:8080/#/answer?id=1509335039582001 會變成 http://localhost:8080/ 造成根本打開不了想要的頁面(微信中獲取網頁授權的時候有#號也會有問題 ...
  • Js阻塞機制,跟Js引擎的單線程處理方式有關,每個window一個JS線程。所謂單線程,在某個特定的時刻只有特定的代碼能夠被執行,並阻塞其它的代碼。 由於瀏覽器是事件驅動的(Event driven),因此瀏覽器中很多行為是非同步(Asynchronized)的,很容易有事件被同時或者連續觸發。當非同步 ...
  • accept表示打開的系統文件目錄;capture表示的是系統所捕獲的預設設備,camera:照相機;camcorder:攝像機;microphone:照相+攝像。 如果不加上capture,則只會顯示相應的,例如上述三種依次是:拍照或圖庫,錄像或圖庫,錄像或拍照或圖庫,加上capture之後不會調 ...
  • javascrpit面向對象之綜合 這一章是對前幾章的一個總結,通過一個案例來綜合認識javascript面向對象的基本用法 需求: 幾乎所有的web應用都需要保存數據一些到本地,那麼我們就來做一個數據儲存器吧。 詳細需求需求: 當本地儲存有數據時,取用本地的數據,沒有時使用預設的數據 判斷本地的數 ...
  • REST即表述性狀態傳遞(英文:Representational State Transfer,簡稱REST)是Roy Fielding博士在2000年他的博士論文中提出來的一種軟體架構風格 ...
  • HP-Socket是一套通用的高性能TCP/UDP/HTTP 通信框架,包含服務端組件、客戶端組件和Agent組件,廣泛適用於各種不同應用場景的TCP/UDP/HTTP通信系統,提供C/C++、C#、Delphi、E(易語言)、Java、Python等編程語言介面。HP-Socket對通信層完全封裝... ...
  • 集群架構 Hadoop的安裝其實就是HDFS和YARN集群的配置,從下麵的架構圖可以看出,HDFS的每一個DataNode都需要配置NameNode的位置。同理YARN中的每一個NodeManager都需要配置ResourceManager的位置。 NameNode和ResourceManager的 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...