开始今日份整理html
保证django自动的加载每个app下的stark.py文件前端
from django.utils.module_loading import autodiscover_modules class StarkConfig(AppConfig): name = 'stark' def ready(self): autodiscover_modules('stark')
所谓注册就是仿照admin模块,对于注册的数据表进行记录,方便后面的url的增删改查java
仿照admin在stark下建立一个包services,并建立一个sites.py文件,代码以下python
from django.contrib import admin from django.urls import path from django.shortcuts import render,HttpResponse class ModelStark(object): list_display =("__str__") def __init__(self,model): self.model = model def list_view(self, request): return render(request,'stark/list_view.html',locals()) def add_view(self, request): return HttpResponse("add_view") def change_view(self, request, id): return HttpResponse("change_view") def delete_view(self, request, id): return HttpResponse("delete_view") @property def get_url(self,): temp = [ path("", self.list_view), path("add/",self. add_view), path("(\d+)/change/", self.change_view), path("(\d+)/delete/", self.delete_view), ] return (temp, None, None) class StarkSite: def __init__(self): self._registry ={} def register(self,model,admin_class=None,**options): admin_class = admin_class or ModelStark self._registry[model]=admin_class(model) def get_urls(self): temp =[] # 拿到已经注册的全部表 for model,config_obj in self._registry.items(): # 表名 model_name = model._meta.model_name # 项目名 model_label = model._meta.app_label temp.append( path("%s/%s/"%(model_label,model_name),config_obj.get_url) ) return temp @property def urls(self): return self.get_urls(),None,None site = StarkSite()
在app01中建立stark.py文件,并注册数据库
from stark.services.sites import site,ModelStark from .models import Book,Publish,Author,Author_detail # 分别注册书籍,出版社以及做者 site.register(Book) site.register(Publish) site.register(Author) print(site._registry)
打印注册的列表,结果以下django
{<class 'app01.models.Publish'>: <stark.services.sites.ModelStark object at 0x04B66B50>, <class 'app01.models.Book'>: <stark.services.sites.ModelStark object at 0x04B669B0>, <class 'app01.models.Author'>: <stark.services.sites.ModelStark object at 0x04B66970>}
这样就注册成功了vim
为了自定义的URL。因此咱们才会有自定义页面,才会有配置类。app
(1)在site中StarkSite类中建立一个URLS(self)方法,用@property方式,静态方法ide
(2)将二级分发功能放在配置类模块中函数
(3)配置类中self以及self.model的区别(超级重要)
self:是配置类对象
self.model:数据表对象,其实就是数据表的数据
经过上面:便可理解为何在注册的时候有一个空字典,在每个表对象进行注册时,对每个表生成对应的配置类对象,若是一个表对象有本身的自定义样式,则会走本身自定义样式,无则会走默认样式。
这样就基本实现了url的分发功能,有一级也有二级分发。这块内容就是理解就会以为东西少,不理解则东西好多!,只须要记住
self是配置类,self.model就是数据表对象就能够了。
对于默认类,self为默认配置类,其中self.model为传入的表对象,展现则使用默认类中的样式。
对于自定义类,self为自定义类,其中self.model为传入的表对象,自定义类继承默认类,优先使用自定义定义的类方法。
以下图展现
from django.contrib import admin from django.urls import path from django.shortcuts import render,HttpResponse class ModelStark(object): list_display =("__str__") def __init__(self,model): self.model = model def list_view(self, request): return render(request,'stark/list_view.html',locals()) def add_view(self, request): return HttpResponse("add_view") def change_view(self, request, id): return HttpResponse("change_view") def delete_view(self, request, id): return HttpResponse("delete_view") @property def get_url(self,): temp = [ path("", self.list_view), path("add/",self. add_view), path("(\d+)/change/", self.change_view), path("(\d+)/delete/", self.delete_view), ] return (temp, None, None) class StarkSite: def __init__(self): self._registry ={} def register(self,model,admin_class=None,**options): admin_class = admin_class or ModelStark self._registry[model]=admin_class(model) def get_urls(self): temp =[] # 拿到已经注册的全部表 for model,config_obj in self._registry.items(): # 表名 model_name = model._meta.model_name # 项目名 model_label = model._meta.app_label temp.append( path("%s/%s/"%(model_label,model_name),config_obj.get_url) ) return temp @property def urls(self): return self.get_urls(),None,None site = StarkSite()
访问顺序
path("stark/app01/book",BookConfig(Book).list_view) path("stark/app01/book/add",BookConfig(Book).add_view) path("stark/app01/publish",ModelAdmin(Publish).list_view) path("stark/app01/publish/add",ModelAdmin(Publish).add_view)
普通数据就是相似于数据库中book表中的title,price,出版日期,做者等基础数据,django自然对一对多支持
#目标数据类型 new_data=[ ["python",123], ["java",234] ]
视图层以下
def list_view(self, request): """ self:当前配置类 self.model:当前访问的表数据 :param request: :return: """ # 当前要展现的数据表的数据 querset = self.model.objects.all() print(querset) print(self.list_display) # 用于构建视图中的展现数据 new_data = [] for obj in querset: temp = [] # 构建列表嵌套中的小列表,使用的是自定义配置列表中要展现的内容 for field_or_info in self.list_display: vim = getattr(obj,field_or_info) temp.append(vim) new_data.append(temp) print('new_data', new_data) return render(request,'stark/list_view.html',locals())
模板层以下
对于Book表,是自定义展现配置类,展现以下图
视图层以及模板层如上,不过须要注意的是
没有加逗号,django会默认认为是一个字符串,并不会以一个元祖来读取元素,最后致使报错
对于出版社展现以下,只会展现对象名,显示名称是因为模型类中有__str__方法
在app01中添加展现列表中添加做者这个多对多字段
添加多对多字段
模板展现
最后展现中,做者多对多数据显示为none,
(1)知识补充:
使用名字访问一个model的实例:模型名._meta.get_field("publish")
展现模型类的的名字:模型名._meta.model_name
展现模型类对应的项目名称:模型名._meta.app_label
展现一个模型类对象的默认名称:模型对象.verbose_name
对于模型类中的参数,若是设置了verbose.name则会显示设置的名字,无则显示参数名称
(2)多对多的判断
对于多对多的判断,首先是导包,对于 list_display来讲,普通属性从self.list_display拿到的是字符串,一对多和多对多则是拿到的对象,拿到对象的类型判断是不是多对多,若是是多对多则报错并报错
对于多对多来讲,须要提示为多对多,须要使用自定义列,弹出错误,用于提示错误
数据的反射,例如book的出版状态只有已出版以及未出版,但在数据库中记录只有1和2,须要对1和2的内容取出并反射出具体的内容
注:这里主要使用的是”get_属性名_display方法”,这样最后在页面中展现就会变成以及出版或者是未出版,不在是数据库中1和2
field_obj = self.model._meta.get_field(field_or_func) #获取模型对象
这句话,获取的是模型类中的方法,因为模型类中没有__str__方法,因此须要对其进行处理
自定义函数,例如show_author,而后把函数名丢到list_display列表中
stites中获取返回值,而后加入到列表中传到前端
注:因为list_display中有字符串也有函数,因此须要用到callable来判断是都为函数名
这里的self 是类函数调用的方式.,由于原来类中须要穿参,如今增长一个参数而已,什么都行.可是最好是self
在callable 内容中传入obj对象,方便操做数据
在自定制配置类中,经过obj 获取对应的做者信息
非定制列 ,即只有 __str__,只须要返回到数据表名的大写便可
若是是普通属性,则只须要丢到对应的head_list列表中便可,对于自定义列,传入为函数名的时候则须要对传入作判断
app中注册类书写
导入mark_safe包
from django.utils.safestring import mark_safe
能够是后台传入的标签内容不会被转化,直接成为前端代码
导入包
from django.urls import reverse
定义类名以及表名
def __init__(self,model): self.model = model self.model_name = self.model._meta.model_name self.app_label = self.model._meta.app_label
视图层反向解析,设置name
@property def get_url(self,): # temp = [ # path("", self.list_view), # path("add/",self. add_view), # re_path("(\d+)/change/", self.change_view), # re_path("(\d+)/delete/", self.delete_view), # ] temp = [ path("", self.list_view, name="%s_%s_list" % (self.app_label, self.model_name)), path("add/", self.add_view, name="%s_%s_add" % (self.app_label, self.model_name)), re_path("(\d+)/change/", self.change_view, name="%s_%s_change" % (self.app_label, self.model_name)), re_path("(\d+)/delete/", self.delete_view, name="%s_%s_delete" % (self.app_label, self.model_name)), ] return (temp, None, None)
反向解析代码
# 反向解析当前访问表的增删改查URL def get_list_url(self): # 反向解析当前表的查询的URL list_url = reverse("%s_%s_list" % (self.app_label, self.model_name)) return list_url def get_add_url(self, obj): # 反向解析当前表的添加的URL add_url = reverse("%s_%s_delete" % (self.app_label, self.model_name)) return add_url def get_delete_url(self, obj): # 反向解析当前表的删除的URL delete_url = reverse("%s_%s_delete" % (self.app_label, self.model_name), args=(obj.pk,)) return delete_url def get_change_url(self, obj): # 反向解析当前表的修改的URL change_url = reverse("%s_%s_change" % (self.app_label, self.model_name), args=(obj.pk,)) return change_url
分析:反向解析名字为app名加表名,利用的是无名分组,注意无名分组为元祖传参,最后是三个默认列代码
# 三个默认列 # 选择框 def show_checkbox(self, obj=None, heade=False): if heade: return mark_safe("<input type='checkbox'>") return mark_safe("<input type='checkbox'>") # 删除框 def show_delbtn(self, obj=None, heade=False): if heade: return '删除' # return mark_safe("<a href='stark/app01/book/%s/delete'>删除</a>" % obj.pk) return mark_safe("<a href='%s'>删除</a>" % self.get_delete_url(obj)) # 编辑框 def show_editbtn(self, obj=None, heade=False): if heade: return '编辑' # return mark_safe("<a href='stark/app01/book/%s/change'>编辑</a>" % obj.pk) return mark_safe("<a href='%s'>编辑</a>" % self.get_change_url(obj)) ####同时构建新的list_display,若是须要在默认列表中都展现,须要设定新的list_display # 构建新的list_display def get_new_list_display(self): temp = [] temp.extend(self.list_display) temp.append(ModelStark.show_editbtn) temp.append(ModelStark.show_delbtn) temp.insert(0, ModelStark.show_checkbox) return temp
属性说明:
获取表头中,是header =true 这样能够获取表头数据内容
完整site代码以下
from django.contrib import admin from django.urls import path,re_path from django.shortcuts import render,HttpResponse from django.utils.safestring import mark_safe from django.urls import reverse class ModelStark(object): list_display =("__str__",) def __init__(self,model): self.model = model self.model_name = self.model._meta.model_name self.app_label = self.model._meta.app_label # 反向解析当前访问表的增删改查URL def get_list_url(self): # 反向解析当前表的查询的URL list_url = reverse("%s_%s_list" % (self.app_label, self.model_name)) return list_url def get_add_url(self, obj): # 反向解析当前表的添加的URL add_url = reverse("%s_%s_delete" % (self.app_label, self.model_name)) return add_url def get_delete_url(self, obj): # 反向解析当前表的删除的URL delete_url = reverse("%s_%s_delete" % (self.app_label, self.model_name), args=(obj.pk,)) return delete_url def get_change_url(self, obj): # 反向解析当前表的修改的URL change_url = reverse("%s_%s_change" % (self.app_label, self.model_name), args=(obj.pk,)) return change_url # 三个默认列 # 选择框 def show_checkbox(self, obj=None, heade=False): if heade: return mark_safe("<input type='checkbox'>") return mark_safe("<input type='checkbox'>") # 删除框 def show_delbtn(self, obj=None, heade=False): if heade: return '删除' # return mark_safe("<a href='stark/app01/book/%s/delete'>删除</a>" % obj.pk) return mark_safe("<a href='%s'>删除</a>" % self.get_delete_url(obj)) # 编辑框 def show_editbtn(self, obj=None, heade=False): if heade: return '编辑' # return mark_safe("<a href='stark/app01/book/%s/change'>编辑</a>" % obj.pk) return mark_safe("<a href='%s'>编辑</a>" % self.get_change_url(obj)) # 构建新的list_display def get_new_list_display(self): temp = [] temp.extend(self.list_display) temp.append(ModelStark.show_editbtn) temp.append(ModelStark.show_delbtn) temp.insert(0, ModelStark.show_checkbox) return temp # 视图函数 def list_view(self, request): """ self:当前配置类 selfmodel:当前访问的表数据 :param request: :return: """ # 当前访问表的数据 querset = self.model.objects.all() print(querset) print(self.list_display) #用于展现头部文件 header_list=[] for field_or_info in self.get_new_list_display(): #判断是函数名或者是字符段 if callable(field_or_info): vim=field_or_info(self,heade=True) header_list.append(vim) else: # 获取指定字段的对象属性,并拿出verbose_name属性 if field_or_info=='__str__': #若是只有默认装饰类,只有__str__,则拿出他的表名做为头 vim = self.model._meta.model_name.upper() else: file_obj =self.model._meta.get_field(field_or_info) vim = file_obj.verbose_name header_list.append(vim) #用于构建视图中的展现数据 new_data=[] for obj in querset: temp=[] for field_or_info in self.get_new_list_display(): # 判断是函数仍是字符段 if callable(field_or_info): vim = field_or_info(self,obj) else: try: from django.db.models.fields.related import ManyToManyField info_obj=self.model._meta.get_field(field_or_info) # 判断多对多字段 if type(info_obj)==ManyToManyField: raise Exception("list_distplay 不能是多很少字段") #判断是不是__str__ # if field_or_info=='__str': # vim=getattr(obj,field_or_info)() # 判断是否有choices字段 if info_obj.choices: vim = getattr(obj,'get_%s_display'%field_or_info)() else: vim =getattr(obj,field_or_info) except Exception as e: vim = getattr(obj, field_or_info)() temp.append(vim) new_data.append(temp) print('new_data',new_data) # 目标数据 # new_data=[ # ["python",123], # ["java",234] # ] return render(request,'stark/list_view.html',locals()) def add_view(self, request): return HttpResponse("add_view") def change_view(self, request, id): return HttpResponse("change_view") def delete_view(self, request, id): return HttpResponse("delete_view") @property def get_url(self,): # temp = [ # path("", self.list_view), # path("add/",self. add_view), # re_path("(\d+)/change/", self.change_view), # re_path("(\d+)/delete/", self.delete_view), # ] temp = [ path("", self.list_view, name="%s_%s_list" % (self.app_label, self.model_name)), path("add/", self.add_view, name="%s_%s_add" % (self.app_label, self.model_name)), re_path("(\d+)/change/", self.change_view, name="%s_%s_change" % (self.app_label, self.model_name)), re_path("(\d+)/delete/", self.delete_view, name="%s_%s_delete" % (self.app_label, self.model_name)), ] return (temp, None, None) class StarkSite: def __init__(self): self._registry ={} def register(self,model,admin_class=None,**options): admin_class = admin_class or ModelStark self._registry[model]=admin_class(model) def get_urls(self): temp =[] # 拿到已经注册的全部表 for model,config_obj in self._registry.items(): # 表名 model_name = model._meta.model_name # 项目名 model_label = model._meta.app_label temp.append( path("%s/%s/"%(model_label,model_name),config_obj.get_url) ) return temp @property def urls(self): return self.get_urls(),None,None site = StarkSite()
完整注册stark代码以下
from stark.services.sites import site,ModelStark from .models import * from django.utils.safestring import mark_safe class BookConfig(ModelStark): def show_authors(self,obj=None,heade=False): if heade: return "做者信息" return " ".join([author.name for author in obj.author.all()]) # # 选择框 # def show_checkbox(self,obj=None,heade=False): # if heade: # return mark_safe("<input type='checkbox'>") # return mark_safe("<input type='checkbox'>") # # # 删除框 # def show_delbtn(self, obj=None, heade=False): # if heade: # return '删除' # return mark_safe("<a href='stark/app01/book/%s/delete'>删除</a>"%obj.pk) # # # 编辑框 # def show_editbtn(self, obj=None, heade=False): # if heade: # return '编辑' # return mark_safe("<a href='stark/app01/book/%s/change'>编辑</a>" % obj.pk) list_display=["title","price","staes","publish",show_authors] # list_display=["title","price","staes","publish"] site.register(Book,BookConfig) site.register(Publish) print(site._registry)
a