1. 程式人生 > >基於Django-admin實現stark組件

基於Django-admin實現stark組件

ati getattr ces size print 相關 就是 .sh temp

一、url的分發練習

from django.conf.urls import url
from django.contrib import admin
from django.shortcuts import  HttpResponse
def index(request):
    return HttpResponse("首頁")
    
    
def add(request):                         #add視圖函數
    return HttpResponse("add")
def list_view(request):                  #list_view視圖函數
    return HttpResponse("list_view")
def change(request,id):                  #change視圖函數
    return HttpResponse("change")
def delete(request,id):                  #delete視圖函數
    return HttpResponse("delete")
    
    
def get_urls2():                        #url的二級分發函數
    temp=[
        url("^add/$",add),
        url("^$",list_view),
        url("^(\d+)/change/$",change),
        url("^(\d+)/delete/$",delete),
    ]
    return temp
    
def get_urls():
    temp=[]
    for model,model_class_obj in admin.site._registry.items(): # 模型類:該模型類的配置類對象 {Book:ModelAdmin(Book),Publish:ModelAdmn(Publish),....}
          app_name=model._meta.app_label                      #得到應用名
          model_name=model._meta.model_name
          temp.append(url(r"%s/%s/"%(app_name,model_name),(get_urls2(),None,None)))   #url做分發,後面跟元組,元組第一項為一個列表
    return  temp
    
from stark.service.sites import site
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r"^stark",(get_urls(),None,None))
]

二、實現stark組件


app01應用的models.py文件:

from django.db import models
class Author(models.Model):
    nid = models.AutoField(primary_key=True)
    name=models.CharField( max_length=32)
    age=models.IntegerField()
    def __str__(self):
        return self.name
class Publish(models.Model):
    nid = models.AutoField(primary_key=True)
    name=models.CharField( max_length=32)
    city=models.CharField( max_length=32)
    email=models.EmailField()
    def __str__(self):
        return self.name
class Book(models.Model):
    nid = models.AutoField(primary_key=True,verbose_name="編號")
    title = models.CharField( max_length=32,verbose_name="名稱")
    publishDate=models.DateField()
    price=models.DecimalField(max_digits=5,decimal_places=2,verbose_name="價格")
    # 與Publish建立一對多的關系,外鍵字段建立在多的一方
    publish=models.ForeignKey(to="Publish",to_field="nid",on_delete=models.CASCADE)
    # 與Author表建立多對多的關系,ManyToManyField可以建在兩個模型中的任意一個,自動創建第三張表
    authors=models.ManyToManyField(to='Author',)
    def __str__(self):
        return self.title
        
        
#執行下面python語句生成相關表(數據遷移)
# python3 manage.py makemigrations
# python3 manage.py migrate

項目下的settings.py文件設置:

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'app01.apps.App01Config',
    "app02.apps.App02Config",
    "stark.apps.StarkConfig",
]


STATIC_URL = '/static/'
STATICFILES_DIRS=[
    os.path.join(BASE_DIR,"static")
]

項目的urls.py文件:

from django.conf.urls import url
from django.contrib import admin
from stark.service.sites import site
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^stark/', site.urls),               #模擬admin的實現方式,在stark目錄後面進行分發
]

app01應用的stark.py文件對app01的應用表進行註冊:


from stark.service.sites import site,ModelStark
from app01.models import Book
from app01.models import Publish
from app01.models import Author
class BookConfig(ModelStark):
    # def display_authors(self, obj=None,is_header=False):     #顯示多對多字段,單獨定義函數實現方式
    #
    #     if is_header:
    #         return "作者"
    #     s=[]
    #     for author in obj.authors.all():
    #         s.append(author.name)
    #
    #     return " ".join(s)
    list_display = ["nid","title","price","publish","authors",]
    # list_display = ["nid","title","price","publish",display_authors]
site.register(Book,BookConfig)
site.register(Publish)
site.register(Author)

項目下的stark目錄下apps.py定義執行各個應用的stark.py:


from django.apps import AppConfig
from django.utils.module_loading import autodiscover_modules
class StarkConfig(AppConfig):
    name = 'stark'
    def ready(self):
        autodiscover_modules('stark')      # 執行每一個app下的stark.py

項目下的stark目錄下service目錄下sites.py定義對用戶訪問url的分發:

from django.conf.urls import url
from django.shortcuts import HttpResponse, render
from django.utils.safestring import mark_safe
class ModelStark():                    #將增,刪,改,查寫到ModelStark類中,這樣誰調用類中的功能,self.model就是用戶訪問的表
    list_display = ["__str__", ]
    def __init__(self, model, site):
        self.model = model
        self.site = site
    def edit(self, obj=None, is_header=False):
        if is_header:
            return "操作"                                                   #表頭返回 "操作"
        return mark_safe("<a href='%s/change'>編輯</a>" % obj.pk)        #mark_safe會識別返回的html標簽
    def delete(self, obj=None, is_header=False):
        if is_header:
            return "操作"
        return mark_safe("<a href='%s/delete'>刪除</a>" % obj.pk)
    def checkbox(self, obj=None, is_header=False):
        if is_header:
            return "選擇"
        return mark_safe("<input type='checkbox' pk=%s>" % obj.pk)        #在對應位置顯示多選框
    def add(self, request):
        return HttpResponse("add")
    def new_list_display(self):                 #新的顯示樣式,這樣所有表的顯示都有多選框,編輯和刪除操作
        temp = []
        temp.append(ModelStark.checkbox)
        temp.extend(self.list_display)
        temp.append(ModelStark.edit)
        temp.append(ModelStark.delete)
        return temp
    def list_view(self, request):
        print(self.model)
        data_list = self.model.objects.all()
        print("list_display", self.list_display)  # ["nid","title","price",edit]
        # 處理表頭
        header_list = []
        for field in self.new_list_display():
            if isinstance(field, str):                              #判斷field是字符串類型
                if field == "__str__":                            #字段是__str__
                    val = self.model._meta.model_name.upper()        #表頭顯示表名的大寫字母
                else:
                    field_obj = self.model._meta.get_field(field)
                    val = field_obj.verbose_name                      #得到字段的verbose_name,定義後可以顯示中文
            else:
                val = field(self, is_header=True)                  #field是函數,執行函數
            header_list.append(val)
        # 處理表單數據
        new_data_list = []
        for obj in data_list:
            temp = []
            for field in self.new_list_display():  # ["nid","title","price","authors",edit]    ['__str__']     ["title","price"]
                if isinstance(field, str):
                    try:
                        from django.db.models.fields.related import ManyToManyField
                        field_obj = self.model._meta.get_field(field)          #得到field的字段對象
                        if isinstance(field_obj, ManyToManyField):            #判斷是多對多關系的字段
                            l = []
                            for i in getattr(obj, field).all():             #.all()得到所有的對象,否則none
                                l.append(str(i))
                            val = ",".join(l)
                        else:
                            val = getattr(obj, field)
                            print("val", val)
                    except Exception as e:
                        val = getattr(obj, field)                      #反射,取到字段名
                else:
                    val = field(self, obj)
                temp.append(val)
            new_data_list.append(temp)
        return render(request, "list_view.html", locals())
    def change(self, request, id):
        return HttpResponse("change")
    def delete_view(self, request, id):
        return HttpResponse("delete_view")
    def get_urls2(self):
        temp = [
            url("^add/$", self.add),
            url("^$", self.list_view),
            url("^(\d+)/change/$", self.change),
            url("^(\d+)/delete/$", self.delete_view),
        ]
        return temp
    @property
    def urls2(self):
        return self.get_urls2(), None, None
        
        
class StarkSite():
    def __init__(self, ):
        self._registry = {}
    # 一級分發
    def get_urls(self):
        temp = []
        for model, model_class_obj in self._registry.items():  # {Book:ModelAdmin(Book),Publish:ModelAdmn(Publish),....}
            app_name = model._meta.app_label
            model_name = model._meta.model_name
            temp.append(url(r"%s/%s/" % (app_name, model_name), model_class_obj.urls2))  #接著二級分發
        return temp
    @property
    def urls(self):
        return self.get_urls(), None, None
    def register(self, model, admin_class=None, **options):
        if not admin_class:
            admin_class = ModelStark
        self._registry[model] = admin_class(model, self)
        
        
site = StarkSite()

list_view.html頁面:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="/static/bs/css/bootstrap.css">
</head>
<body>
<h3>查看數據</h3>
<div>
    <div>
        <div>
            <table class="table table-bordered table-hover table-striped">
                <thead>
                     <tr>
                          {% for foo in header_list %}
                          <th>{{ foo }}</th>
                          {% endfor %}
                     </tr>
                </thead>
                <tbody>
                      {% for new_data in new_data_list %}
                      <tr>
                         {% for foo in new_data %}
                         <td>{{ foo }}</td>
                         {% endfor %}
                      </tr>
                      {% endfor %}
                </tbody>
            </table>
        </div>
    </div>
</div>
</body>
</html>

三、顯示多對多字段的另一種方法


stark.py註冊表時自定義函數:

class BookConfig(ModelStark):
    def display_authors(self, obj=None,is_header=False):     #顯示多對多字段
        if is_header:
            return "作者"
        s=[]
        for author in obj.authors.all():
            s.append(author.name)
        return " ".join(s)
    list_display = ["nid","title","price","publish",display_authors]

sites.py裏面的ModelStark類定義的list_view

def list_view(self, request):
    print(self.model)
    data_list = self.model.objects.all()
    print("list_display", self.list_display)  #  ["nid","title","price",edit]
    # 處理表頭
    # header_list=["ID","名稱","價格"]
    header_list=[]
    for field in self.new_list_display():
        if isinstance(field,str):
            if field=="__str__":
                val=self.model._meta.model_name.upper()
            else:
                field_obj=self.model._meta.get_field(field)
                val=field_obj.verbose_name
        else:
            val=field(self,is_header=True)
        header_list.append(val)
    # 處理表單數據
    new_data_list = []
    for obj in data_list:
        temp = []
        for field in self.new_list_display():  #   ["nid","title","price","authors",edit]    ['__str__']     ["title","price"]
            if isinstance(field,str):
                val = getattr(obj, field)
            else:
                val=field(self,obj)
            temp.append(val)
        new_data_list.append(temp)

頁面顯示效果圖:

技術分享圖片



基於Django-admin實現stark組件