django_models后台管理myarya

时间:2023-03-09 01:29:58
django_models后台管理myarya

arya重点代码

# urls.py
from django.urls import path,re_path,include
from arya.service import v1 urlpatterns = [
re_path("^arya/",v1.site.urls),
] # arya/service/v1.py def get_urls(self):
from django.conf.urls import url, include urlpatterns = [
url(r'^$', self.index, name='index'),
url(r'^login/$', self.login, name='login'),
url(r'^logout/$', self.logout, name='logout'),
] for model_class, arya_model_obj in self._registry.items():
urlpatterns += [
url(r'^%s/%s/' % (model_class._meta.app_label, model_class._meta.model_name),
include(arya_model_obj.urls))
]
return urlpatterns @property
def urls(self):
"""
创建URL对应关系
:return: 元组类型:url关系列表或模块(模块内部必须有urlpatterns属性);app_name;namespace
""" return self.get_urls(), self.app_name, self.namespace

urls相关部分

# arya/service/v1.py

    def __init__(self, app_name='arya', namespace='arya'):
self.app_name = app_name
self.namespace = namespace
self._registry = {} def register(self, model_class, arya_model_class=BaseAryaModal):
self._registry[model_class] = arya_model_class(model_class, self) # app/arya.py class MovieAdmin(v1.BaseAryaModal):
""""""
v1.site.register(models.Movie,MovieAdmin)

register把models与arya关联起来

# 对每一个models进行url细分,curd。

# site
for model_class, arya_model_obj in self._registry.items():
urlpatterns += [
url(r'^%s/%s/' % (model_class._meta.app_label, model_class._meta.model_name),
include(arya_model_obj.urls))
] # BaseAryaModal
def get_urls(self):
from django.conf.urls import url
info = self.model_class._meta.app_label, self.model_class._meta.model_name urlpatterns = [
url(r'^$', self.changelist_view, name='%s_%s_changelist' % info),
url(r'^add/$', self.add_view, name='%s_%s_add' % info),
url(r'^(.+)/delete/$', self.delete_view, name='%s_%s_delete' % info),
url(r'^(.+)/change/$', self.change_view, name='%s_%s_change' % info),
url(r'^(.+)/detail/$', self.detail_view, name='%s_%s_detail' % info),
# For backwards compatibility (was the change url before 1.9)
# url(r'^(.+)/$', RedirectView.as_view(pattern_name='%s:%s_%s_change' % ((self.backend_site.name,) + info))),
]
urlpatterns += self.another_urls()
return urlpatterns @property
def urls(self):
return self.get_urls()

BaseAryaModal的url部分

class ChangeList(object):
def __init__(self, request, arya_modal, list_display, result_list, model_cls, list_filter, actions):
self.request = request
self.list_display = list_display
self.list_filter = list_filter self.model_cls = model_cls
self.arya_modal = arya_modal
self.actions = actions all_count = result_list.count()
query_params = copy.copy(request.GET)
query_params._mutable = True self.pager = Page(self.request.GET.get('page'), all_count, base_url=self.arya_modal.changelist_url(),
query_params=query_params)
self.result_list = result_list[self.pager.start:self.pager.end] def add_btn(self):
"""
列表页面定制新建数据按钮
:return:
"""
add_url = reverse(
'%s:%s_%s_add' % (self.arya_modal.site.namespace, self.arya_modal.app_label, self.arya_modal.model_name)) _change = QueryDict(mutable=True)
_change['_change_filter'] = self.request.GET.urlencode() tpl = "<a class='btn btn-success' style='float:right' href='{0}?{1}'><span class='glyphicon glyphicon-share-alt' aria-hidden='true'></span> 新建数据</a>".format(
add_url,
_change.urlencode())
return mark_safe(tpl) def gen_list_filter(self): for option in self.list_filter:
if option.is_func:
data_list = option.field_or_func(self)
else:
_field = self.model_cls._meta.get_field(option.field_or_func)
if isinstance(_field, ForeignKey):
data_list = FilterList(option, self, _field.related_model.objects.all(), self.request.GET,is_foreign=True)
elif isinstance(_field, ManyToManyField):
data_list = FilterList(option, self, _field.related_model.objects.all(), self.request.GET,is_foreign=True)
else:
data_list = FilterList(option, self, _field.model.objects.all(), self.request.GET)
yield data_list

BaseAryaModal的主页面部分,把所有items、filter、actions封装到对象ChangeList里,直接在页面分别引用

class FilterList(object):
"""
组合搜索项
""" def __init__(self, option, change_list, data_list, param_dict=None,is_foreign=False):
self.option = option self.data_list = data_list self.param_dict = copy.deepcopy(param_dict) self.param_dict._mutable = True self.change_list = change_list self.is_foreign = is_foreign def __iter__(self): base_url = self.change_list.arya_modal.changelist_url()
tpl = "<a href='{0}' class='{1}'>{2}</a>"
# 全部
if self.option.name in self.param_dict:
pop_value = self.param_dict.pop(self.option.name)
url = "{0}?{1}".format(base_url, self.param_dict.urlencode())
val = tpl.format(url, '', '全部')
self.param_dict.setlist(self.option.name, pop_value)
else:
url = "{0}?{1}".format(base_url, self.param_dict.urlencode())
val = tpl.format(url, 'active', '全部')
yield mark_safe("<div class='whole'>")
yield mark_safe(val)
yield mark_safe("</div>") yield mark_safe("<div class='others'>")
tmp_set = set()
for obj in self.data_list:
param_dict = copy.deepcopy(self.param_dict) # pk = getattr(obj, self.option.val_func_name)() if self.option.val_func_name else obj.pk
print(getattr(obj,self.option.name),type(getattr(obj,self.option.name)))
pk = getattr(obj,self.option.name) if not self.is_foreign else getattr(obj, self.option.val_func_name)() if self.option.val_func_name else obj.pk
pk = str(pk) # text = getattr(obj, self.option.text_func_name)() if self.option.text_func_name else str(obj)
text = getattr(obj,self.option.name) if not self.is_foreign else getattr(obj, self.option.text_func_name)() if self.option.text_func_name else str(obj)
if text not in tmp_set:
tmp_set.add(text)
exist = False
if pk in param_dict.getlist(self.option.name):
exist = True if self.option.is_multi:
if exist:
tmp = param_dict.getlist(self.option.name)
tmp.remove(pk)
param_dict.setlist(self.option.name,tmp)
else:
param_dict.appendlist(self.option.name, pk)
else:
if exist:
param_dict.pop(self.option.name)
else:
param_dict[self.option.name] = pk
url = "{0}?{1}".format(base_url, param_dict.urlencode())
val = tpl.format(url, 'active' if exist else '', text)
yield mark_safe(val)
yield mark_safe("</div>") class FilterOption(object):
def __init__(self, field_or_func, is_multi=False, text_func_name=None, val_func_name=None):
"""
:param field: 字段名称或函数
:param is_multi: 是否支持多选
:param text_func_name: 在Model中定义函数,显示文本名称,默认使用 str(对象)
:param val_func_name: 在Model中定义函数,显示文本名称,默认使用 对象.pk
"""
self.field_or_func = field_or_func
self.is_multi = is_multi
self.text_func_name = text_func_name
self.val_func_name = val_func_name @property
def is_func(self):
if isinstance(self.field_or_func, FunctionType):
return True @property
def name(self):
if self.is_func:
return self.field_or_func.__name__
else:
return self.field_or_func

单独创建对象FilterList,用以iter出筛选框。FilterOption则记录用户arya里该单项筛选条件的属性

Fork wupeiqi的pro_admin,结合rbac:https://github.com/fat39/pro_admin

开发过程

1、最简

from django.apps import AppConfig

class MyaryaConfig(AppConfig):
name = 'myarya' def ready(self):
super(MyaryaConfig, self).ready()
from django.utils.module_loading import autodiscover_modules
autodiscover_modules("myarya")

tmp_dj(项目名称,下同)/myarya/apps.py

# -*- coding:utf-8 -*-

from django.urls import re_path
from django.shortcuts import HttpResponse class MyaryaSite(): def __init__(self):
self._registry = {} # model_class class -> admin_class instance @property
def urls(self):
return self.get_urls() def get_urls(self):
urlpatterns = [
re_path("",self.index,name="abc")
] return urlpatterns,"testapp_name","testnamespace"
# return urlpatterns,app_name,namespace def register(self,model_class,v):
self._registry[model_class] = v def index(self):
return HttpResponse("index") site = MyaryaSite()

tmp_dj/myarya/service/v1.py

"""tmp_dj URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/2.0/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path,re_path,include
from myarya.service import v1 as my_v1 urlpatterns = [
path('admin/', admin.site.urls),
re_path("myarya/",my_v1.site.urls),
]

tmp_dj/tmp_dj/urls.py

django_models后台管理myarya

2、增加BaseMyaryaModel

BaseMyaryaModel是给detail、delete、add生成url的

from django.contrib import admin
from django.urls import path,re_path,include
from myarya.service import v1 as my_v1 urlpatterns = [
re_path("^myarya/",my_v1.site.urls),
]

tmp_dj/tmp_dj/urls.py

# -*- coding:utf-8 -*-
from django.urls import re_path,include
from django.shortcuts import HttpResponse,render
from django.template.response import TemplateResponse
from myarya.utils.pagination import Page class BaseMyaryaModel(): def __init__(self,model_class,site):
self.model_class = model_class
self.site = site @property
def urls(self):
return self.get_urls() def get_urls(self):
app_label = self.model_class._meta.app_label
model_name = self.model_class._meta.model_name urlpatterns = [
re_path("^$",self.changelist,name="{}_{}_changelist".format(app_label,model_name))
] return urlpatterns def changelist(self,request):
return HttpResponse("myarya changelist") class MyaryaSite(): def __init__(self,app_name="myarya",namespace="myarya"):
self._registry = {} # model_class class -> admin_class instance
self.app_name = app_name
self.namespace = namespace @property
def urls(self):
return self.get_urls(),self.app_name,self.namespace def get_urls(self):
urlpatterns = [
re_path("^index/$",self.index,name="index")
] for model_class,myaryamodel in self._registry.items():
urlpatterns.append(
re_path("{}/{}/".format(model_class._meta.app_label,model_class._meta.model_name),include(myaryamodel.urls))
) return urlpatterns
# return urlpatterns,app_name,namespace # 把这个挪到self.urls def register(self,model_class,myaryamodel=BaseMyaryaModel):
self._registry[model_class] = myaryamodel(model_class,self) def index(self,request):
return HttpResponse("myarya index") def test(self,request):
return HttpResponse("myarya test") site = MyaryaSite()

tmp_dj/myarya/service/v1.py

django_models后台管理myarya

3、可以访问所有items的页面

# -*- coding:utf-8 -*-
from django.urls import re_path,include
from django.shortcuts import HttpResponse,render
from django.template.response import TemplateResponse
from myarya.utils.pagination import Page
from django.urls import reverse class Items():
def __init__(self, objs,myaryamodel):
request = myaryamodel.request
query_params = request.GET.copy()
query_params._mutable = True
self.page = Page(current_page=request.GET.get("page"), all_count=objs.count(), base_url=request.path,
query_params=query_params)
self.objs_to_display = objs[self.page.start:self.page.end]
self.myaryamodel = myaryamodel class BaseMyaryaModel(): def __init__(self,model_class,site):
self.model_class = model_class
self.model_name = model_class._meta.model_name
self.site = site list_display = "__str__" @property
def urls(self):
return self.get_urls() def get_urls(self):
app_label = self.model_class._meta.app_label
model_name = self.model_class._meta.model_name urlpatterns = [
re_path("^$",self.changelist_view,name="{}_{}_changelist".format(app_label,model_name)),
re_path("^add/$",self.add_view,name="{}_{}_add".format(app_label,model_name)),
re_path("^(\d+)/detail/$",self.detail_view,name="{}_{}_detail".format(app_label,model_name))
] return urlpatterns def get_models_query_params(self,query_params):
query_params = query_params.copy()
query_params._mutable = True def changelist_view(self,request):
self.request = request
objs = self.model_class.objects.all() items = Items(objs,self) context = {
"items":items
}
return TemplateResponse(request,"changelist.html",context=context)
return render(request,"changelist.html",context=context)
return HttpResponse("changelist page") def add_view(self,request):
return TemplateResponse(request,"add.html") def detail_view(self,request,pk):
obj = self.model_class.objects.filter(pk=pk).first()
context = {
"obj":obj
}
return TemplateResponse(request,"detail.html",context=context) class MyaryaSite(): def __init__(self,app_name="myarya",namespace="myarya"):
self._registry = {} # model_class class -> admin_class instance
self.app_name = app_name
self.namespace = namespace @property
def urls(self):
return self.get_urls(),self.app_name,self.namespace def get_urls(self):
urlpatterns = [
re_path("^index/$",self.index,name="index")
] for model_class,myaryamodel in self._registry.items():
urlpatterns.append(
re_path("{}/{}/".format(model_class._meta.app_label,model_class._meta.model_name),include(myaryamodel.urls))
) return urlpatterns
# return urlpatterns,app_name,namespace # 把这个挪到self.urls def register(self,model_class,myaryamodel=BaseMyaryaModel):
self._registry[model_class] = myaryamodel(model_class,self) def index(self,request):
return HttpResponse("myarya index") def test(self,request):
return HttpResponse("myarya test") site = MyaryaSite()

tmp_dj/myarya/service/v1.py

{% load static %}
{% load font_table %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src={% static 'myarya/js/jquery-1.12.4.js' %}></script>
<link rel="stylesheet" href="{% static 'myarya/plugins/bootstrap-3.3.7-dist/css/bootstrap.min.css' %}">
</head>
<body>
{# {% font_table items.objs_to_display %}#}
{% font_table items %} <nav aria-label="Page navigation">
<ul class="pagination">
{{ items.page.page_html|safe }}
</ul>
</nav> </body>
</html>

tmp_dj/myarya/templates/changelist.html

# -*- coding:utf-8 -*-
from django.template import Library
from types import FunctionType register = Library() def table_headers(items):
if items.myaryamodel.list_display == "__str__":
yield items.myaryamodel.model_name
else:
for col in items.myaryamodel.list_display:
if isinstance(col,FunctionType):
yield col(items.myaryamodel,is_header=True)
else:
yield items.myaryamodel.model_class._meta.get_field(col).verbose_name def table_body(items):
for obj in items.objs_to_display:
if items.myaryamodel.list_display == "__str__":
yield [str(obj)]
else:
yield [col(items.myaryamodel) if isinstance(col,FunctionType) else getattr(obj,col) for col in items.myaryamodel.list_display] @register.inclusion_tag("font_table.html")
def font_table(items):
return {
"table_headers":table_headers(items),
"table_body":table_body(items),
}

tmp_dj/myarya/templatetags/font_table.py

django_models后台管理myarya

4、在数据列表页面增加筛选

简易版:把filter直接写在Items类,忘保存了

现版:Filter类、FilterOption类,涉及单选多选,没加上css

# #!/usr/bin/env python
# # -*- coding:utf-8 -*-
# import copy
# import json
# import urllib.parse
# from django.template.response import TemplateResponse, SimpleTemplateResponse
# from django.shortcuts import redirect
# from django.urls import reverse
# from django.utils.safestring import mark_safe
# from django.http.request import QueryDict
# from django.forms import Form, ModelForm
# from django.forms import fields
# from django.forms import widgets
# from django.db.models import ForeignKey, ManyToManyField
# from arya.utils.pagination import Page
# from types import FunctionType
#
# from django.http.request import QueryDict
#
# def model_to_dict(instance, fields=None, exclude=None):
# from itertools import chain
# opts = instance._meta
# data = {}
# for f in chain(opts.concrete_fields, opts.private_fields, opts.many_to_many):
# print(f, type(f))
# if not getattr(f, 'editable', False):
# continue
# if fields and f.name not in fields:
# continue
# if exclude and f.name in exclude:
# continue
# if type(f) == ForeignKey:
# data[f.name + "_id"] = f.value_from_object(instance)
# else:
# data[f.name] = f.value_from_object(instance)
# return data
#
#
# class FilterList(object):
# """
# 组合搜索项
# """
#
# def __init__(self, option, change_list, data_list, param_dict=None):
# self.option = option
#
# self.data_list = data_list
#
# self.param_dict = copy.deepcopy(param_dict)
#
# self.param_dict._mutable = True
#
# self.change_list = change_list
#
# def __iter__(self):
#
# base_url = self.change_list.arya_modal.changelist_url()
# tpl = "<a href='{0}' class='{1}'>{2}</a>"
# # 全部
# if self.option.name in self.param_dict:
# pop_value = self.param_dict.pop(self.option.name)
# url = "{0}?{1}".format(base_url, self.param_dict.urlencode())
# val = tpl.format(url, '', '全部')
# self.param_dict.setlist(self.option.name, pop_value)
# else:
# url = "{0}?{1}".format(base_url, self.param_dict.urlencode())
# val = tpl.format(url, 'active', '全部')
# yield mark_safe("<div class='whole'>")
# yield mark_safe(val)
# yield mark_safe("</div>")
#
# yield mark_safe("<div class='others'>")
# for obj in self.data_list:
# param_dict = copy.deepcopy(self.param_dict)
#
# pk = getattr(obj, self.option.val_func_name)() if self.option.val_func_name else obj.pk
# pk = str(pk)
#
# text = getattr(obj, self.option.text_func_name)() if self.option.text_func_name else str(obj)
#
# exist = False
# if pk in param_dict.getlist(self.option.name):
# exist = True
# tmp_list = param_dict.getlist(self.option.name)
# tmp_list.remove(pk)
# param_dict.setlist(self.option.name,tmp_list)
#
# if self.option.is_multi:
# exist or param_dict.appendlist(self.option.name, pk)
# else:
# if not exist:
# param_dict[self.option.name] = pk
# url = "{0}?{1}".format(base_url, param_dict.urlencode())
# val = tpl.format(url, 'active' if exist else '', text)
# yield mark_safe(val)
# yield mark_safe("</div>")
#
#
# class FilterOption(object):
# def __init__(self, field_or_func, is_multi=False, text_func_name=None, val_func_name=None):
# """
# :param field: 字段名称或函数
# :param is_multi: 是否支持多选
# :param text_func_name: 在Model中定义函数,显示文本名称,默认使用 str(对象)
# :param val_func_name: 在Model中定义函数,显示文本名称,默认使用 对象.pk
# """
# self.field_or_func = field_or_func
# self.is_multi = is_multi
# self.text_func_name = text_func_name
# self.val_func_name = val_func_name
#
# @property
# def is_func(self):
# if isinstance(self.field_or_func, FunctionType):
# return True
#
# @property
# def name(self):
# if self.is_func:
# return self.field_or_func.__name__
# else:
# return self.field_or_func
#
#
# class ChangeList(object):
# def __init__(self, request, arya_modal, list_display, result_list, model_cls, list_filter, actions):
# self.request = request
# self.list_display = list_display
# self.list_filter = list_filter
#
# self.model_cls = model_cls
# self.arya_modal = arya_modal
# self.actions = actions
#
# query_params = copy.deepcopy(request.GET)
# query_params._mutable = True
#
# all_count = result_list.count()
# self.pager = Page(self.request.GET.get('page'), all_count,per_page=int(self.request.GET.get("per_page") or 10), base_url=self.arya_modal.changelist_url(),
# query_params=query_params)
# self.result_list = result_list[self.pager.start:self.pager.end]
#
# def add_btn(self):
# """
# 列表页面定制新建数据按钮
# :return:
# """
# add_url = reverse(
# '%s:%s_%s_add' % (self.arya_modal.site.namespace, self.arya_modal.app_label, self.arya_modal.model_name))
#
# _change = QueryDict(mutable=True)
# _change['_change_filter'] = self.request.GET.urlencode()
#
# tpl = "<a class='btn btn-success' style='float:right' href='{0}?{1}'><span class='glyphicon glyphicon-share-alt' aria-hidden='true'></span> 新建数据</a>".format(
# add_url,
# _change.urlencode())
# return mark_safe(tpl)
#
# def gen_list_filter(self):
#
# for option in self.list_filter:
# if option.is_func:
# data_list = option.field_or_func(self)
# else:
# _field = self.model_cls._meta.get_field(option.field_or_func)
# if isinstance(_field, ForeignKey):
# data_list = FilterList(option, self, _field.related_model.objects.all(), self.request.GET)
# elif isinstance(_field, ManyToManyField):
# data_list = FilterList(option, self, _field.related_model.objects.all(), self.request.GET)
# else:
# data_list = FilterList(option, self, _field.model.objects.all(), self.request.GET)
# yield data_list
#
#
# class BaseAryaModal(object):
# def __init__(self, model_class, site):
# self.model_class = model_class
# self.app_label = model_class._meta.app_label
# self.model_name = model_class._meta.model_name
# self.param_key = "_change_filter"
#
# self.site = site
#
# self.request = None
#
# def changelist_param_url(self, query_params):
# # redirect_url = "%s?%s" % (reverse('%s:%s_%s' % (self.site.namespace, self.app_label, self.model_name)),
# # urllib.parse.urlencode(self.change_list_condition))
# redirect_url = "%s?%s" % (
# reverse('%s:%s_%s_changelist' % (self.site.namespace, self.app_label, self.model_name)),
# query_params.urlencode())
# return redirect_url
#
# def changelist_url(self):
# redirect_url = reverse('%s:%s_%s_changelist' % (self.site.namespace, self.app_label, self.model_name))
# return redirect_url
#
# def another_urls(self):
# """
# 钩子函数,用于自定义额外的URL
# :return:
# """
# return []
#
# def get_urls(self):
# from django.conf.urls import url
# info = self.model_class._meta.app_label, self.model_class._meta.model_name
#
# urlpatterns = [
# url(r'^$', self.changelist_view, name='%s_%s_changelist' % info),
# url(r'^add/$', self.add_view, name='%s_%s_add' % info),
# url(r'^(.+)/delete/$', self.delete_view, name='%s_%s_delete' % info),
# url(r'^(.+)/change/$', self.change_view, name='%s_%s_change' % info),
# url(r'^(.+)/detail/$', self.detail_view, name='%s_%s_detail' % info),
# # For backwards compatibility (was the change url before 1.9)
# # url(r'^(.+)/$', RedirectView.as_view(pattern_name='%s:%s_%s_change' % ((self.backend_site.name,) + info))),
# ]
# urlpatterns += self.another_urls()
# return urlpatterns
#
# @property
# def urls(self):
# return self.get_urls()
#
# # ########## CURD功能 ##########
#
# """1. 定制显示列表的Html模板"""
# change_list_template = []
# add_form_template = []
# detail_template = []
# change_form_template = []
#
# """2. 定制列表中的筛选条件"""
#
# def get_model_field_name_list(self):
# """
# 获取当前model中定义的字段
# :return:
# """
# # print(type(self.model_class._meta))
# from django.db.models.options import Options
# return [item.name for item in self.model_class._meta.fields]
#
# def get_model_field_name_list_m2m(self):
# return [item.name for item in self.model_class._meta.many_to_many]
#
# def get_all_model_field_name_list(self):
# """
# # 获取当前model中定义的字段(包括反向查找字段)
# :return:
# """
# return [item.name for item in self.model_class._meta._get_fields()]
#
# def get_change_list_condition(self, query_params):
#
# # 获取当前访问的数据类 self.model_class
# field_list = self.get_all_model_field_name_list()
# condition = {}
# for k in query_params:
# if k not in field_list:
# # raise Exception('条件查询字段%s不合法,合法字段为:%s' % (k, ",".join(field_list)))
# continue
# condition[k + "__in"] = query_params.getlist(k)
# return condition
#
# """3. 定制数据列表开始"""
#
# list_display = "__str__"
#
# """4. 定制Action行为"""
#
# def delete_action(self, request, queryset):
# """
# 定制Action行为
# :param request:
# :param queryset:
# :return: True表示保留所有条件,False表示回到列表页面
# """
# pk_list = request.POST.getlist('pk')
# queryset.filter(id__in=pk_list).delete()
#
# return True
#
# delete_action.short_description = "删除选择项"
#
#
#
# actions = [delete_action, ]
#
# """5. 定制添加和编辑页面中的Form组件"""
# page_model_form = None
#
# @property
# def get_model_form_cls(self):
# model_form_cls = self.page_model_form
# if not model_form_cls:
# _meta = type('Meta', (object,), {'model': self.model_class, "fields": "__all__"})
# model_form_cls = type('DynamicModelForm', (ModelForm,), {'Meta': _meta})
# return model_form_cls
#
# """6. 定制查询组合条件"""
# list_filter = []
#
# """增删改查方法"""
#
# def changelist_view(self, request):
# """
# 显示数据列表
# 1. 数据列表
# 2. 筛选
# 3. 分页
# 4. 是否可编辑
# 5. 搜索
# 6. 定制行为
# :param request:
# :return:
# """
# self.request = request
# result_list = self.model_class.objects.filter(**self.get_change_list_condition(request.GET))
#
# if request.method == "POST":
# """执行Action行为"""
# action = request.POST.get('action')
# if not action:
# return redirect(self.changelist_param_url(request.GET))
# if getattr(self, action)(request, result_list):
# return redirect(self.changelist_param_url(request.GET))
# else:
# return redirect(self.changelist_url())
#
# change_list = ChangeList(request, self, self.list_display, result_list, self.model_class, self.list_filter,
# actions=self.actions)
# context = {
# 'cl': change_list,
# }
# return TemplateResponse(request, self.change_list_template or [
# 'arya/%s/%s/change_list.html' % (self.app_label, self.model_name),
# 'arya/%s/change_list.html' % self.app_label,
# 'arya/change_list.html'
# ], context)
#
# def add_view(self, request):
# """
# 添加页面
# :param request:
# :return:
# """
#
# if request.method == 'GET':
# form = self.get_model_form_cls()
#
# elif request.method == "POST":
# form = self.get_model_form_cls(data=request.POST, files=request.FILES)
# if form.is_valid():
# obj = form.save()
# popup_id = request.GET.get("_popup")
# if popup_id:
# context = {'pk': obj.pk, 'value': str(obj), 'popup_id': popup_id}
# return SimpleTemplateResponse('arya/popup_response.html',
# {"popup_response_data": json.dumps(context)})
# else:
# # _change_filter = request.GET.get('_change_filter')
# _change_filter = request.GET.get(self.param_key)
# if _change_filter:
# change_list_url = "{0}?{1}".format(self.changelist_url(), _change_filter)
# else:
# change_list_url = self.changelist_url()
# return redirect(change_list_url)
# else:
# raise Exception('当前URL只支持GET/POST方法')
# context = {
# 'form': form
# }
# return TemplateResponse(request, self.add_form_template or [
# 'arya/%s/%s/add.html' % (self.app_label, self.model_name),
# 'arya/%s/add.html' % self.app_label,
# 'arya/add.html'
# ], context)
#
# def delete_view(self, request, pk):
# """
# 删除
# :param request:
# :param pk:
# :return:
# """
# self.model_class.objects.filter(pk=pk).delete()
# # _change_filter = request.GET.get('_change_filter')
# _change_filter = request.GET.get(self.param_key)
# if _change_filter:
# change_list_url = "{0}?{1}".format(self.changelist_url(), _change_filter)
# else:
# change_list_url = self.changelist_url()
# return redirect(change_list_url)
#
# def change_view(self, request, pk):
# """
# 修改页面
# :param request:
# :param pk:
# :return:
# """
# obj = self.model_class.objects.filter(pk=pk).first()
# if request.method == 'GET':
# form = self.get_model_form_cls(instance=obj)
# elif request.method == 'POST':
# form = self.get_model_form_cls(data=request.POST, files=request.FILES, instance=obj)
# if form.is_valid():
# form.save()
# # 如果修改成功,则跳转回去原来筛选页面
# _change_filter = request.GET.get(self.param_key)
# if _change_filter:
# change_list_url = "{0}?{1}".format(self.changelist_url(), _change_filter)
# else:
# change_list_url = self.changelist_url()
# return redirect(change_list_url)
# else:
# raise Exception('当前URL只支持GET/POST方法')
#
# context = {
# 'form': form
# }
# return TemplateResponse(request, self.change_form_template or [
# 'arya/%s/%s/change.html' % (self.app_label, self.model_name),
# 'arya/%s/change.html' % self.app_label,
# 'arya/change.html'
# ], context)
#
# def detail_view(self, request, pk):
# """
# 查看详细
# :param request:
# :param pk:
# :return:
# """
# row = self.model_class.objects.filter(pk=pk).first()
# fields = self.get_model_form_cls.Meta.fields
# if fields == '__all__':
# fields = self.get_model_field_name_list()
# # print(self.get_model_field_name_list_m2m())
# context_ = {}
# for name in fields:
# val = getattr(row, name)
# context_[name] = val
#
# context = {
# # 'row': row
# "kv":context_,
# }
# return TemplateResponse(request, self.change_form_template or [
# 'arya/%s/%s/detail.html' % (self.app_label, self.model_name),
# 'arya/%s/detail.html' % self.app_label,
# 'arya/detail.html'
# ], context)
#
#
# class AryaSite(object):
# def __init__(self, app_name='arya', namespace='arya'):
# self.app_name = app_name
# self.namespace = namespace
# self._registry = {}
#
# def register(self, model_class, arya_model_class=BaseAryaModal):
# self._registry[model_class] = arya_model_class(model_class, self)
#
# def get_urls(self):
# from django.conf.urls import url, include
#
# urlpatterns = [
# url(r'^$', self.index, name='index'),
# url(r'^login/$', self.login, name='login'),
# url(r'^logout/$', self.logout, name='logout'),
# ]
#
# for model_class, arya_model_obj in self._registry.items():
# urlpatterns += [
# url(r'^%s/%s/' % (model_class._meta.app_label, model_class._meta.model_name),
# include(arya_model_obj.urls))
# ]
# return urlpatterns
#
# @property
# def urls(self):
# """
# 创建URL对应关系
# :return: 元组类型:url关系列表或模块(模块内部必须有urlpatterns属性);app_name;namespace
# """
#
# return self.get_urls(), self.app_name, self.namespace
#
# def login(self, request):
# """
# 用户登录
# :param request:
# :return:
# """
# pass
#
# def logout(self, request):
# """
# 用户注销
# :param request:
# :return:
# """
# pass
#
# def index(self, request):
# """
# 首页
# :param request:
# :return:
# """
# from django.http import HttpResponse
# return HttpResponse("index ok")
# pass
#
#
# site = AryaSite() #!/usr/bin/env python
# -*- coding:utf-8 -*-
import copy
import json
import urllib.parse
from django.template.response import TemplateResponse, SimpleTemplateResponse
from django.shortcuts import redirect, render, HttpResponse
from django.urls import reverse
from django.utils.safestring import mark_safe
from django.http.request import QueryDict
from django.forms import Form, ModelForm
from django.forms import fields
from django.forms import widgets
from django.db.models import ForeignKey, ManyToManyField
from arya.utils.pagination import Page
from types import FunctionType from django.http.request import QueryDict def model_to_dict(instance, fields=None, exclude=None):
from itertools import chain
"""
Returns a dict containing the data in ``instance`` suitable for passing as
a Form's ``initial`` keyword argument. ``fields`` is an optional list of field names. If provided, only the named
fields will be included in the returned dict. ``exclude`` is an optional list of field names. If provided, the named
fields will be excluded from the returned dict, even if they are listed in
the ``fields`` argument.
"""
opts = instance._meta
data = {}
for f in chain(opts.concrete_fields, opts.private_fields, opts.many_to_many):
print(f, type(f))
if not getattr(f, 'editable', False):
continue
if fields and f.name not in fields:
continue
if exclude and f.name in exclude:
continue
if type(f) == ForeignKey:
data[f.name + "_id"] = f.value_from_object(instance)
else:
data[f.name] = f.value_from_object(instance)
return data class FilterList(object):
"""
组合搜索项
""" def __init__(self, option, change_list, data_list, param_dict=None):
self.option = option self.data_list = data_list self.param_dict = copy.deepcopy(param_dict) self.param_dict._mutable = True self.change_list = change_list def __iter__(self): base_url = self.change_list.arya_modal.changelist_url()
tpl = "<a href='{0}' class='{1}'>{2}</a>"
# 全部
if self.option.name in self.param_dict:
pop_value = self.param_dict.pop(self.option.name)
url = "{0}?{1}".format(base_url, self.param_dict.urlencode())
val = tpl.format(url, '', '全部')
self.param_dict.setlist(self.option.name, pop_value)
else:
url = "{0}?{1}".format(base_url, self.param_dict.urlencode())
val = tpl.format(url, 'active', '全部')
yield mark_safe("<div class='whole'>")
yield mark_safe(val)
yield mark_safe("</div>") yield mark_safe("<div class='others'>")
for obj in self.data_list:
param_dict = copy.deepcopy(self.param_dict) pk = getattr(obj, self.option.val_func_name)() if self.option.val_func_name else obj.pk
pk = str(pk) text = getattr(obj, self.option.text_func_name)() if self.option.text_func_name else str(obj) exist = False
if pk in param_dict.getlist(self.option.name):
exist = True if self.option.is_multi:
if exist:
param_dict.getlist(self.option.name).remove(pk)
else:
param_dict.appendlist(self.option.name, pk)
else:
param_dict[self.option.name] = pk
url = "{0}?{1}".format(base_url, param_dict.urlencode())
val = tpl.format(url, 'active' if exist else '', text)
yield mark_safe(val)
yield mark_safe("</div>") class FilterOption(object):
def __init__(self, field_or_func, is_multi=False, text_func_name=None, val_func_name=None):
"""
:param field: 字段名称或函数
:param is_multi: 是否支持多选
:param text_func_name: 在Model中定义函数,显示文本名称,默认使用 str(对象)
:param val_func_name: 在Model中定义函数,显示文本名称,默认使用 对象.pk
"""
self.field_or_func = field_or_func
self.is_multi = is_multi
self.text_func_name = text_func_name
self.val_func_name = val_func_name @property
def is_func(self):
if isinstance(self.field_or_func, FunctionType):
return True @property
def name(self):
if self.is_func:
return self.field_or_func.__name__
else:
return self.field_or_func class ChangeList(object):
def __init__(self, request, arya_modal, list_display, result_list, model_cls, list_filter, actions):
self.request = request
self.list_display = list_display
self.list_filter = list_filter self.model_cls = model_cls
self.arya_modal = arya_modal
self.actions = actions all_count = result_list.count()
query_params = copy.copy(request.GET)
query_params._mutable = True self.pager = Page(self.request.GET.get('page'), all_count, base_url=self.arya_modal.changelist_url(),
query_params=query_params)
self.result_list = result_list[self.pager.start:self.pager.end] def add_btn(self):
"""
列表页面定制新建数据按钮
:return:
"""
add_url = reverse(
'%s:%s_%s_add' % (self.arya_modal.site.namespace, self.arya_modal.app_label, self.arya_modal.model_name)) _change = QueryDict(mutable=True)
_change['_change_filter'] = self.request.GET.urlencode() tpl = "<a class='btn btn-success' style='float:right' href='{0}?{1}'><span class='glyphicon glyphicon-share-alt' aria-hidden='true'></span> 新建数据</a>".format(
add_url,
_change.urlencode())
return mark_safe(tpl) def gen_list_filter(self): for option in self.list_filter:
if option.is_func:
data_list = option.field_or_func(self)
else:
_field = self.model_cls._meta.get_field(option.field_or_func)
if isinstance(_field, ForeignKey):
data_list = FilterList(option, self, _field.related_model.objects.all(), self.request.GET)
elif isinstance(_field, ManyToManyField):
data_list = FilterList(option, self, _field.related_model.objects.all(), self.request.GET)
else:
data_list = FilterList(option, self, _field.model.objects.all(), self.request.GET)
yield data_list class BaseAryaModal(object):
def __init__(self, model_class, site):
self.model_class = model_class
self.app_label = model_class._meta.app_label
self.model_name = model_class._meta.model_name self.site = site self.request = None def changelist_param_url(self, query_params):
# redirect_url = "%s?%s" % (reverse('%s:%s_%s' % (self.site.namespace, self.app_label, self.model_name)),
# urllib.parse.urlencode(self.change_list_condition))
redirect_url = "%s?%s" % (
reverse('%s:%s_%s_changelist' % (self.site.namespace, self.app_label, self.model_name)),
query_params.urlencode())
return redirect_url def changelist_url(self):
redirect_url = reverse('%s:%s_%s_changelist' % (self.site.namespace, self.app_label, self.model_name))
return redirect_url def another_urls(self):
"""
钩子函数,用于自定义额外的URL
:return:
"""
return [] def get_urls(self):
from django.conf.urls import url
info = self.model_class._meta.app_label, self.model_class._meta.model_name urlpatterns = [
url(r'^$', self.changelist_view, name='%s_%s_changelist' % info),
url(r'^add/$', self.add_view, name='%s_%s_add' % info),
url(r'^(.+)/delete/$', self.delete_view, name='%s_%s_delete' % info),
url(r'^(.+)/change/$', self.change_view, name='%s_%s_change' % info),
url(r'^(.+)/detail/$', self.detail_view, name='%s_%s_detail' % info),
# For backwards compatibility (was the change url before 1.9)
# url(r'^(.+)/$', RedirectView.as_view(pattern_name='%s:%s_%s_change' % ((self.backend_site.name,) + info))),
]
urlpatterns += self.another_urls()
return urlpatterns @property
def urls(self):
return self.get_urls() # ########## CURD功能 ########## """1. 定制显示列表的Html模板"""
change_list_template = []
add_form_template = []
detail_template = []
change_form_template = [] """2. 定制列表中的筛选条件""" def get_model_field_name_list(self):
"""
获取当前model中定义的字段
:return:
"""
# print(type(self.model_class._meta))
from django.db.models.options import Options
return [item.name for item in self.model_class._meta.fields] def get_model_field_name_list_m2m(self):
return [item.name for item in self.model_class._meta.many_to_many] def get_all_model_field_name_list(self):
"""
# 获取当前model中定义的字段(包括反向查找字段)
:return:
"""
return [item.name for item in self.model_class._meta._get_fields()] def get_change_list_condition(self, query_params): field_list = self.get_all_model_field_name_list()
condition = {}
for k in query_params:
if k not in field_list:
# raise Exception('条件查询字段%s不合法,合法字段为:%s' % (k, ",".join(field_list)))
continue
condition[k + "__in"] = query_params.getlist(k)
return condition """3. 定制数据列表开始""" list_display = "__str__" """4. 定制Action行为""" def delete_action(self, request, queryset):
"""
定制Action行为
:param request:
:param queryset:
:return: True表示保留所有条件,False表示回到列表页面
"""
pk_list = request.POST.getlist('pk')
queryset.filter(id__in=pk_list).delete() return True delete_action.short_description = "删除选择项"
actions = [delete_action, ] """5. 定制添加和编辑页面中的Form组件"""
page_model_form = None @property
def get_model_form_cls(self):
model_form_cls = self.page_model_form
if not model_form_cls:
_meta = type('Meta', (object,), {'model': self.model_class, "fields": "__all__"})
model_form_cls = type('DynamicModelForm', (ModelForm,), {'Meta': _meta})
return model_form_cls """6. 定制查询组合条件"""
list_filter = [] """增删改查方法""" def changelist_view(self, request):
"""
显示数据列表
1. 数据列表
2. 筛选
3. 分页
4. 是否可编辑
5. 搜索
6. 定制行为
:param request:
:return:
"""
self.request = request
result_list = self.model_class.objects.filter(**self.get_change_list_condition(request.GET)) if request.method == "POST":
"""执行Action行为"""
action = request.POST.get('action')
if not action:
return redirect(self.changelist_param_url(request.GET))
if getattr(self, action)(request, result_list):
return redirect(self.changelist_param_url(request.GET))
else:
return redirect(self.changelist_url()) change_list = ChangeList(request, self, self.list_display, result_list, self.model_class, self.list_filter,
actions=self.actions)
context = {
'cl': change_list, }
return TemplateResponse(request, self.change_list_template or [
'arya/%s/%s/change_list.html' % (self.app_label, self.model_name),
'arya/%s/change_list.html' % self.app_label,
'arya/change_list.html'
], context) def add_view(self, request):
"""
添加页面
:param request:
:return:
""" if request.method == 'GET':
form = self.get_model_form_cls() elif request.method == "POST":
form = self.get_model_form_cls(data=request.POST, files=request.FILES)
if form.is_valid():
obj = form.save()
popup_id = request.GET.get("_popup")
if popup_id:
context = {'pk': obj.pk, 'value': str(obj), 'popup_id': popup_id}
return SimpleTemplateResponse('arya/popup_response.html',
{"popup_response_data": json.dumps(context)})
else:
_change_filter = request.GET.get('_change_filter')
if _change_filter:
change_list_url = "{0}?{1}".format(self.changelist_url(), _change_filter)
else:
change_list_url = self.changelist_url()
return redirect(change_list_url)
else:
raise Exception('当前URL只支持GET/POST方法')
context = {
'form': form
}
return TemplateResponse(request, self.add_form_template or [
'arya/%s/%s/add.html' % (self.app_label, self.model_name),
'arya/%s/add.html' % self.app_label,
'arya/add.html'
], context) def delete_view(self, request, pk):
"""
删除
:param request:
:param pk:
:return:
"""
self.model_class.objects.filter(pk=pk).delete()
_change_filter = request.GET.get('_change_filter')
if _change_filter:
change_list_url = "{0}?{1}".format(self.changelist_url(), _change_filter)
else:
change_list_url = self.changelist_url()
return redirect(change_list_url) def change_view(self, request, pk):
"""
修改页面
:param request:
:param pk:
:return:
"""
obj = self.model_class.objects.filter(pk=pk).first()
if request.method == 'GET':
form = self.get_model_form_cls(instance=obj)
elif request.method == 'POST':
form = self.get_model_form_cls(data=request.POST, files=request.FILES, instance=obj)
if form.is_valid():
form.save()
# 如果修改成功,则跳转回去原来筛选页面
_change_filter = request.GET.get('_change_filter')
if _change_filter:
change_list_url = "{0}?{1}".format(self.changelist_url(), _change_filter)
else:
change_list_url = self.changelist_url()
return redirect(change_list_url)
else:
raise Exception('当前URL只支持GET/POST方法') context = {
'form': form
}
return TemplateResponse(request, self.change_form_template or [
'arya/%s/%s/change.html' % (self.app_label, self.model_name),
'arya/%s/change.html' % self.app_label,
'arya/change.html'
], context) def detail_view(self, request, pk):
"""
查看详细
:param request:
:param pk:
:return:
"""
row = self.model_class.objects.filter(pk=pk).first()
fields = self.get_model_form_cls.Meta.fields
if fields == '__all__':
fields = self.get_model_field_name_list()
# print(self.get_model_field_name_list_m2m())
for name in fields:
val = getattr(row, name)
# print(name, val) context = {
'row': row
}
return TemplateResponse(request, self.change_form_template or [
'arya/%s/%s/detail.html' % (self.app_label, self.model_name),
'arya/%s/detail.html' % self.app_label,
'arya/detail.html'
], context) class AryaSite(object):
def __init__(self, app_name='arya', namespace='arya'):
self.app_name = app_name
self.namespace = namespace
self._registry = {} def register(self, model_class, arya_model_class=BaseAryaModal):
self._registry[model_class] = arya_model_class(model_class, self) def get_urls(self):
from django.conf.urls import url, include urlpatterns = [
url(r'^$', self.index, name='index'),
url(r'^login/$', self.login, name='login'),
url(r'^logout/$', self.logout, name='logout'),
] for model_class, arya_model_obj in self._registry.items():
urlpatterns += [
url(r'^%s/%s/' % (model_class._meta.app_label, model_class._meta.model_name),
include(arya_model_obj.urls))
]
return urlpatterns @property
def urls(self):
"""
创建URL对应关系
:return: 元组类型:url关系列表或模块(模块内部必须有urlpatterns属性);app_name;namespace
""" return self.get_urls(), self.app_name, self.namespace def login(self, request):
"""
用户登录
:param request:
:return:
"""
from arya import models
from arya.service import rbac # 测试
# obj = models.User.objects.get(id=1)
# rbac.initial_permission(request, obj) # 初始化权限信息
#
# return HttpResponse('Login') if request.method == 'GET':
return render(request, 'login.html')
else:
from arya import models
from arya.service import rbac user = request.POST.get('username')
pwd = request.POST.get('password')
obj = models.User.objects.filter(username=user, password=pwd).first()
if obj:
rbac.initial_permission(request, obj)
return redirect('/arya/')
else:
return render(request, 'login.html') def logout(self, request):
"""
用户注销
:param request:
:return:
"""
pass def index(self, request):
"""
首页
:param request:
:return:
"""
return render(request, 'arya/index.html') site = AryaSite()

tmp_dj/myarya/service/v1.py

{% load static %}
{% load font_table %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src={% static 'myarya/js/jquery-1.12.4.js' %}></script>
<link rel="stylesheet" href="{% static 'myarya/plugins/bootstrap-3.3.7-dist/css/bootstrap.min.css' %}">
</head>
<body>
{% for list_filter in items.gen_list_filter %}
{% for option in list_filter %}
{{ option|safe }}
{% endfor %}
{% endfor %} {% font_table items %} <nav aria-label="Page navigation">
<ul class="pagination">
{{ items.page.page_html|safe }}
</ul>
</nav>
</body>
</html>

tmp_dj/myarya/templates/changelist.html

# -*- coding:utf-8 -*-
from myarya.service import v1
from myarya.service.v1 import FilterOption
from . import models class MovieMyaryModel(v1.BaseMyaryaModel): def custom_field(self,obj=None,is_header=False):
if is_header:
return "custom_field"
else:
return "haha" list_display = [custom_field,"name","url"] list_filter = [
FilterOption("district",is_multi=True),
# FilterOption("district"),
] v1.site.register(models.Movie,MovieMyaryModel)
v1.site.register(models.Actors)

tmp_dj/其他app/myarya.py

django_models后台管理myarya

5、添加“操作”栏,添加add按钮

# -*- coding:utf-8 -*-
from django.http.request import QueryDict
from django.urls import re_path,include
from django.shortcuts import HttpResponse,render
from django.template.response import TemplateResponse
from myarya.utils.pagination import Page
from django.urls import reverse
from django.db.models.fields import Field
from django.db.models.fields.related import ForeignKey
from django.db.models.fields.related import ManyToManyField
from django.utils.safestring import mark_safe
from types import FunctionType
import copy class FilterOption():
def __init__(self,field_or_func,is_multi=False,):
self.field_or_func = field_or_func
self.is_multi = is_multi @property
def is_func(self):
if isinstance(self.field_or_func,FunctionType):
return True @property
def name(self):
if isinstance(self.field_or_func, FunctionType):
return self.field_or_func.__name__
else:
return self.field_or_func class Filter():
def __init__(self,option,request,data_list,changelist,is_foreign=False):
self.option = option
self.data_list = data_list
self.is_foreign = is_foreign
self.request = request
self.query_params = copy.deepcopy(self.request.GET)
self.query_params._mutable = True
self.changelist = changelist def __iter__(self):
query_params = copy.deepcopy(self.query_params)
# base_url = self.changelist.myaryamodel.changelist_url
base_url = self.request.path
if self.option.name in query_params:
query_params.pop(self.option.name)
whole_url = "{}?{}".format(base_url,query_params.urlencode())
yield mark_safe("<div class='whole'><a href='{}' class=''>全部</a></div>".format(whole_url))
else:
whole_url = "{}?{}".format(base_url, query_params.urlencode())
yield mark_safe("<div class='whole'><a href='{}' class='active'>全部</a></div>".format(whole_url)) yield mark_safe("<div>")
text_set = set()
for obj in self.data_list:
query_params = copy.deepcopy(self.query_params)
text = str(obj) if self.is_foreign else getattr(obj, self.option.name)
if text not in text_set:
text_set.add(text)
val = str(obj.pk if self.is_foreign else text)
tmp_list = query_params.getlist(self.option.name)
if val not in tmp_list:
exist_flag = False
else:
exist_flag = True if self.option.is_multi:
if not exist_flag:
tmp_list.append(val)
query_params.setlist(self.option.name, tmp_list)
else:
tmp_list.remove(val)
query_params.setlist(self.option.name, tmp_list)
else:
if not exist_flag:
query_params.setlist(self.option.name,[val]) url = "{}?{}".format(base_url, query_params.urlencode())
yield mark_safe("<a href='{}' class='{}'>{}</a>".format(url,"active" if exist_flag else "", text)) yield mark_safe("</div>") class Items():
def __init__(self, objs,myaryamodel):
self.myaryamodel = myaryamodel
self.model_class = myaryamodel.model_class
self.request = myaryamodel.request
self.list_filter = myaryamodel.list_filter
self.query_params = copy.deepcopy(self.request.GET)
self.query_params._mutable = True
self.page = Page(current_page=self.request.GET.get("page"), all_count=objs.count(), base_url=self.request.path,
query_params=self.query_params)
self.objs_to_display = objs[self.page.start:self.page.end] def add_btn(self):
add_url = reverse(
'%s:%s_%s_add' % (self.myaryamodel.site.namespace, self.myaryamodel.app_label, self.myaryamodel.model_name))
query_param = copy.deepcopy(self.request.GET)
_query_param = QueryDict(mutable=True)
_query_param["_changelist"] = query_param.urlencode()
url = "{}?{}".format(add_url,_query_param.urlencode())
return mark_safe("<a href='{}'>添加条目</a>".format(url)) @property
def gen_list_filter(self):
for option in self.list_filter:
field = self.model_class._meta.get_field(option.name)
if isinstance(field, ManyToManyField):
data_list = Filter(option,self.request,field.related_model.objects.all(),self,is_foreign=True)
elif isinstance(field, ForeignKey):
data_list = Filter(option,self.request,field.related_model.objects.all(),self,is_foreign=True)
elif isinstance(field, Field):
data_list = Filter(option,self.request,field.model.objects.all(),self)
else:
data_list = Filter(option,self.request, field.model.objects.all(),self)
yield data_list class BaseMyaryaModel(): def __init__(self,model_class,site):
self.model_class = model_class
self.app_label = self.model_class._meta.app_label
self.model_name = self.model_class._meta.model_name
self.site = site list_display = "__str__" @property
def urls(self):
return self.get_urls() def get_urls(self): urlpatterns = [
re_path("^$",self.changelist_view,name="{}_{}_changelist".format(self.app_label,self.model_name)),
re_path("^add/$",self.add_view,name="{}_{}_add".format(self.app_label,self.model_name)),
re_path("^(\d+)/edit/$",self.edit_view,name="{}_{}_edit".format(self.app_label,self.model_name)),
re_path("^(\d+)/detail/$",self.detail_view,name="{}_{}_detail".format(self.app_label,self.model_name)),
re_path("^(\d+)/delete/$",self.delete_view,name="{}_{}_delete".format(self.app_label,self.model_name))
] return urlpatterns @property
def changelist_url(self):
return reverse('%s:%s_%s_changelist' % (self.site.namespace, self.app_label, self.model_name)) def changelist_view(self,request):
self.request = request
objs = self.model_class.objects.all() items = Items(objs,self) context = {
"items":items
}
return TemplateResponse(request,"changelist.html",context=context)
return render(request,"changelist.html",context=context)
return HttpResponse("changelist page") def add_view(self,request):
return TemplateResponse(request,"add.html") def edit_view(self,request,pk):
return HttpResponse("") def detail_view(self,request,pk):
obj = self.model_class.objects.filter(pk=pk).first()
context = {
"obj":obj
}
return TemplateResponse(request,"detail.html",context=context)
def delete_view(self,request,pk):
return HttpResponse("") list_filter = [] class MyaryaSite(): def __init__(self,app_name="myarya",namespace="myarya"):
self._registry = {} # model_class class -> admin_class instance
self.app_name = app_name
self.namespace = namespace @property
def urls(self):
return self.get_urls(),self.app_name,self.namespace def get_urls(self):
urlpatterns = [
re_path("^index/$",self.index,name="index")
] for model_class,myaryamodel in self._registry.items():
urlpatterns.append(
re_path("{}/{}/".format(model_class._meta.app_label,model_class._meta.model_name),include(myaryamodel.urls))
) return urlpatterns
# return urlpatterns,app_name,namespace # 把这个挪到self.urls def register(self,model_class,myaryamodel=BaseMyaryaModel):
self._registry[model_class] = myaryamodel(model_class,self) def index(self,request):
return HttpResponse("myarya index") def test(self,request):
return HttpResponse("myarya test") site = MyaryaSite()

tmp_dj/myarya/service/v1.py

# -*- coding:utf-8 -*-
from myarya.service import v1
from myarya.service.v1 import FilterOption
from . import models
from django.urls import reverse
import copy
from django.http.request import QueryDict
from django.utils.safestring import mark_safe class MovieMyaryModel(v1.BaseMyaryaModel): def custom_field(self,obj=None,is_header=False):
if is_header:
return "custom_field"
else:
return "haha" def edit_field(self,obj=None,is_header=False):
if is_header:
return "操作"
else:
edit_url = reverse('{0}:{1}_{2}_edit'.format(self.site.namespace, self.app_label, self.model_name),
args=(obj.pk,))
del_url = reverse('{0}:{1}_{2}_delete'.format(self.site.namespace, self.app_label, self.model_name),
args=(obj.pk,))
detail_url = reverse('{0}:{1}_{2}_detail'.format(self.site.namespace, self.app_label, self.model_name),
args=(obj.pk,)) query_param = copy.deepcopy(self.request.GET)
_query_param = QueryDict(mutable=True)
_query_param["_changelist"] = query_param.urlencode() url_format = "{}?"+_query_param.urlencode()
htm_str = "<a href='{}'>编辑</a>|<a href='{}'>删除</a>|<a href='{}'>查看详细</a>".format(
url_format.format(edit_url),
url_format.format(del_url),
url_format.format(detail_url),
) return mark_safe(htm_str) list_display = [custom_field,"name","url",edit_field] list_filter = [
FilterOption("district",is_multi=True),
# FilterOption("district"),
] v1.site.register(models.Movie,MovieMyaryModel)
v1.site.register(models.Actors)

tmp_dj/其他app/myarya.py

{% load static %}
{% load font_table %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src={% static 'myarya/js/jquery-1.12.4.js' %}></script>
<link rel="stylesheet" href="{% static 'myarya/plugins/bootstrap-3.3.7-dist/css/bootstrap.min.css' %}">
</head>
<body>
{% for list_filter in items.gen_list_filter %}
{% for option in list_filter %}
{{ option|safe }}
{% endfor %}
{% endfor %} <div>{{ items.add_btn }}</div> {% font_table items %} <nav aria-label="Page navigation">
<ul class="pagination">
{{ items.page.page_html|safe }}
</ul>
</nav>
</body>
</html>

tmp_dj/myarya/templates/changelist.html

django_models后台管理myarya