stark组件之pop页面,按钮,url,页面

 

1、Window open() 方法

 

效果图

 

2、admin的pop添加按钮

3、stark之pop功能

POP功能:   

  1.如何只有多对多和一对多字段后面才渲染 "+"
  2."+"的对应的跳转路径
  3.保存添加记录的同时,应该将原页面对应的下拉菜单添加该记录。

1、

 

2、多对多字段如何渲染

3、isinstance判断类型

4、  一对多或多对多字段的关联模型

 

5、bootstrap页面自适应col-xs-8

 

 6、model表显示的是__str__

 

7、构造url

 

 

8、传递数据,window.open使用

 

 3、知识点总结

1、pop功能:

  1.在一对多和多对多字段后渲染 +
2.+对应的跳转路径
3.保存添加记录同时,将原页面的对应的下拉菜单中添加该记录

2、在一对多和多对多字段后渲染+   

 后台需要先判断 是否是 一对多 多对多字段
modelform, 遍历
for bfield in form:
print(bfield.field) # 是每个form字段对象
所以:判断是否是一对多,多对多字段
if isinstance(bfield.field, ModelChoiceField):
bfield.is_pop = True # 为特殊字段加上特有属性,方便前端判断。

注意:ModelMultipleChoiceField(多对多) 继承 ModelChoiceField(一对多)
ModelChoiceField 继承 ChoiceField

3、+对应的跳转路径

    form表单得一对多,多对多得字段对象
bfield.field.queryset.model # 相关联得模型!!<class 'app01.models.Publish'>
#(模型表得对象去找 filter_field_obj.rel.to.objects.all(),到to是模型。)

根据queryset找model queryset.model
根据model找queryset model.objects.all()

related_model_name = bfield.field.queryset.model._meta.model_name # publish
related_app_label = bfield.field.queryset.model._meta.app_label # app01

反向解析url
_url = reverse("%s_%s_add" % (related_app_label, related_model_name))

# 为bfield添加自己特有的url,
# ?后面是为了,区分是top,还是正常页面打开/add/,方便之后关闭,以及赋值。
bfield.url = _url + "?pop_res_id=id_%s" % bfield.name

4、关闭弹出得top页面

    top弹出,关闭页面,回到到原页面;
正常添加,跳转到list页面;

返回 res = {"pk":obj.pk, 'text':str(obj), "pop_res_id": pop_res_id}
pop.html,方便关闭pop页面

pop.html:
关闭以及将接收得数据传到原页面上!
window.opener.pop_response("{{ res.pk}}","{{ res.text }}","{{ res.pop_res_id }}");
window.close()

5、原页面接收数据,并显示刚添加得数据(window.opener)

    拿到 id, text, pop_res_id
动态创建 option append到对应得下拉框中,并选中;
var $option = $("<option>");
$option.html(text);
$option.val(pk);
$option.attr('selected','selected');

$('#'+pop_res_id).append($option)

6、前端展示:定位,(父相子绝)

     <div style="position: relative">
        {% if field.is_pop %}
            <a onclick="pop('{{ field.url }}')"><span style="font-size: 23px;position: absolute; right: -23px; top: 25px;">+</span></a>
        {% endif %}
     </div>

7、补充:

ChoiceFiled
ModelChoiceFiled(ChoiceFiled) ---- select(单选) --- ForeignKey
MultiModelChoiceFiled (ModelChoiceFiled)----select(多选) --- ManyToManyField

Book模型,form表单,modelform;
modelform帮我们转成了form表单;

bootstrap页面自适应: col-xs-8

代码注释总结:

首先准备工作做完:
    window.opener.pop_response('{{ res.pk }}','{{ res.text }}','{{ res.pop_res_id }}');
    window.close()
在pop页面关闭前把指定的值传参给主页面执行,然后执行一个close,关闭掉自己。

2.增加视图函数

 # 增加数据视图函数
    def add_view(self,request):
        ModelFormDemo=self.get_modelform_class()
        form = ModelFormDemo()
        #循环每个form字段,看看他们的类型是不是一对多和对多类型,是的话需要前端添加+号
        for bfield in form:    循环ModelForm的每一个字段,把多对多和一对多字段筛选出来。
            print(bfield.field) #字段对象
            print(bfield.name) #字段名(字符串)
            from django.forms.models import ModelChoiceField
            if isinstance(bfield.field,ModelChoiceField):
                bfield.is_pop=True           如果需要加+的话,那么赋一个True的值。方便前端判定
                    【
                    {% if field.is_pop %}
                        <a onclick="pop('{{ field.url }}')" href="" style="position: absolute;right: -30px;top: 26px"><spanstyle="font-size: 26px">+</span></a>
                    {% endif %}
                    】

                #print(bfield.field.queryset.model)
    #这里需要注意,pop出来页面需要添加的表名和app名,和主页面的添加是不一样的。
 

注意:

 related_model_name=bfield.field.queryset.model._meta.model_name
 related_app_label=bfield.field.queryset.model._meta.app_label

  #通过一个方向解析拿到一个url.
  _url=reverse("%s_%s_add"%(related_app_label,related_model_name))

  #要知道的是,点的哪个加号,在URL后加一个这个字段的名字,做一个记号。
  bfield.url=_url+"?pop_res_id=id_%s"%bfield.name

视图函数中继续:

        if request.method=="POST":
            form = ModelFormDemo(request.POST)
            if form.is_valid():
                obj=form.save()
                pop_res_id=request.GET.get("pop_res_id") #每一个modelform渲染到前端的id是id_+"字段名"

                #<input type="text" name="title" maxlength="32" required="" id="id_title">
                

                if pop_res_id:
                    #如果能取到id的话,表示是pop页面而不是主页面的添加。
                    res={"pop_res_id":pop_res_id,"pk":obj.pk,"text":str(obj)}
                    #pop页面添加成功以后,obj也就有了值,就是当前添加这条数据的各种值,
                    #取到id,添加的字段,添加的内容给了前端模板。
                    return render(request,"pop.html",locals())
                else:
                    return redirect(self.get_list_url())

        return render(request,"add_view.html",locals())
前端模板拿到后端传过来的url以后,渲染到+上。

    http://127.0.0.1:8000/stark/app01/publish/add/?pop_res_id=id_publish
    http://127.0.0.1:8000/stark/app01/author/add/?pop_res_id=id_authors
    点击不同的+,url也不同。pop_res_id也都不同。
    同时给+绑定一个弹框事件:
        function pop(url) {
        window.open(url,"","width=600,height=400,top=100,left=100")
    }
     打开框以后,添加完毕点击提交后,

  window.opener.pop_response('{{ res.pk }}','{{ res.text }}','{{ res.pop_res_id }}');
  window.close()
  #把值取到并且把窗口关闭。

 

    最后就是

 function pop_response(pk,text,pop_res_id){
                var $option = $("<option>");          //创建一个标签
                $option.html(text);                   //将添加的数据的文本值给了这个标签内容
                $option.val(pk);                      //赋一个value值,值是这条记录的PK
                $option.attr("selected","selected");  //默认为选中
                $("#"+pop_res_id).append($option)     //哪个标签后添加的,就把这个option放到哪个标签下。
            }
    #主添加页面拿到关闭前通过参数传过来的值以后,渲染出一个option标签,把内容,和id,等全部写好,最后加到指定的select标签下面。

4、coding代码

1、starkadmin

from django.shortcuts import HttpResponse
from stark.service import stark
from .models import *
from django.forms import ModelForm

class AuthorConfig(stark.ModelStark):
    list_display = ['nid', 'name', 'age']
    list_display_links = ['name','age']


class BookModelForm(ModelForm):
    class Meta:
        model = Book
        fields = "__all__"

        labels = {
            "authors":"作者",
            "publishDate":"出版日期",
        }

class BookConfig(stark.ModelStark):
    # list_display = ['title', 'price','publish','authors']
    list_display = ['__str__',]
    list_display_links = ['title']
    modelform_class = BookModelForm
    search_fields = ['title','price']
    list_filter = ['title','publish','authors']  # 一对多,多对多字段

    # 批量修改数据
    def patch_init(self,request,queryset):
        queryset.update(price=111)

        # return HttpResponse("批量初始化OK")

    patch_init.short_description = "批量初始化"

    actions = [patch_init]


stark.site.register(Book,BookConfig)
stark.site.register(Publish)
stark.site.register(Author,AuthorConfig)
stark.site.register(AuthorDetail)

# print(stark.site._registry)
View Code

 2、stark/service/stark.py

# -*- coding: utf-8 -*-
# @Time    : 2018/08/17 0017 14:46
# @Author  : Venicid
from django.conf.urls import url
from django.shortcuts import HttpResponse,render,redirect

from django.utils.safestring import mark_safe
from django.urls import reverse
from django.db.models import Q  # 与或非
from django.db.models.fields.related import ForeignKey
from django.db.models.fields.related import ManyToManyField
import copy

from stark.utils.page import Pagination
class ShowList(object):
    def __init__(self,config, data_list,request):
        self.config = config  # MOdelStark实例对象
        self.data_list = data_list      # 数据
        self.request =request

        # 分页
        data_count = self.data_list.count()
        current_page = int(self.request.GET.get('page',1))
        base_path = self.request.path
        self.pagination = Pagination(current_page,data_count,base_path,self.request.GET,per_page_num=10, pager_count=11,)

        # 分页后的数据
        self.page_data = self.data_list[self.pagination.start:self.pagination.end]

        # actions 批量初始化,字段
        # self.actions = self.config.actions # [patch_init]
        self.actions = self.config.new_actions() # [pathch_delete,patch_init,]
        # 构建数据[{'name':'path_init',"desc":'xxxxx'}]

    # filter的tag如何生成的
    def get_filter_linktags(self):
        link_dic = {}
        for filter_field in self.config.list_filter:        # ['title','publish','authors']
            # 1.获取url中的相关字段,后面比较
            current_id = self.request.GET.get(filter_field,0)
            pararms = copy.deepcopy(self.request.GET)

            # 2 页面生成  各种字段
            filter_field_obj = self.config.model._meta.get_field(filter_field)
            print(filter_field_obj,type(filter_field_obj))
            # app01.Book.publish  < class 'django.db.models.fields.related.ForeignKey'>
            # app01.Book.authors < class 'django.db.models.fields.related.ManyToManyField'>

            # print('rel...',filter_field_obj.re)     # <ManyToOneRel: app01.book>
            # print('rel...',filter_field_obj.re.to.objects.all())  # <QuerySet [<Publish: 南京出版社>, <Publish: 北京出版社>]>

            # 解决步骤
            # print('rel...',filter_field_obj.__dict__)
            # print('rel...',filter_field_obj.remote_field)
            # print('rel...',filter_field_obj.remote_field.__dict__)
            # print("rel...", filter_field_obj.remote_field.model.objects.all())
            # <QuerySet [<Publish: 南京出版社>, <Publish: 北京出版社>]>
            # <QuerySet [<Author: jack>, <Author: tom>]>

            # 一对一字段or一对多字段
            if isinstance(filter_field_obj,ForeignKey) or isinstance(filter_field_obj,ManyToManyField):
                data_list = filter_field_obj.remote_field.model.objects.all()
            else:
                # 普通字段
                data_list = self.config.model.objects.all().values('pk',filter_field)

            # 3、 生成标签的href
            temp = []
            if pararms.get(filter_field):
                del pararms[filter_field]
                temp.append("<a href='?%s'>全部</a>"%pararms.urlencode())
            else:
                temp.append("<a href='#' class='active'>全部</a>")

            # 处理filter字段的href
            for obj in data_list:
                # print(data_list)
                # 一对一,一对多字段
                if isinstance(filter_field_obj, ForeignKey) or isinstance(filter_field_obj, ManyToManyField):
                    pk = obj.pk
                    text = str(obj)
                    pararms[filter_field] = pk
                else:
                    # 普通字段
                    pk = obj.get('pk')
                    text = obj.get(filter_field)
                    pararms[filter_field] = text

                _url = pararms.urlencode()
                # print(type(current_id),type(pk),type(text))
                if str(current_id) == str(pk) or str(current_id) ==str(text):
                    link_tag = "<a href='?%s' class='active'>%s</a>"%(_url,text)
                else:
                    link_tag = "<a href='?%s'>%s</a>"%(_url,text)
                temp.append(link_tag)
            link_dic[filter_field] = temp

        return link_dic

    def get_action_list(self):
        """action批量初始化,构架数据"""
        temp = []
        for action in self.actions:
            temp.append(
                {'name':action.__name__,                # class的类名
                 "desc":action.short_description        # class的属性
                 }
            )
        return temp

    def get_header(self):
        # 构建表头
        header_list = []  # # header_list = ['选择','pk',...'操作','操作']
        for field in self.config.new_list_play():
            if callable(field):
                # header_list.append(field.__name__)
                val = field(self.config, header=True)
                header_list.append(val)
            else:
                if field == "__str__":
                    header_list.append(self.config.model._meta.model_name.upper())
                else:
                    val = self.config.model._meta.get_field(field).verbose_name    # 中文名称
                    header_list.append(val)

        return header_list

    def get_body(self):
        # 构建表单
        new_data_list = []
        for obj in self.page_data:    #分页后的数据               # Book表模型,Author表模型
            temp = []
            for field in self.config.new_list_play():     #  ["__str__"]  ['name','age']
                if callable(field):                 # edit()  可调用的
                    val = field(self.config,obj)           # 直接调用edit()函数
                else:
                    try:
                        field_obj = self.config.model._meta.get_field(field)
                        if isinstance(field_obj,ManyToManyField):
                            ret = getattr(obj,field).all()       # 反射  obj是实例对象,name是方法
                            t = []
                            for obj in ret:
                                t.append(str(obj))
                            val = ','.join(t)

                        else:
                            val = getattr(obj, field)
                            # list_display_links 按钮
                            if field in self.config.list_display_links:
                                _url = self.config.get_change_url(self,obj)
                                val = mark_safe("<a href='%s'>%s</a>"%(_url,val))

                    # __str__ 的步骤
                    except  Exception as e:
                        val = getattr(obj,field)                #  <bound method Book.__str__ of <Book: php>
                        _url = self.config.get_change_url(obj)   # /app01/book/3/change/
                        val = mark_safe("<a href='%s'> %s </a>" % (_url, val()))

                temp.append(val)

            new_data_list.append(temp)

        # print('new_data_list',new_data_list)        # 构造数据  [['jack', 44], ['mark', 33]]

        return new_data_list


class ModelStark(object):
    list_display = ['__str__',]  # 子类中没有,直接用父类自己的
    list_display_links = []
    modelform_class = []
    search_fields = []  # 模糊查询字段
    actions = []
    list_filter = []        # 过滤字段


    # 批量删除
    def patch_delete(self,request,queryset):
        queryset.delete()

    patch_delete.short_description = "Delete selected "


    def __init__(self,model, site):
        self.model = model
        self.site = site

    # 增删改查url
    def get_add_url(self):
        model_name = self.model._meta.model_name
        app_label = self.model._meta.app_label
        _url = reverse("%s_%s_add" %(app_label,model_name))
        return _url

    def get_list_url(self):
        model_name = self.model._meta.model_name
        app_label = self.model._meta.app_label
        _url = reverse("%s_%s_list" %(app_label,model_name))
        return _url

    def get_change_url(self,obj):
        model_name = self.model._meta.model_name
        app_label = self.model._meta.app_label
        _url = reverse("%s_%s_change" %(app_label,model_name),args=(obj.pk,))
        return _url

    # 复选框,编辑,删除
    def checkbox(self,obj=None, header=False):
        if header:
            return mark_safe("<input id='choice' type='checkbox'>")
        return mark_safe("<input class='choice_item' type='checkbox' name='selected_pk' value='%s'>"%obj.pk)

    def edit(self,obj=None, header=False):
        if header:
            return "操作"
        # 方案1:固定url
        # return mark_safe("<a href=/stark/app01/userinfo/%s/change>编辑</a>")
        # 方案2:拼接url
        # return mark_safe("<a href='%s/change'>编辑</a>")

        # 方案3:反向解析
        model_name = self.model._meta.model_name
        app_label = self.model._meta.app_label
        _url = reverse("%s_%s_change"%(app_label,model_name),args=(obj.pk,))
        # print("_url",_url)
        return mark_safe("<a href='%s'>编辑</a>"%_url)

    def deletes(self,obj=None, header=False):
        if header:
            return "操作"
        model_name = self.model._meta.model_name
        app_label = self.model._meta.app_label
        _url = reverse("%s_%s_delete"%(app_label,model_name),args=(obj.pk,))
        return mark_safe("<a href='%s'>删除</a>"%_url)



    # ModelForm组件渲染  list、增、删、改页面
    def get_modelform_class(self):
        """ModelForm组件"""
        if not self.modelform_class:
            from django.forms import ModelForm
            class ModelFormDemo(ModelForm):
                class Meta:
                    model = self.model
                    fields = "__all__"
            return ModelFormDemo
        else:
            return self.modelform_class

    def new_list_play(self):
        """构建 ['checkbox','pk', 'name', 'age', edit,'delete']"""
        temp = []
        temp.append(ModelStark.checkbox)
        temp.extend(self.list_display)
        if not self.list_display_links:
            temp.append(ModelStark.edit)
        temp.append(ModelStark.deletes)
        return temp

    # action = ['delete',...]
    def new_actions(self):
        temp = []
        temp.append(ModelStark.patch_delete)        # delete添加
        temp.extend(self.actions)   # 如果定义新的,就扩展到temp中
        return temp

    '''
    def list_view(self,request):
        ret1 = self.model.objects.filter(title__startswith='py')
        ret2 = self.model.objects.filter(price__in=[11,22,33,44,55])
        ret3 = self.model.objects.filter(price__range=[10,20])
        ret4 = self.model.objects.filter(title__contains='O')
        ret5 = self.model.objects.filter(title__icontains='O')
        return HttpResponse("过滤成功")
    '''

    def get_search_condition(self,request):
        """search模糊查询"""
        key_word = request.GET.get("q",'')
        self.key_word = key_word

        search_connection = Q()
        if key_word:
            search_connection.connector = "or"
            for search_field in self.search_fields:
                search_connection.children.append((search_field+"__contains", key_word))

        return search_connection


    def get_filter_condition(self,request):
        """filter过滤处理"""
        filter_condition = Q()      # 并且
        for filter_field,val in request.GET.items():
            if filter_field in self.list_filter:        # list_filter = ['publish','authors']
                filter_condition.children.append((filter_field,val))
        return filter_condition


    def list_view(self, request):
        if request.method == 'POST':
            # print('post',request.POST)
            action = request.POST.get("action")                     # action': ['patch_init'],
            if action:
                selected_pk = request.POST.getlist('selected_pk')       # 'selected_pk': ['5']}>
                action_func = getattr(self,action)  # 反射查询 action       # 取出实例方法

                queryset = self.model.objects.filter(pk__in=selected_pk)        # 查询
                ret = action_func(request,queryset)    # 执行action()     # 执行实例方法()
                # return ret

        # 获取search的Q对象
        search_connection = self.get_search_condition(request)

        # 获取filter构建Q对象
        filter_condition = self.get_filter_condition(request)

        # 筛选获取当前表所有数据
        # data_list = self.model.objects.all().filter(search_connection)
        data_list = self.model.objects.all().filter(search_connection).filter(filter_condition)

        #按照showlist展示页面, 构建表头,表单
        show_list = ShowList(self,data_list,request)  # self=ModelSTark实例对象

        # 构建一个查看addurl
        add_url = self.get_add_url()
        return render(request,'list_view.html', locals())

    def add_view(self, request):
        ModelFormDemo=self.get_modelform_class()
        form = ModelFormDemo()

        # 打印form的每个字段
        from django.forms.boundfield import BoundField
        from django.forms.models import ModelChoiceField
        from django.forms.models import ModelMultipleChoiceField

        for bfield in form:
            # print(type(bfield))  # <class 'django.forms.boundfield.BoundField'>
            # print('field',bfield.field)   # <django.forms.models.ModelChoiceField object at 0x000000F2C0DEDC50>
            # print('name',bfield.name)    # publish

            if isinstance(bfield.field,ModelChoiceField):
                bfield.is_pop = True
                # print(bfield.field.queryset.model)     # 一对多或多对多字段的关联模型
                # <class 'app01.models.Publish'>  <class 'app01.models.Author'>

                # print(bfield.field.queryset.model._meta)  # app01.author
                related_app_name = bfield.field.queryset.model._meta.app_label  # app01
                related_model_name = bfield.field.queryset.model._meta.model_name # author

                _url = reverse("%s_%s_add"%(related_app_name,related_model_name))
                bfield.url = _url+"?pop_res_id=id_%s"%bfield.name

        if request.method == "POST":
            form = ModelFormDemo(request.POST)
            if form.is_valid():
                obj = form.save()

                # window.open添加页面 要返回的数据
                pop_res_id = request.GET.get('pop_res_id')
                if pop_res_id:
                    res = {"pk":obj.pk,'text':str(obj),'pop_res_id':pop_res_id}
                    return render(request,'pop_view.html',locals())
                else:
                    return redirect(self.get_list_url())

        return render(request, "add_view.html",locals())

    def delete_view(self, request, id):
        url = self.get_list_url()
        if request.method == "POST":
            self.model.objects.filter(pk=id).delete()
            return redirect(url)
        return render(request, "delete_view.html", locals())

    def change_view(self, request, id):
        edit_obj = self.model.objects.filter(pk=id).first()

        ModelFormDemo=self.get_modelform_class()
        form = ModelFormDemo(instance=edit_obj)
        if request.method == "POST":
            form = ModelFormDemo(request.POST,instance=edit_obj)
            if form.is_valid():
                form.save()
                return redirect(self.get_list_url())

        return render(request, "change_view.html",locals())


    #构造 add/delete/change
    def get_urls2(self):
        model_name = self.model._meta.model_name
        app_label = self.model._meta.app_label

        temp = []
        temp.append(url(r'^$', self.list_view, name='%s_%s_list'%(app_label,model_name)))
        temp.append(url(r'^add/', self.add_view, name='%s_%s_add'%(app_label,model_name)))
        temp.append(url(r'^(\d+)/delete/', self.delete_view, name='%s_%s_delete'%(app_label,model_name)))
        temp.append(url(r'^(\d+)/change/', self.change_view, name='%s_%s_change'%(app_label,model_name)))

        return temp

    @property
    def urls2(self):

        return self.get_urls2(), None, None


class StarkSite(object):
    """site单例类"""
    def __init__(self):
        self._registry = {}

    def register(self,model, stark_class=None):
        """注册"""
        if not stark_class:
            stark_class = ModelStark

        self._registry[model] = stark_class(model,self)

    def get_urls(self):
        """构造一层urls app01/book"""
        temp = []
        for model, stark_class_obj in self._registry.items():
            # print(model, 'stark_clas_obj', stark_class_obj)  # 不同的model模型表
            """
             <class 'app01.models.UserInfo'> ----> <app01.starkadmin.UserConfig object at 0x00000072DDB65198>
             <class 'app01.models.Book'> ----> <stark.service.stark.ModelStark object at 0x00000072DDB65240>
             """

            app_label = model._meta.app_label     # app01
            model_name = model._meta.model_name   # book
            # temp.append(url(r'^%s/%s'%(app_label, model_name),([],None,None)))
            temp.append(url(r'^%s/%s/'%(app_label, model_name),stark_class_obj.urls2))
            """
               path('app01/userinfo/',UserConfig(Userinfo,site).urls2),
               path('app01/book/',ModelStark(Book,site).urls2),
            """


        return temp

    @property
    def urls(self):

        # return [],None,None
        return self.get_urls(),None,None

site = StarkSite()   # 单例对象
View Code

 3、list_View.html

{% extends 'base.html' %}

{% block title %}
    <title>list页面</title>
{% endblock %}

{% block css %}
    <style type="text/css">
        .active {
            color: red !important;
        }

        .filter a {
            text-decoration: none;
            color: grey;
        }
    </style>
{% endblock %}
{% block content %}
    <div class="col-md-9">

        <a class="btn btn-primary" href="{{ add_url }}">添加数据</a>

        {% if show_list.config.search_fields %}
            <form action="" method="get">
                <input type="text" class="form-control" style="width: 30%;display: inline-block;margin-top: 8px"
                       name="q"
                       value="{{ show_list.config.key_word }}">
                <button class="btn btn-success">submit</button>
            </form>
        {% endif %}


        <form action="" method="post">
            {% csrf_token %}
            <select name="action" class="form-control"
                    style="display: inline-block;width: 200px;margin: 8px 8px 8px 0;height: 35px;vertical-align: -2px">
                <option value="">-------</option>
                {% for item in show_list.get_action_list %}
                    <option value="{{ item.name }}">{{ item.desc }}</option>
                {% endfor %}
            </select>
            <button type="submit" class="btn btn-primary">Go</button>


            <table class="table table-bordered table-striped">
                <tr>
                    {% for header in show_list.get_header %}
                        <th>{{ header }}</th>
                    {% endfor %}
                </tr>

                {% for data in show_list.get_body %}
                    <tr>
                        {% for item in data %}
                            <td>{{ item }}</td>
                        {% endfor %}

                    </tr>
                {% endfor %}
            </table>
        </form>

        <nav>
            <ul class="pagination">
                {{ show_list.pagination.page_html|safe }}
            </ul>
        </nav>
    </div>
    <div class="col-md-3">
        <div class="filter">
            {% for filter_field, linktags in show_list.get_filter_linktags.items %}

                <div class="well">
                    <p>{{ filter_field.upper }}</p>

                    {% for link in linktags %}
                        <p>{{ link|safe }}</p>
                    {% endfor %}

                </div>

            {% endfor %}

        </div>
    </div>
{% endblock %}




{% block javascript %}
    <script type="text/javascript">
        $('#choice').click(function () {
            if ($(this).prop('checked')) {   //对象自身属性中是否具有指定的属性
                $('.choice_item').prop("checked", true)
            } else {
                $('.choice_item').prop("checked", false)
            }
        })
    </script>
{% endblock %}
View Code

4、add_view.html

{% extends 'base.html' %}

{% block title %}
    <title>add页面</title>
{% endblock %}


{% block css %}
    <style type="text/css">
        input, 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;
        }

        .error {
            color: red;
        }
    </style>
{% endblock %}

{% block header %}
    <h3>add页面</h3>
{% endblock %}

{% block content %}
    <div class="col-md-6 col-xs-8 col-md-offset-4">
        {% include 'form.html' %}
    </div>


{% endblock %}

{% block javascript %}
    <script type="text/javascript">
        //打开open页面
        function pop(url) {
            window.open(url, '', 'width=600,height=400,left=100,right=100')
        }
        //open页面操作完成,返回数据
        function pop_response(pk,text,id) {
            //选择哪一个select标签
            // option的文本值与value值
            var $option =$('<option>');     //<option></option>
            $option.html(text);  //<option>南京出版社</option>
            $option.val(pk);       //<option val=111>南京出版社</option>
            $option.attr("selected","selected");       //<option val=111 selected>南京出版社</option>
            $('#'+id).append($option)
        }
    </script>
{% endblock %}
View Code

 5、form.html

<form action="" method="post" novalidate>
    {% for field in form %}
        {% csrf_token %}
        <div class="form-group" style="position:relative;">
            <label for="">{{ field.label }}</label>
            {{ field }}
            <span class="error pull-right">{{ field.errors.0 }}</span>
            {% if field.is_pop %}
                <a onclick="pop('{{ field.url }}')" href=""
                   style="font-size: 25px;position: absolute;top: 25px;right: -25px"><span>+</span></a>
            {% endif %}
        </div>
    {% endfor %}
    <br>
    <button class="btn btn-success pull-right">提交</button>
</form>
View Code

6、pop_view.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>


<script>
    //pop页面返回到上一个页面的数据
{#    window.opener.pop_response();#}
    window.opener.pop_response('{{ res.pk }}','{{ res.text }}','{{ res.pop_res_id }}');

    window.close();
</script>

</body>
</html>
View Code

1、Window open() 方法

 

效果图

 

2、admin的pop添加按钮

3、stark之pop功能

POP功能:   

  1.如何只有多对多和一对多字段后面才渲染 "+"
  2."+"的对应的跳转路径
  3.保存添加记录的同时,应该将原页面对应的下拉菜单添加该记录。

1、

 

2、多对多字段如何渲染

3、isinstance判断类型

4、  一对多或多对多字段的关联模型

 

5、bootstrap页面自适应col-xs-8

 

 6、model表显示的是__str__

 

7、构造url

 

 

8、传递数据,window.open使用

 

 3、知识点总结

1、pop功能:

  1.在一对多和多对多字段后渲染 +
2.+对应的跳转路径
3.保存添加记录同时,将原页面的对应的下拉菜单中添加该记录

2、在一对多和多对多字段后渲染+   

 后台需要先判断 是否是 一对多 多对多字段
modelform, 遍历
for bfield in form:
print(bfield.field) # 是每个form字段对象
所以:判断是否是一对多,多对多字段
if isinstance(bfield.field, ModelChoiceField):
bfield.is_pop = True # 为特殊字段加上特有属性,方便前端判断。

注意:ModelMultipleChoiceField(多对多) 继承 ModelChoiceField(一对多)
ModelChoiceField 继承 ChoiceField

3、+对应的跳转路径

    form表单得一对多,多对多得字段对象
bfield.field.queryset.model # 相关联得模型!!<class 'app01.models.Publish'>
#(模型表得对象去找 filter_field_obj.rel.to.objects.all(),到to是模型。)

根据queryset找model queryset.model
根据model找queryset model.objects.all()

related_model_name = bfield.field.queryset.model._meta.model_name # publish
related_app_label = bfield.field.queryset.model._meta.app_label # app01

反向解析url
_url = reverse("%s_%s_add" % (related_app_label, related_model_name))

# 为bfield添加自己特有的url,
# ?后面是为了,区分是top,还是正常页面打开/add/,方便之后关闭,以及赋值。
bfield.url = _url + "?pop_res_id=id_%s" % bfield.name

4、关闭弹出得top页面

    top弹出,关闭页面,回到到原页面;
正常添加,跳转到list页面;

返回 res = {"pk":obj.pk, 'text':str(obj), "pop_res_id": pop_res_id}
pop.html,方便关闭pop页面

pop.html:
关闭以及将接收得数据传到原页面上!
window.opener.pop_response("{{ res.pk}}","{{ res.text }}","{{ res.pop_res_id }}");
window.close()

5、原页面接收数据,并显示刚添加得数据(window.opener)

    拿到 id, text, pop_res_id
动态创建 option append到对应得下拉框中,并选中;
var $option = $("<option>");
$option.html(text);
$option.val(pk);
$option.attr('selected','selected');

$('#'+pop_res_id).append($option)

6、前端展示:定位,(父相子绝)

     <div style="position: relative">
        {% if field.is_pop %}
            <a onclick="pop('{{ field.url }}')"><span style="font-size: 23px;position: absolute; right: -23px; top: 25px;">+</span></a>
        {% endif %}
     </div>

7、补充:

ChoiceFiled
ModelChoiceFiled(ChoiceFiled) ---- select(单选) --- ForeignKey
MultiModelChoiceFiled (ModelChoiceFiled)----select(多选) --- ManyToManyField

Book模型,form表单,modelform;
modelform帮我们转成了form表单;

bootstrap页面自适应: col-xs-8

代码注释总结:

首先准备工作做完:
    window.opener.pop_response('{{ res.pk }}','{{ res.text }}','{{ res.pop_res_id }}');
    window.close()
在pop页面关闭前把指定的值传参给主页面执行,然后执行一个close,关闭掉自己。

2.增加视图函数

 # 增加数据视图函数
    def add_view(self,request):
        ModelFormDemo=self.get_modelform_class()
        form = ModelFormDemo()
        #循环每个form字段,看看他们的类型是不是一对多和对多类型,是的话需要前端添加+号
        for bfield in form:    循环ModelForm的每一个字段,把多对多和一对多字段筛选出来。
            print(bfield.field) #字段对象
            print(bfield.name) #字段名(字符串)
            from django.forms.models import ModelChoiceField
            if isinstance(bfield.field,ModelChoiceField):
                bfield.is_pop=True           如果需要加+的话,那么赋一个True的值。方便前端判定
                    【
                    {% if field.is_pop %}
                        <a onclick="pop('{{ field.url }}')" href="" style="position: absolute;right: -30px;top: 26px"><spanstyle="font-size: 26px">+</span></a>
                    {% endif %}
                    】

                #print(bfield.field.queryset.model)
    #这里需要注意,pop出来页面需要添加的表名和app名,和主页面的添加是不一样的。
 

注意:

 related_model_name=bfield.field.queryset.model._meta.model_name
 related_app_label=bfield.field.queryset.model._meta.app_label

  #通过一个方向解析拿到一个url.
  _url=reverse("%s_%s_add"%(related_app_label,related_model_name))

  #要知道的是,点的哪个加号,在URL后加一个这个字段的名字,做一个记号。
  bfield.url=_url+"?pop_res_id=id_%s"%bfield.name

视图函数中继续:

        if request.method=="POST":
            form = ModelFormDemo(request.POST)
            if form.is_valid():
                obj=form.save()
                pop_res_id=request.GET.get("pop_res_id") #每一个modelform渲染到前端的id是id_+"字段名"

                #<input type="text" name="title" maxlength="32" required="" id="id_title">
                

                if pop_res_id:
                    #如果能取到id的话,表示是pop页面而不是主页面的添加。
                    res={"pop_res_id":pop_res_id,"pk":obj.pk,"text":str(obj)}
                    #pop页面添加成功以后,obj也就有了值,就是当前添加这条数据的各种值,
                    #取到id,添加的字段,添加的内容给了前端模板。
                    return render(request,"pop.html",locals())
                else:
                    return redirect(self.get_list_url())

        return render(request,"add_view.html",locals())
前端模板拿到后端传过来的url以后,渲染到+上。

    http://127.0.0.1:8000/stark/app01/publish/add/?pop_res_id=id_publish
    http://127.0.0.1:8000/stark/app01/author/add/?pop_res_id=id_authors
    点击不同的+,url也不同。pop_res_id也都不同。
    同时给+绑定一个弹框事件:
        function pop(url) {
        window.open(url,"","width=600,height=400,top=100,left=100")
    }
     打开框以后,添加完毕点击提交后,

  window.opener.pop_response('{{ res.pk }}','{{ res.text }}','{{ res.pop_res_id }}');
  window.close()
  #把值取到并且把窗口关闭。

 

    最后就是

 function pop_response(pk,text,pop_res_id){
                var $option = $("<option>");          //创建一个标签
                $option.html(text);                   //将添加的数据的文本值给了这个标签内容
                $option.val(pk);                      //赋一个value值,值是这条记录的PK
                $option.attr("selected","selected");  //默认为选中
                $("#"+pop_res_id).append($option)     //哪个标签后添加的,就把这个option放到哪个标签下。
            }
    #主添加页面拿到关闭前通过参数传过来的值以后,渲染出一个option标签,把内容,和id,等全部写好,最后加到指定的select标签下面。

4、coding代码

1、starkadmin

from django.shortcuts import HttpResponse
from stark.service import stark
from .models import *
from django.forms import ModelForm

class AuthorConfig(stark.ModelStark):
    list_display = ['nid', 'name', 'age']
    list_display_links = ['name','age']


class BookModelForm(ModelForm):
    class Meta:
        model = Book
        fields = "__all__"

        labels = {
            "authors":"作者",
            "publishDate":"出版日期",
        }

class BookConfig(stark.ModelStark):
    # list_display = ['title', 'price','publish','authors']
    list_display = ['__str__',]
    list_display_links = ['title']
    modelform_class = BookModelForm
    search_fields = ['title','price']
    list_filter = ['title','publish','authors']  # 一对多,多对多字段

    # 批量修改数据
    def patch_init(self,request,queryset):
        queryset.update(price=111)

        # return HttpResponse("批量初始化OK")

    patch_init.short_description = "批量初始化"

    actions = [patch_init]


stark.site.register(Book,BookConfig)
stark.site.register(Publish)
stark.site.register(Author,AuthorConfig)
stark.site.register(AuthorDetail)

# print(stark.site._registry)
View Code

 2、stark/service/stark.py

# -*- coding: utf-8 -*-
# @Time    : 2018/08/17 0017 14:46
# @Author  : Venicid
from django.conf.urls import url
from django.shortcuts import HttpResponse,render,redirect

from django.utils.safestring import mark_safe
from django.urls import reverse
from django.db.models import Q  # 与或非
from django.db.models.fields.related import ForeignKey
from django.db.models.fields.related import ManyToManyField
import copy

from stark.utils.page import Pagination
class ShowList(object):
    def __init__(self,config, data_list,request):
        self.config = config  # MOdelStark实例对象
        self.data_list = data_list      # 数据
        self.request =request

        # 分页
        data_count = self.data_list.count()
        current_page = int(self.request.GET.get('page',1))
        base_path = self.request.path
        self.pagination = Pagination(current_page,data_count,base_path,self.request.GET,per_page_num=10, pager_count=11,)

        # 分页后的数据
        self.page_data = self.data_list[self.pagination.start:self.pagination.end]

        # actions 批量初始化,字段
        # self.actions = self.config.actions # [patch_init]
        self.actions = self.config.new_actions() # [pathch_delete,patch_init,]
        # 构建数据[{'name':'path_init',"desc":'xxxxx'}]

    # filter的tag如何生成的
    def get_filter_linktags(self):
        link_dic = {}
        for filter_field in self.config.list_filter:        # ['title','publish','authors']
            # 1.获取url中的相关字段,后面比较
            current_id = self.request.GET.get(filter_field,0)
            pararms = copy.deepcopy(self.request.GET)

            # 2 页面生成  各种字段
            filter_field_obj = self.config.model._meta.get_field(filter_field)
            print(filter_field_obj,type(filter_field_obj))
            # app01.Book.publish  < class 'django.db.models.fields.related.ForeignKey'>
            # app01.Book.authors < class 'django.db.models.fields.related.ManyToManyField'>

            # print('rel...',filter_field_obj.re)     # <ManyToOneRel: app01.book>
            # print('rel...',filter_field_obj.re.to.objects.all())  # <QuerySet [<Publish: 南京出版社>, <Publish: 北京出版社>]>

            # 解决步骤
            # print('rel...',filter_field_obj.__dict__)
            # print('rel...',filter_field_obj.remote_field)
            # print('rel...',filter_field_obj.remote_field.__dict__)
            # print("rel...", filter_field_obj.remote_field.model.objects.all())
            # <QuerySet [<Publish: 南京出版社>, <Publish: 北京出版社>]>
            # <QuerySet [<Author: jack>, <Author: tom>]>

            # 一对一字段or一对多字段
            if isinstance(filter_field_obj,ForeignKey) or isinstance(filter_field_obj,ManyToManyField):
                data_list = filter_field_obj.remote_field.model.objects.all()
            else:
                # 普通字段
                data_list = self.config.model.objects.all().values('pk',filter_field)

            # 3、 生成标签的href
            temp = []
            if pararms.get(filter_field):
                del pararms[filter_field]
                temp.append("<a href='?%s'>全部</a>"%pararms.urlencode())
            else:
                temp.append("<a href='#' class='active'>全部</a>")

            # 处理filter字段的href
            for obj in data_list:
                # print(data_list)
                # 一对一,一对多字段
                if isinstance(filter_field_obj, ForeignKey) or isinstance(filter_field_obj, ManyToManyField):
                    pk = obj.pk
                    text = str(obj)
                    pararms[filter_field] = pk
                else:
                    # 普通字段
                    pk = obj.get('pk')
                    text = obj.get(filter_field)
                    pararms[filter_field] = text

                _url = pararms.urlencode()
                # print(type(current_id),type(pk),type(text))
                if str(current_id) == str(pk) or str(current_id) ==str(text):
                    link_tag = "<a href='?%s' class='active'>%s</a>"%(_url,text)
                else:
                    link_tag = "<a href='?%s'>%s</a>"%(_url,text)
                temp.append(link_tag)
            link_dic[filter_field] = temp

        return link_dic

    def get_action_list(self):
        """action批量初始化,构架数据"""
        temp = []
        for action in self.actions:
            temp.append(
                {'name':action.__name__,                # class的类名
                 "desc":action.short_description        # class的属性
                 }
            )
        return temp

    def get_header(self):
        # 构建表头
        header_list = []  # # header_list = ['选择','pk',...'操作','操作']
        for field in self.config.new_list_play():
            if callable(field):
                # header_list.append(field.__name__)
                val = field(self.config, header=True)
                header_list.append(val)
            else:
                if field == "__str__":
                    header_list.append(self.config.model._meta.model_name.upper())
                else:
                    val = self.config.model._meta.get_field(field).verbose_name    # 中文名称
                    header_list.append(val)

        return header_list

    def get_body(self):
        # 构建表单
        new_data_list = []
        for obj in self.page_data:    #分页后的数据               # Book表模型,Author表模型
            temp = []
            for field in self.config.new_list_play():     #  ["__str__"]  ['name','age']
                if callable(field):                 # edit()  可调用的
                    val = field(self.config,obj)           # 直接调用edit()函数
                else:
                    try:
                        field_obj = self.config.model._meta.get_field(field)
                        if isinstance(field_obj,ManyToManyField):
                            ret = getattr(obj,field).all()       # 反射  obj是实例对象,name是方法
                            t = []
                            for obj in ret:
                                t.append(str(obj))
                            val = ','.join(t)

                        else:
                            val = getattr(obj, field)
                            # list_display_links 按钮
                            if field in self.config.list_display_links:
                                _url = self.config.get_change_url(self,obj)
                                val = mark_safe("<a href='%s'>%s</a>"%(_url,val))

                    # __str__ 的步骤
                    except  Exception as e:
                        val = getattr(obj,field)                #  <bound method Book.__str__ of <Book: php>
                        _url = self.config.get_change_url(obj)   # /app01/book/3/change/
                        val = mark_safe("<a href='%s'> %s </a>" % (_url, val()))

                temp.append(val)

            new_data_list.append(temp)

        # print('new_data_list',new_data_list)        # 构造数据  [['jack', 44], ['mark', 33]]

        return new_data_list


class ModelStark(object):
    list_display = ['__str__',]  # 子类中没有,直接用父类自己的
    list_display_links = []
    modelform_class = []
    search_fields = []  # 模糊查询字段
    actions = []
    list_filter = []        # 过滤字段


    # 批量删除
    def patch_delete(self,request,queryset):
        queryset.delete()

    patch_delete.short_description = "Delete selected "


    def __init__(self,model, site):
        self.model = model
        self.site = site

    # 增删改查url
    def get_add_url(self):
        model_name = self.model._meta.model_name
        app_label = self.model._meta.app_label
        _url = reverse("%s_%s_add" %(app_label,model_name))
        return _url

    def get_list_url(self):
        model_name = self.model._meta.model_name
        app_label = self.model._meta.app_label
        _url = reverse("%s_%s_list" %(app_label,model_name))
        return _url

    def get_change_url(self,obj):
        model_name = self.model._meta.model_name
        app_label = self.model._meta.app_label
        _url = reverse("%s_%s_change" %(app_label,model_name),args=(obj.pk,))
        return _url

    # 复选框,编辑,删除
    def checkbox(self,obj=None, header=False):
        if header:
            return mark_safe("<input id='choice' type='checkbox'>")
        return mark_safe("<input class='choice_item' type='checkbox' name='selected_pk' value='%s'>"%obj.pk)

    def edit(self,obj=None, header=False):
        if header:
            return "操作"
        # 方案1:固定url
        # return mark_safe("<a href=/stark/app01/userinfo/%s/change>编辑</a>")
        # 方案2:拼接url
        # return mark_safe("<a href='%s/change'>编辑</a>")

        # 方案3:反向解析
        model_name = self.model._meta.model_name
        app_label = self.model._meta.app_label
        _url = reverse("%s_%s_change"%(app_label,model_name),args=(obj.pk,))
        # print("_url",_url)
        return mark_safe("<a href='%s'>编辑</a>"%_url)

    def deletes(self,obj=None, header=False):
        if header:
            return "操作"
        model_name = self.model._meta.model_name
        app_label = self.model._meta.app_label
        _url = reverse("%s_%s_delete"%(app_label,model_name),args=(obj.pk,))
        return mark_safe("<a href='%s'>删除</a>"%_url)



    # ModelForm组件渲染  list、增、删、改页面
    def get_modelform_class(self):
        """ModelForm组件"""
        if not self.modelform_class:
            from django.forms import ModelForm
            class ModelFormDemo(ModelForm):
                class Meta:
                    model = self.model
                    fields = "__all__"
            return ModelFormDemo
        else:
            return self.modelform_class

    def new_list_play(self):
        """构建 ['checkbox','pk', 'name', 'age', edit,'delete']"""
        temp = []
        temp.append(ModelStark.checkbox)
        temp.extend(self.list_display)
        if not self.list_display_links:
            temp.append(ModelStark.edit)
        temp.append(ModelStark.deletes)
        return temp

    # action = ['delete',...]
    def new_actions(self):
        temp = []
        temp.append(ModelStark.patch_delete)        # delete添加
        temp.extend(self.actions)   # 如果定义新的,就扩展到temp中
        return temp

    '''
    def list_view(self,request):
        ret1 = self.model.objects.filter(title__startswith='py')
        ret2 = self.model.objects.filter(price__in=[11,22,33,44,55])
        ret3 = self.model.objects.filter(price__range=[10,20])
        ret4 = self.model.objects.filter(title__contains='O')
        ret5 = self.model.objects.filter(title__icontains='O')
        return HttpResponse("过滤成功")
    '''

    def get_search_condition(self,request):
        """search模糊查询"""
        key_word = request.GET.get("q",'')
        self.key_word = key_word

        search_connection = Q()
        if key_word:
            search_connection.connector = "or"
            for search_field in self.search_fields:
                search_connection.children.append((search_field+"__contains", key_word))

        return search_connection


    def get_filter_condition(self,request):
        """filter过滤处理"""
        filter_condition = Q()      # 并且
        for filter_field,val in request.GET.items():
            if filter_field in self.list_filter:        # list_filter = ['publish','authors']
                filter_condition.children.append((filter_field,val))
        return filter_condition


    def list_view(self, request):
        if request.method == 'POST':
            # print('post',request.POST)
            action = request.POST.get("action")                     # action': ['patch_init'],
            if action:
                selected_pk = request.POST.getlist('selected_pk')       # 'selected_pk': ['5']}>
                action_func = getattr(self,action)  # 反射查询 action       # 取出实例方法

                queryset = self.model.objects.filter(pk__in=selected_pk)        # 查询
                ret = action_func(request,queryset)    # 执行action()     # 执行实例方法()
                # return ret

        # 获取search的Q对象
        search_connection = self.get_search_condition(request)

        # 获取filter构建Q对象
        filter_condition = self.get_filter_condition(request)

        # 筛选获取当前表所有数据
        # data_list = self.model.objects.all().filter(search_connection)
        data_list = self.model.objects.all().filter(search_connection).filter(filter_condition)

        #按照showlist展示页面, 构建表头,表单
        show_list = ShowList(self,data_list,request)  # self=ModelSTark实例对象

        # 构建一个查看addurl
        add_url = self.get_add_url()
        return render(request,'list_view.html', locals())

    def add_view(self, request):
        ModelFormDemo=self.get_modelform_class()
        form = ModelFormDemo()

        # 打印form的每个字段
        from django.forms.boundfield import BoundField
        from django.forms.models import ModelChoiceField
        from django.forms.models import ModelMultipleChoiceField

        for bfield in form:
            # print(type(bfield))  # <class 'django.forms.boundfield.BoundField'>
            # print('field',bfield.field)   # <django.forms.models.ModelChoiceField object at 0x000000F2C0DEDC50>
            # print('name',bfield.name)    # publish

            if isinstance(bfield.field,ModelChoiceField):
                bfield.is_pop = True
                # print(bfield.field.queryset.model)     # 一对多或多对多字段的关联模型
                # <class 'app01.models.Publish'>  <class 'app01.models.Author'>

                # print(bfield.field.queryset.model._meta)  # app01.author
                related_app_name = bfield.field.queryset.model._meta.app_label  # app01
                related_model_name = bfield.field.queryset.model._meta.model_name # author

                _url = reverse("%s_%s_add"%(related_app_name,related_model_name))
                bfield.url = _url+"?pop_res_id=id_%s"%bfield.name

        if request.method == "POST":
            form = ModelFormDemo(request.POST)
            if form.is_valid():
                obj = form.save()

                # window.open添加页面 要返回的数据
                pop_res_id = request.GET.get('pop_res_id')
                if pop_res_id:
                    res = {"pk":obj.pk,'text':str(obj),'pop_res_id':pop_res_id}
                    return render(request,'pop_view.html',locals())
                else:
                    return redirect(self.get_list_url())

        return render(request, "add_view.html",locals())

    def delete_view(self, request, id):
        url = self.get_list_url()
        if request.method == "POST":
            self.model.objects.filter(pk=id).delete()
            return redirect(url)
        return render(request, "delete_view.html", locals())

    def change_view(self, request, id):
        edit_obj = self.model.objects.filter(pk=id).first()

        ModelFormDemo=self.get_modelform_class()
        form = ModelFormDemo(instance=edit_obj)
        if request.method == "POST":
            form = ModelFormDemo(request.POST,instance=edit_obj)
            if form.is_valid():
                form.save()
                return redirect(self.get_list_url())

        return render(request, "change_view.html",locals())


    #构造 add/delete/change
    def get_urls2(self):
        model_name = self.model._meta.model_name
        app_label = self.model._meta.app_label

        temp = []
        temp.append(url(r'^$', self.list_view, name='%s_%s_list'%(app_label,model_name)))
        temp.append(url(r'^add/', self.add_view, name='%s_%s_add'%(app_label,model_name)))
        temp.append(url(r'^(\d+)/delete/', self.delete_view, name='%s_%s_delete'%(app_label,model_name)))
        temp.append(url(r'^(\d+)/change/', self.change_view, name='%s_%s_change'%(app_label,model_name)))

        return temp

    @property
    def urls2(self):

        return self.get_urls2(), None, None


class StarkSite(object):
    """site单例类"""
    def __init__(self):
        self._registry = {}

    def register(self,model, stark_class=None):
        """注册"""
        if not stark_class:
            stark_class = ModelStark

        self._registry[model] = stark_class(model,self)

    def get_urls(self):
        """构造一层urls app01/book"""
        temp = []
        for model, stark_class_obj in self._registry.items():
            # print(model, 'stark_clas_obj', stark_class_obj)  # 不同的model模型表
            """
             <class 'app01.models.UserInfo'> ----> <app01.starkadmin.UserConfig object at 0x00000072DDB65198>
             <class 'app01.models.Book'> ----> <stark.service.stark.ModelStark object at 0x00000072DDB65240>
             """

            app_label = model._meta.app_label     # app01
            model_name = model._meta.model_name   # book
            # temp.append(url(r'^%s/%s'%(app_label, model_name),([],None,None)))
            temp.append(url(r'^%s/%s/'%(app_label, model_name),stark_class_obj.urls2))
            """
               path('app01/userinfo/',UserConfig(Userinfo,site).urls2),
               path('app01/book/',ModelStark(Book,site).urls2),
            """


        return temp

    @property
    def urls(self):

        # return [],None,None
        return self.get_urls(),None,None

site = StarkSite()   # 单例对象
View Code

 3、list_View.html

{% extends 'base.html' %}

{% block title %}
    <title>list页面</title>
{% endblock %}

{% block css %}
    <style type="text/css">
        .active {
            color: red !important;
        }

        .filter a {
            text-decoration: none;
            color: grey;
        }
    </style>
{% endblock %}
{% block content %}
    <div class="col-md-9">

        <a class="btn btn-primary" href="{{ add_url }}">添加数据</a>

        {% if show_list.config.search_fields %}
            <form action="" method="get">
                <input type="text" class="form-control" style="width: 30%;display: inline-block;margin-top: 8px"
                       name="q"
                       value="{{ show_list.config.key_word }}">
                <button class="btn btn-success">submit</button>
            </form>
        {% endif %}


        <form action="" method="post">
            {% csrf_token %}
            <select name="action" class="form-control"
                    style="display: inline-block;width: 200px;margin: 8px 8px 8px 0;height: 35px;vertical-align: -2px">
                <option value="">-------</option>
                {% for item in show_list.get_action_list %}
                    <option value="{{ item.name }}">{{ item.desc }}</option>
                {% endfor %}
            </select>
            <button type="submit" class="btn btn-primary">Go</button>


            <table class="table table-bordered table-striped">
                <tr>
                    {% for header in show_list.get_header %}
                        <th>{{ header }}</th>
                    {% endfor %}
                </tr>

                {% for data in show_list.get_body %}
                    <tr>
                        {% for item in data %}
                            <td>{{ item }}</td>
                        {% endfor %}

                    </tr>
                {% endfor %}
            </table>
        </form>

        <nav>
            <ul class="pagination">
                {{ show_list.pagination.page_html|safe }}
            </ul>
        </nav>
    </div>
    <div class="col-md-3">
        <div class="filter">
            {% for filter_field, linktags in show_list.get_filter_linktags.items %}

                <div class="well">
                    <p>{{ filter_field.upper }}</p>

                    {% for link in linktags %}
                        <p>{{ link|safe }}</p>
                    {% endfor %}

                </div>

            {% endfor %}

        </div>
    </div>
{% endblock %}




{% block javascript %}
    <script type="text/javascript">
        $('#choice').click(function () {
            if ($(this).prop('checked')) {   //对象自身属性中是否具有指定的属性
                $('.choice_item').prop("checked", true)
            } else {
                $('.choice_item').prop("checked", false)
            }
        })
    </script>
{% endblock %}
View Code

4、add_view.html

{% extends 'base.html' %}

{% block title %}
    <title>add页面</title>
{% endblock %}


{% block css %}
    <style type="text/css">
        input, 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;
        }

        .error {
            color: red;
        }
    </style>
{% endblock %}

{% block header %}
    <h3>add页面</h3>
{% endblock %}

{% block content %}
    <div class="col-md-6 col-xs-8 col-md-offset-4">
        {% include 'form.html' %}
    </div>


{% endblock %}

{% block javascript %}
    <script type="text/javascript">
        //打开open页面
        function pop(url) {
            window.open(url, '', 'width=600,height=400,left=100,right=100')
        }
        //open页面操作完成,返回数据
        function pop_response(pk,text,id) {
            //选择哪一个select标签
            // option的文本值与value值
            var $option =$('<option>');     //<option></option>
            $option.html(text);  //<option>南京出版社</option>
            $option.val(pk);       //<option val=111>南京出版社</option>
            $option.attr("selected","selected");       //<option val=111 selected>南京出版社</option>
            $('#'+id).append($option)
        }
    </script>
{% endblock %}
View Code

 5、form.html

<form action="" method="post" novalidate>
    {% for field in form %}
        {% csrf_token %}
        <div class="form-group" style="position:relative;">
            <label for="">{{ field.label }}</label>
            {{ field }}
            <span class="error pull-right">{{ field.errors.0 }}</span>
            {% if field.is_pop %}
                <a onclick="pop('{{ field.url }}')" href=""
                   style="font-size: 25px;position: absolute;top: 25px;right: -25px"><span>+</span></a>
            {% endif %}
        </div>
    {% endfor %}
    <br>
    <button class="btn btn-success pull-right">提交</button>
</form>
View Code

6、pop_view.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>


<script>
    //pop页面返回到上一个页面的数据
{#    window.opener.pop_response();#}
    window.opener.pop_response('{{ res.pk }}','{{ res.text }}','{{ res.pop_res_id }}');

    window.close();
</script>

</body>
</html>
View Code

猜你喜欢

转载自www.cnblogs.com/geogre123/p/9790698.html