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
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
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
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
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的更多相关文章
- MVC5 网站开发之七 用户功能 1、角色的后台管理
角色是网站中都有的一个功能,用来区分用户的类型.划分用户的权限,这次实现角色列表浏览.角色添加.角色修改和角色删除. 目录 奔跑吧,代码小哥! MVC5网站开发之一 总体概述 MVC5 网站开发之二 ...
- 后台管理UI的选择
最近要做一个企业的OA系统,以前一直使用EasyUI,一切都好,但感觉有点土了,想换成现在流行的Bootstrap为基础的后台UI风格,想满足的条件应该达到如下几个: 1.美观.大方.简洁 2.兼容I ...
- Django-Admin后台管理
Rhel6.5 Django1.10 Python3.5 应用环境:Python+Virtualenv(Python Virtualenv运行Django环境配置) Django-Admin后台管理 ...
- 集成一体化的移动POS开单扫描解决方案--"移动开单掌上POS"。它集后台管理软件
针对商贸企业的批发.零售管理设计的软硬件集成一体化的移动POS开单扫描解决方案--"移动开单掌上POS".它集后台管理软件.商品价格.库存等信息查询,店铺.展销会开单,移动捡货配送 ...
- MVC5 网站开发实践 2、后台管理
目录 MVC5 网站开发实践 概述 MVC5 网站开发实践 1.建立项目 从这一部分开始做后台管理,首先是基本框架的 一.Data项目 1.项目添加EntityFramework引用 在Data项 ...
- 学用MVC4做网站六:后台管理(续)
关于后台的说明: 后台将会用easyui + ajax模式. 这里涉及两个问题,一个是使用easyui如何在前台验证模型的问题,另一个是ajax提交后返回数据. 一.Easyui验证 前台验证采用ea ...
- php相册功能实现(包含php图片上传,后台管理,浏览和删除)教程例子
相册功能实现(包含php图片上传,后台管理,浏览和删除)教程例子包括五个部分: 一.相册首页 <html> <head> <meta charset="utf- ...
- 【tornado】系列项目(二)基于领域驱动模型的区域后台管理+前端easyui实现
本项目是一个系列项目,最终的目的是开发出一个类似京东商城的网站.本文主要介绍后台管理中的区域管理,以及前端基于easyui插件的使用.本次增删改查因数据量少,因此采用模态对话框方式进行,关于数据量大采 ...
- yii2-basic后台管理功能开发之三:自定义GridView列显示
在第二篇 yii2-basic后台管理功能开发之二:创建CRUD增删改查 中,我们利用gii工具生成的结果一般并不是我们想要的结果. 我们需要根据自己的需求自定义列显示.我遇到的主要是一下变更: 时间 ...
随机推荐
- 多线程之ThreadLocal
Java并发编程:深入剖析ThreadLocal 想必很多朋友对ThreadLocal并不陌生,今天我们就来一起探讨下ThreadLocal的使用方法和实现原理.首先,本文先谈一下对ThreadLoc ...
- nginx 查看版本 查看模块
如图,简单说 大V看模块,小v看版本. nginx -v //查看版本号 nginx -V //查看版本号和加载模块明细
- UITextView 和 UITextField限制字符数和表情符号
UITextField限制字符数 - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)r ...
- Java日志框架中真的需要判断log.isDebugEnabled()吗?
在项目中我们经常可以看到这样的代码: if (logger.isDebugEnabled()) { logger.debug(message); } 简单来说,就是用isDebugEnabled方法判 ...
- JVM(一)Java内存模型
前言 对于从事C.C++程序开发的开发人员来说,在开始使用对象之前,他们都需要使用new关键字为对象申请内存空间,在使用完对象之后,也需要使用delete关键字来释放对象占用的内存空间.对于Java程 ...
- B. Sleepy Game
http://codeforces.com/problemset/problem/936/B Petya and Vasya arranged a game. The game runs by the ...
- sudo 其他用户执行命令
sudo -E -u clouder /home/clouder/vs/program/chatserver/bin/startup.sh -E 加载用户环境变量
- CentOS 安装第三方yum源
yum install wget #安装下载工具 wget http://www.atomicorp.com/installers/atomic #下载 sh ./atomic #安装 yum che ...
- 《数据结构算法分析C描述》引论:选择问题,字谜游戏问题
#include <stdio.h> #include <stdlib.h> // 第一题 // 找出N个数的第k个最大者 // 方法1:排序(冒泡),降序找出第k个值 // ...
- MySQL 卸载
第一步:先查看 mysql 服务是否停止 没有停止就停止 第二步:用 管理员身份 运行 命令提示符 查看mysql 服务是否停止 : net stop mysql 卸载 : mysqld remo ...