仿照admin写一个startk组件
settings.py
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'app01.apps.App01Config', 'app02.apps.App02Config', 'stark.apps.StarkConfig', ]
urls.py
from stark.sites import site urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^stark/', site.urls), ]
stark/apps.py
from django.utils.module_loading import autodiscover_modules class StarkConfig(AppConfig): name = 'stark' def ready(self): autodiscover_modules('stark')
stark/sites.py
from django.utils.safestring import mark_safe from django.shortcuts import HttpResponse,render,redirect from django.core.urlresolvers import reverse from django.forms import ModelForm class DataList: def __init__(self,config,obj_list): self.config=config self.obj_list=obj_list def get_header_list(self): header_list = [] for i in self.config.new_list_display(): if isinstance(i, str): if i == "__str__": val = self.config.model._meta.model_name.upper() else: filed_obj = self.config.model._meta.get_field(i) val = filed_obj.verbose_name else: val = i(is_header=True) header_list.append(val) return header_list def get_body_list(self): new_data_list = [] for obj in self.obj_list: tmp = [] for filed in self.config.new_list_display(): if isinstance(filed, str): try: from django.db.models.fields.related import ManyToManyField filed_obj = self.config.model._meta.get_field(filed) if isinstance(filed_obj, ManyToManyField): li = [] for i in getattr(obj, filed).all(): li.append(str(i)) val = ",".join(li) else: val = getattr(obj, filed) except Exception as e: val = getattr(obj, filed) else: val = filed(obj=obj) tmp.append(val) new_data_list.append(tmp) return new_data_list class ModelStark: list_display = ('__str__',) search_fields=[] actions=[] def __init__(self,model,site): self.model=model self.site=site def edit(self,is_header=False,obj=None): if is_header: return "操作" info = self.model._meta.app_label, self.model._meta.model_name return mark_safe('<a class="btn btn-warning" href="%s">编辑</a>'%reverse('%s_%s_change'%info,args=(obj.pk,))) def delete(self,is_header=False,obj=None): if is_header: return "操作" info = self.model._meta.app_label, self.model._meta.model_name return mark_safe('<a class="btn btn-danger" href="%s">删除</a>'%reverse('%s_%s_delete'%info,args=(obj.pk,))) def checkbox(self, obj=None, is_header=False): if is_header: return "选择" return mark_safe("<input type='checkbox' name=checked_data value=%s>" % obj.pk) def new_list_display(self): tmp=[] tmp.append(self.checkbox) tmp.extend(self.list_display) tmp.append(self.edit) tmp.append(self.delete) return tmp def get_search_condition(self,request): from django.db.models import Q search_condition=Q() search_condition.connector="or" val=request.GET.get("q") if val: for field in self.search_fields: search_condition.children.append((field+"__contains",val)) return search_condition def get_actions_list(self): li=[] for func in self.actions: dic={} dic["name"]=func.__name__ dic["desc"]=func.desc li.append(dic) return li def get_list_url(self): info = self.model._meta.app_label, self.model._meta.model_name return reverse('%s_%s_list'%info) def list_view(self,request): if request.method=="POST": print(request.POST) action=request.POST.get("action") checked_data=request.POST.getlist("checked_data") action=getattr(self,action) action(checked_data) search_condition=self.get_search_condition(request) from django.db.models import Q filter_condition = Q() for key, value in request.GET.items(): filter_condition.children.append((key, value)) obj_list = self.model.objects.all().filter(search_condition).filter(filter_condition) data_list=DataList(self,obj_list) return render(request, "list.html", locals()) def get_modelform(self): from django.forms import ModelForm class StarkModelForm(ModelForm): class Meta: model=self.model fields="__all__" return StarkModelForm def add_view(self,request): if request.method=="POST": form= self.get_modelform()(request.POST) if form.is_valid(): form.save() return redirect(self.get_list_url()) else: return render(request, "add.html", locals()) form=self.get_modelform()() return render(request, "add.html", locals()) def delete_view(self,request,nid): if request.method == "POST": self.model.objects.get(pk=nid).delete() return redirect(self.get_list_url()) url = self.get_list_url() return render(request, "delete.html", locals()) def extra_url(self): return [] def change_view(self,request,nid): obj = self.model.objects.filter(pk=nid).first() if request.method == "POST": form = self.get_modelform()(request.POST, instance=obj) if form.is_valid(): form.save() return redirect(self.get_list_url()) form = self.get_modelform()(instance=obj) return render(request, "change.html", locals()) @property def get_url2(self): from django.conf.urls import url info = self.model._meta.app_label, self.model._meta.model_name urlpatterns = [ url(r'^$', self.list_view, name='%s_%s_list' % info), url(r'^add/$', self.add_view, name='%s_%s_add' % info), url(r'^(\d+)/delete/$', self.delete_view, name='%s_%s_delete' % info), url(r'^(\d+)/change/$', self.change_view, name='%s_%s_change' % info), ] return urlpatterns class StarkSite(object): def __init__(self, name='stark'): self._registry = {} # model_class class -> admin_class instance self.name = name def register(self, model, admin_class=None, **options): if not admin_class: admin_class = ModelStark self._registry[model] = admin_class(model, self) def get_url(self): from django.conf.urls import url urlpatterns=[] for model,model_stark in self._registry.items(): urlpatterns+=[ url(r'^%s/%s/'%(model._meta.app_label, model._meta.model_name),(model_stark.get_url2,None,None)), ] return urlpatterns @property def urls(self): return self.get_url(),None,None site = StarkSite()
app01/models.py
from django.db import models # Create your models here. class Author(models.Model): nid = models.AutoField(primary_key=True) name = models.CharField(max_length=32,verbose_name="姓名") age = models.IntegerField(verbose_name="年龄") # 与AuthorDetail建立一对一的关系 authorDetail = models.OneToOneField(to="AuthorDetail") def __str__(self): return self.name class AuthorDetail(models.Model): nid = models.AutoField(primary_key=True) birthday = models.DateField() telephone = models.BigIntegerField() addr = models.CharField(max_length=64) def __str__(self): return self.addr class Publish(models.Model): nid = models.AutoField(primary_key=True) name = models.CharField(max_length=32) city = models.CharField(max_length=32) email = models.EmailField() def __str__(self): return self.name class Book(models.Model): nid = models.AutoField(primary_key=True) title = models.CharField(max_length=32,verbose_name="书名") publishDate = models.DateField(verbose_name="发行日期") price = models.DecimalField(max_digits=5, decimal_places=2,verbose_name="价格") keepNum = models.IntegerField() commentNum = models.IntegerField() # 与Publish建立一对多的关系,外键字段建立在多的一方 publish = models.ForeignKey(to="Publish", to_field="nid",verbose_name="出版社") # 与Author表建立多对多的关系,ManyToManyField可以建在两个模型中的任意一个,自动创建第三张表 authors = models.ManyToManyField(to='Author',verbose_name="作者") def __str__(self): return self.title
app01/stark.py
from stark.sites import site,ModelStark from .models import * # Register your models here. class BookStark(ModelStark): list_display = ("title","publishDate","price","publish","authors") search_fields = ["title"] def patch_delete(self,selected_pk): self.model.objects.filter(pk__in=selected_pk).delete() patch_delete.desc="批量删除" actions=[patch_delete] site.register(Author) site.register(AuthorDetail) site.register(Publish) site.register(Book,BookStark)
templates/list.html
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>Title</title> <!-- 最新版本的 Bootstrap 核心 CSS 文件 --> <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"> </head> <body> <h3>查看数据</h3> <div class="container"> <div class="row"> <div class="col-md-8"> {% if self.search_fields %} <form class="form-inline pull-right" method="get" action="" style="margin-bottom: 10px"> {% else %} <form class="form-inline pull-right hidden" method="get" action="" style="margin-bottom: 10px"> {% endif %} {% csrf_token %} <div class="form-group"> <input type="text" class="form-control" name="q"> </div> <button type="submit" class="btn btn-default">搜索</button> </form> <form action="" method="post"> {% csrf_token %} <select class="form-control pull-left" name="action" style="width: auto"> {% for action in self.get_actions_list %} <option value="{{ action.name }}">{{ action.desc }}</option> {% endfor %} </select> <input type="submit" class="btn btn-default" value="执行"> <table class="table table-bordered table-hover table-striped"> <thead> <tr> {% for foo in data_list.get_header_list %} <th>{{ foo }}</th> {% endfor %} </tr> </thead> <tbody> {% for new_data in data_list.get_body_list %} <tr> {% for foo in new_data %} <td>{{ foo }}</td> {% endfor %} </tr> {% endfor %} </tbody> </table> </form> </div> </div> </div> </body> </html>
templates/add.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"> <style> input[id], select { display: block; width: 100%; height: 34px; padding: 6px 12px; font-size: 14px; line-height: 1.42857143; color: #555; background-color: #fff; background-image: none; border: 1px solid #ccc; border-radius: 4px; -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); -webkit-transition: border-color ease-in-out .15s, -webkit-box-shadow ease-in-out .15s; -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; } </style> </head> <body> <h3>添加页面</h3> {% include 'form.html' %} </body> </html>
templates/change.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"> <style> input[id], select { display: block; width: 100%; height: 34px; padding: 6px 12px; font-size: 14px; line-height: 1.42857143; color: #555; background-color: #fff; background-image: none; border: 1px solid #ccc; border-radius: 4px; -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); -webkit-transition: border-color ease-in-out .15s, -webkit-box-shadow ease-in-out .15s; -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; } </style> </head> <body> <h3>编辑页面</h3> {% include 'form.html' %} </body> </html>
templates/form.html
<div class="container"> <div class="row"> <div class="col-md-8 col-md-offset-1"> <form action="" method="post" novalidate> {% csrf_token %} {% for field in form %} <div class="form-group"> <label for="">{{ field.label }}</label> {{ field }} <span class="pull-right" style="color: red">{{ field.errors.0 }}</span> </div> {% endfor %} <input type="submit" class="btn btn-default"> </form> </div> </div> </div>
templates/delete.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"> </head> <body> <h3>删除页面</h3> <form action="" method="post"> {% csrf_token %} <input type="submit" value="确认删除"> <a href="{{ url }}">取消</a> </form> </body> </html>