crm项目-django-admin的重写-重点!

###############  admin基本认识和常用的定制功能    ###############

stark组件

对admin的基本认识
1,就是一个app,嵌入到了django里面,你可以在settings中看到
2,就是一个web后台管理工具,使用它可以更加的方便
3,通常我们在生成项目时会在 urls.py 中自动设置好url访问路径
urlpatterns = [
    url(r'^admin/', admin.site.urls)
]
4,启动开发服务器,然后在浏览器中访问 http://127.0.0.1:8000/admin/
5,你通过命令 python manage.py createsuperuser 来创建超级用户
6,使用的时候先注册数据模型:admin.site.register(models.UserInfo)
7,点击进入会展示数据,默认就是把这个对象打印出来,复杂的,需要定制的,需要利用ModelAdmin进行操作
class CourseConfig(admin.ModelAdmin):
    pass
admin.site.register(Course,CourseConfig)


#######################

class UserInfoConfig(admin.ModelAdmin):
    list_display=["id","name","username","password","email","depart"]  # 定制显示的列。不能放多对多的字段
    list_display_links=["username"]  # 定制列可以点击跳转到详情页面,
    list_filter=["depart"]  # 定制右侧快速筛选。
    list_editable=["email"]  # 可以编辑的列,可以编辑就不能是list_display_links字段了,
    search_fields=["username"]  # 模糊搜索的功能

    # 定义action的函数
    def func(self,request,queryset):
        print(request,queryset)
        queryset.update(email="[email protected]")
    func.short_description = "批量初始化操作"

    actions=[func,]  # 定制action中的操作
    fields=["username"]  # 查看详情和新增页面,可以控制显示的字段
    ordering=["-id"]  # 数据排序规则,倒序在字段前面加符号,


admin.site.register(UserInfo,UserInfoConfig)

 

###############  admin的url设计的基础知识点   ###############

admin的url是怎么设计的,这是核心,
urlpatterns = [
    url(r'^admin/', admin.site.urls),  # 为什么这一句能能够生成多条url,
]

第一个知识点,url的嵌套使用

def yuan(request):
    return HttpResponse("Yuan")


def test01(request):
    return HttpResponse("test01")


def test02(request):
    return HttpResponse("test02")


def test03(request):
    return HttpResponse("test03")


def test04(request):
    return HttpResponse("test04")


def test05(request):
    return HttpResponse("test05")


urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^yuan/', ([
                        url(r'^test01/', ([
                                              url(r'^test04/', test04),  # http://127.0.0.1:8000/yuan/test01/test04/
                                              url(r'^test05/', test05),
                                          ], None, None)),
                        url(r'^test02/', test02),
                        url(r'^test03/', test03),
                    ], None, None))
]

第二个知识点:单例模式,

# 单例模式

# 一个类只允许实例一个对象

# class Singleton(object):
#     _instance = None
#     def __new__(cls, *args, **kw):
#         if not cls._instance:
#             cls._instance = super(Singleton, cls).__new__(cls, *args, **kw)
#         return cls._instance
#
# class MyClass(Singleton):
#     a = 1
#
#
# one = MyClass()
# one.a=3
#
# two = MyClass()
# print(two.a)  # 这个地方就是3,因为one和two指向的同一个内存空间,one改掉了a=3,所以two取值的时候就是3
#
# # print(one==two)
# # print(id(one),id(two))



# 第二种方法
###########################
# 第一个文件
class My_Singleton(object):
    x =12
    def foo(self):
        print(self.x)
my_singleton = My_Singleton()  # 这是一个关键的一步

print("OK")

###################
# 第二个文件
from mysingleton import my_singleton
def foo():
    print(id(my_singleton))
############
# 第三个文件
from mysingleton import my_singleton,My_Singleton

# a=My_Singleton()
# b=My_Singleton()
#
# print(id(a))
# print(id(b))  # 这是拿的类对象,而不是实例对象,所以,这两个不一样,

print(id(my_singleton))
from mysingleton import my_singleton
print(id(my_singleton))
from func import *
foo()  # 这三次都是拿的实例对象,所以id的结果都是一样的,

 

############### admin的url设计    ###############

第一个注册:

 

# 注册

self._registry = {}
self._registry[model] = admin_class(model, self)
# 注册的时候,是定义了一个字典,然后以model表为键,以对应的自定义类为值,生成对应的字典,

 

第二个url设置

def add(request):
    return HttpResponse("add")
def delete(request,id):
    return HttpResponse("delete")
def change(request,id):
    return HttpResponse("change")
def list_view(request):
    return HttpResponse("list_view")


def get_urls2():

    temp=[]
    temp.append(url(r"^add/",add))
    temp.append(url(r"^(\d+)/delete/",delete))
    temp.append(url(r"^(\d+)/change/",change))
    temp.append(url(r"^$",list_view))
    print("temp2",temp)
    # [
    # ,
    # ,
    # ,
    # 
    # ]
    return temp

def get_urls():


    temp=[]
    print("_registry",admin.site._registry)

    for model,admin_class_obj in admin.site._registry.items():
         print("model",model) # 所有的注册模型表

         # < class 'app01.models.Book'>----->     "book"  "app01"
         # < class 'app01.models.Room'>----->     "room"  "app01"
         print("===>",model._meta.model_name)
         print("===>",model._meta.app_label)

         model_name=model._meta.model_name  # 对应的model表的名字
         app_label=model._meta.app_label  # 对应的app名字
         temp.append(url(r"%s/%s/"%(app_label,model_name),(get_urls2(),None,None)))
    print("temp",temp)
    """
    [
     (None:None) auth/group/>, 
     (None:None) auth/user/>, 
     (None:None) crm/userinfo/>
    ]
    """

    return temp


urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^yuan/', (get_urls(), None, None))
]

 

###############  模仿admin-stark组件的url设计    ###############

class ModelStark(object):

    def __init__(self,model,site):
        self.model=model  # 谁调用的就是那个表
        self.site=site

    def add_view(self, request):
        return HttpResponse("add_view")

    def change_view(self, request, id):
        return HttpResponse("change_view")

    def delete_view(self, request, id):
        return HttpResponse("delete_view")

    def list_view(self, request):
        return HttpResponse("list_view")

    def get_urls_2(self):

        temp = []

        model_name=self.model._meta.model_name
        app_label=self.model._meta.app_label

        temp.append(url(r"^add/", self.add_view))
        temp.append(url(r"^(\d+)/delete/", self.delete_view))
        temp.append(url(r"^(\d+)/change/", self.change_view))
        temp.append(url(r"^$", self.list_view))

        return temp

    @property
    def urls_2(self):
        print(self.model)
        return self.get_urls_2(), None, None

class StarkSite(object):
    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)  # 括号内的两个参数,就是ModelStark默认的两个参数,self就是site


    def get_urls(self):
        temp=[]
        for model,stark_class_obj in self._registry.items():
            model_name=model._meta.model_name
            app_label=model._meta.app_label
            # 分发增删改查
            temp.append(url(r"^%s/%s/"%(app_label,model_name),stark_class_obj.urls_2))

            '''
            url(r"^app01/userinfo/",UserConfig(Userinfo).urls_2),
            url(r"^app01/book/",ModelStark(Book).urls_2), 
        
            '''
        return temp

    @property
    def urls(self):
       return self.get_urls(),None,None

site=StarkSite()  # 单例模式

 

##############  stark组件需要实现的功能    ###############

在完成了注册和url设计之后,stark组件需要完成什么功能

1,查询页面
1.1 表头展示,可以定制展示的列,
1.2 表内容展示,删除 编辑,复选框的功能
1.3 查询功能,可以定义查询的字段,
1.4 action功能,可以定制批量操作
1.5 筛选功能,可以定制筛选的字段,
1.6 分页功能
这是最为复杂的部分,


2,新增页面
2.1 一个重要的pop功能,


3,删除页面
这个简单

4,编辑页面,
这个简单,和新增页面很相似,只需要把要编辑的数据带到页面展示,


整个重写,使用到了
1,django
2,admin
3,前端,js,html,bootstrap,jQuery,

 

##############  stark-service    ###############

# by luffycity.com
from django.conf.urls import url

from django.shortcuts import HttpResponse,render,redirect
from django.urls import reverse
from django.db.models import Q
from django.utils.safestring import mark_safe

from stark.utils.page import  Pagination
from django.db.models.fields.related import ManyToManyField,ForeignKey
class ShowList(object):
    def __init__(self,config,data_list,request):
        self.config=config  # 这里的config就是用来接收传递的modelstark类的,下面就可以使用config调用modelstark里面的方法了,
        self.data_list=data_list  # 这个datalist是需要展示的数据
        self.request=request  # 为什么需要传递request?因为需要在这个里面获取page参数,是第几页
        #分页
        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.new_actions() # [patch_init,] # 获取modelstark中配置的action列表,


    def get_filter_linktags(self):
        print("list_filter:",self.config.list_filter)
        link_dic={}  # 格式是{筛选字段1:筛选值1,筛选字段2:筛选值2}
        import copy

        for filter_field in self.config.list_filter: # ["title","publish","authors",]
            params = copy.deepcopy(self.request.GET)  # 复制一份方便操作

            cid=self.request.GET.get(filter_field,0)  # 这是获取到前端拼接的id,

            print("filter_field",filter_field) # "publish"
            filter_field_obj=self.config.model._meta.get_field(filter_field)  # 这是拿到的字段对象
            print("filter_field_obj",filter_field_obj)
            print(type(filter_field_obj))
            from django.db.models.fields.related import ForeignKey
            from django.db.models.fields.related import ManyToManyField
            # 举例说明:拿到出版社关联的书籍,筛选是所有关联的出版社,拿到作者关联的书籍,筛选是所有关联的作者,怎么获取?
            print("rel======...",filter_field_obj.rel)

            if isinstance(filter_field_obj,ForeignKey) or isinstance(filter_field_obj,ManyToManyField):
                 data_list=filter_field_obj.rel.to.objects.all()# 【publish1,publish2...】
                 # filter_field_obj.rel.to,这种特殊写法,只有字段有关联表的时候才有意义,一对多,和多对多的,
            else:
                 data_list=self.config.model.objects.all().values("pk",filter_field)
                 print("data_list",data_list)


            temp=[]
            # 处理全部标签
            if params.get(filter_field):  # filter_field 这是筛选的字段,如果有筛选值,就删掉,
                del params[filter_field]
                temp.append("全部"%params.urlencode())
            else:
                temp.append("全部")

            # 处理数据标签
            for obj in data_list:
                if isinstance(filter_field_obj,ForeignKey) or isinstance(filter_field_obj,ManyToManyField):
                    pk=obj.pk
                    text=str(obj)
                    params[filter_field] = pk
                else: # data_list= [{"pk":1,"title":"go"},....]
                    print("========")
                    pk=obj.get("pk")
                    text=obj.get(filter_field)
                    params[filter_field] =text  # 处理单表查询


                _url=params.urlencode()
                if cid==str(pk) or cid==text:  # 这是为了实现点击选中的标签,展示深蓝色,active
                     link_tag="%s"%(_url,text)
                else:
                    link_tag = "%s" % (_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:  # 这是配置的action列表,循环这个列表,每一个action就是每一个函数,
           temp.append({
               "name":action.__name__,  # 获取函数的名字,作为值
               "desc":action.short_description  # 获取函数的描述,作为展示short_description,这是函数的一个动态属性
           })  #  [{"name":""patch_init,"desc":"批量初始化"}]

        print("temp",temp)
        return temp

    def get_header(self):
        # 构建表头
        header_list = []
        print("header",
              self.config.new_list_play())  # [checkbox,"pk","name","age",edit ,deletes]     【checkbox ,"__str__", edit ,deletes】

        for field in self.config.new_list_play():

            if callable(field):
                # header_list.append(field.__name__)  # field.__name__函数的名字
                val = field(self.config, header=True)  # header=True,header默认是false,这个再去拿值的之后就会拿到汉字了
                header_list.append(val)

            else:
                if field == "__str__": # 这是没有自定义的情况
                    header_list.append(self.config.model._meta.model_name.upper())  # 这是展示表名的大写作为表头
                else:  # 这是自定义的情况
                    # header_list.append(field)
                    val = self.config.model._meta.get_field(field).verbose_name  # 这是获取到了表里面的字段,verbose_name这是字段的中文
                    header_list.append(val)
        return header_list

    def get_body(self):
        # 构建表单数据
        new_data_list = []
        for obj in self.page_data:
            temp = []

            for filed in self.config.new_list_play():  # ["__str__",]      ["pk","name","age",edit] 这一步应该把编辑,删除,复选框都加进来了

                if callable(filed):  # callable判断是否是一个可调用的,如果是一个字符串就是False,如果是一个方法就是true
                    print("obj-----:",obj)
                    val = filed(self.config, obj)
                else:
                    try:
                        field_obj=self.config.model._meta.get_field(filed)
                        if isinstance(field_obj,ManyToManyField):  # 多对多的时候如何展示数据
                            ret = getattr(obj,filed).all()  # 这是获取到多对多的情况,可能会有多个值,
                            t=[]
                            for mobj in ret:
                                t.append(str(mobj))
                            val=",".join(t)  # 拼成逗号隔开的样子,展示出来,
                        else:
                            print("====>",field_obj.choices)
                            if field_obj.choices:
                                val = getattr(obj, "get_"+filed+"_display")  # 这个obj是每一条数据,filed是每一条数据应该显示的字段,
                            else:
                                 val = getattr(obj, filed)
                            if filed in self.config.list_display_links:  # 如果是一个可以点击的字段,要特殊处理成为超链接
                                # "app01/userinfo/(\d+)/change"
                                _url = self.config.get_change_url(obj)
                                val = mark_safe("%s" % (_url, val))

                    except Exception as e:
                        val = getattr(obj, filed)


                temp.append(val)

            new_data_list.append(temp)
        return new_data_list

'''
        [
            [1,"alex",12],
            [1,"alex",12],
            [1,"alex",12],
            [1,"alex",12],

                 ]

        '''

class ModelStark(object):

    list_display=["__str__",]
    list_display_links=[]
    modelform_class=None
    search_fields=[]
    actions = []
    list_filter=[]


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

    patch_delete.short_description = "批量删除"

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


    # 删除 编辑,复选框
    def edit(self,obj=None,header=False):
        if header:
            return "操作"
        #return mark_safe("编辑"%obj.pk)
        _url=self.get_change_url(obj)

        return mark_safe("编辑"%_url)

    def deletes(self,obj=None,header=False):
        if header:
            return "操作"
        # return mark_safe("编辑"%obj.pk)

        _url=self.get_delete_url(obj)

        return mark_safe("删除" % _url)

    def checkbox(self,obj=None,header=False):
        if header:
            return mark_safe('')

        return mark_safe(''%obj.pk)
    # 这一步非常的重要,因为在配合action去取到选中的数据,

    def get_modelform_class(self):
        """如果客户定制了用客户定制的,如果没有没有定制使用默认的,"""
        if not self.modelform_class:
            from django.forms import ModelForm  # 这个涉及到了form表单的内容,
            from django.forms import widgets as wid
            class ModelFormDemo(ModelForm):  # 可以在每一个app中的stark里面,对每一个model进行重写这个类,就可以定制了
                class Meta:
                    model = self.model
                    fields = "__all__"
                    labels={
                        ""
                    }  # 可以在每一个app中的stark里面,labels可以对字段进行设置汉字,格式是键:值的方式,
            return ModelFormDemo
        else:
            return self.modelform_class

    def get_new_form(self,form):
        """这是pop弹出的窗口对象的方法,"""
        for bfield in form:
            from django.forms.boundfield import BoundField
            print(bfield.field) # 字段对象
            print("name",bfield.name)  # 字段名(字符串)
            print(type(bfield.field)) # 字段类型
            from django.forms.models import ModelChoiceField
            if isinstance(bfield.field,ModelChoiceField):
                bfield.is_pop=True  # 这是动态给多对多的字段加属性
                # 怎么拿到关联表的名字,和它所属的APP呢,
                print("=======>",bfield.field.queryset.model) # 一对多或者多对多字段的关联模型表
                related_model_name=bfield.field.queryset.model._meta.model_name
                related_app_label=bfield.field.queryset.model._meta.app_label


                _url=reverse("%s_%s_add"%(related_app_label,related_model_name))  # 反向解析进入对应的添加页面,
                bfield.url=_url+"?pop_res_id=id_%s"%bfield.name  # 动态加字段,字段名(字符串)

        return form


    def add_view(self, request):
        ModelFormDemo = self.get_modelform_class()  # 这是返回一个类
        form = ModelFormDemo()  # 使用这个类实例化一个对象出来,

        form=self.get_new_form(form)

        if request.method=="POST":  # 点击提交按钮要做的事情
            form = ModelFormDemo(request.POST)
            if form.is_valid():
                obj=form.save()  # 这都是form表单的功能,校验通过就保存到数据库,

                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}
                    import json
                    return render(request, "pop.html", {"res":res})
                else:
                    return redirect(self.get_list_url())
        print("locals()",locals())
        """
        {
        'form': ,
         'ModelFormDemo': .ModelFormDemo'>, 
         'request': , 
         'self': 
         }
        """
        return render(request, "add_view.html", locals())  # Python 的内建函数 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):
        ModelFormDemo = self.get_modelform_class()  # 获取这个类,可以控制展示的字段等信息
        print("=====id",id)
        edit_obj = self.model.objects.filter(pk=id).first()

        if request.method=="POST":
            form = ModelFormDemo(request.POST,instance=edit_obj)  # 这个instance也是djangoform表单的功能,
            if form.is_valid():
                form.save()
                return redirect(self.get_list_url()) # 提交之后返回到列表页

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

        print("***********",edit_obj)
        form = ModelFormDemo(instance=edit_obj)  # 和新增页面一样,只需要加一个instance
        form = self.get_new_form(form)

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

    def new_list_play(self):
        """这个方法不只是把每一条数据的字段放进来了,还把编辑,删除,复选框也放进来了,"""
        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

    def new_actions(self):
        temp=[]
        temp.append(ModelStark.patch_delete)
        temp.extend(self.actions)  # 这个里面就可能会有自定义的action,这样组成一个新的action,

        return temp


    def get_change_url(self,obj):  # 这一个功能多个地方使用,所以封装到一个方法里面,
        model_name = self.model._meta.model_name
        app_label = self.model._meta.app_label
        print("obj===========",obj)
        # from django.urls import reverse,这个是django中的一个工具
        _url = reverse("%s_%s_change" % (app_label, model_name), args=(obj.pk,))  # 反向解析,args,是传入的id字段,

        return _url

    def get_delete_url(self, obj):
        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 _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_serach_conditon(self,request):
        key_word = request.GET.get("q","")
        self.key_word=key_word  # 这是给modelstark加一个实例对象,然后在查询之后就可以直接把查询内容渲染到页面了,通过showlist.config.keyword

        search_connection = Q()  # 默认这个是空的条件
        if key_word:
            # self.search_fields # ["title","price"]
            search_connection.connector = "or"  # 这是orm使用q查询的另外一种方法,
            for search_field in self.search_fields:
                search_connection.children.append((search_field + "__contains", key_word))
        print("search_connection",search_connection)
        return search_connection


    def get_filter_condition(self,request):
        filter_condition=Q()

        for filter_field,val in request.GET.items():# courserecord=2
             if filter_field !="page":  # 把page这个去掉,不加入过滤
                filter_condition.children.append((filter_field,val))

        return filter_condition


    def list_view(self, request):
        if request.method=="POST":  # 这个post请求,就是在处理action的提交(go)
            print("POST:",request.POST)  # 把input框的值传过来了,把select下面的选中的值传过来,可以在post中取到action和selected_pk
            action=request.POST.get("action") # patch_init
            selected_pk=request.POST.getlist("selected_pk")
            action_func=getattr(self,action)  # 反射,从self中去找action,action这是一个变量,是对应的点击的哪一个函数
            # self,是配置类,如果没有找到就去父类找,
            queryset=self.model.objects.filter(pk__in=selected_pk)
            ret=action_func(request,queryset)  # 调用对应的函数操作,

            #return ret

        # 获取serach的Q对象
        search_connection=self.get_serach_conditon(request)

        # 获取filter构建Q对象

        filter_condition=self.get_filter_condition(request)

        print("search_connection",search_connection,"filter_condition",filter_condition)

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

        print("data_list",data_list)
        # 按这ShowList展示页面
        showlist=ShowList(self,data_list,request)  # 实例化一个showlist,这个self就是现在的modelstark类,需要作为一个参数传递,

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



    def extra_url(self):

        return []

    def get_urls_2(self):

        temp = []

        model_name=self.model._meta.model_name
        app_label=self.model._meta.app_label

        temp.append(url(r"^add/", self.add_view,name="%s_%s_add"%(app_label,model_name)))  # 这个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)))
        temp.append(url(r"^$", self.list_view,name="%s_%s_list"%(app_label,model_name)))

        # 扩展url
        temp.extend(self.extra_url())

        return temp

    @property
    def urls_2(self):
        print(self.model)
        return self.get_urls_2(), None, None

class StarkSite(object):
    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)  # 括号内的两个参数,就是ModelStark默认的两个参数,self就是site


    def get_urls(self):
        temp=[]
        for model,stark_class_obj in self._registry.items():
            model_name=model._meta.model_name
            app_label=model._meta.app_label
            # 分发增删改查
            temp.append(url(r"^%s/%s/"%(app_label,model_name),stark_class_obj.urls_2))

            '''
            url(r"^app01/userinfo/",UserConfig(Userinfo).urls_2),
            url(r"^app01/book/",ModelStark(Book).urls_2), 
            
        
            '''
        return temp

    @property
    def urls(self):
       return self.get_urls(),None,None

site=StarkSite()

 

###############  stark-分页      ###############

"""
自定义分页组件

"""


class Pagination(object):
    def __init__(self, current_page, all_count, base_url,params, per_page_num=8, pager_count=11, ):
        """
        封装分页相关数据
        :param current_page: 当前页
        :param all_count:    数据库中的数据总条数
        :param per_page_num: 每页显示的数据条数
        :param base_url: 分页中显示的URL前缀
        :param pager_count:  最多显示的页码个数
        """

        try:
            current_page = int(current_page)
        except Exception as e:
            current_page = 1

        if current_page < 1:
            current_page = 1

        self.current_page = current_page

        self.all_count = all_count
        self.per_page_num = per_page_num

        self.base_url = base_url

        # 总页码
        all_pager, tmp = divmod(all_count, per_page_num)
        if tmp:
            all_pager += 1
        self.all_pager = all_pager

        self.pager_count = pager_count  # 最多显示页码数
        self.pager_count_half = int((pager_count - 1) / 2)

        import copy
        params = copy.deepcopy(params)
        params._mutable = True
        self.params = params  # self.params : {"page":77,"title":"python","nid":1}


    @property
    def start(self):
        return (self.current_page - 1) * self.per_page_num


    @property
    def end(self):
        return self.current_page * self.per_page_num


    def page_html(self):
        # 如果总页码 < 11个:
        if self.all_pager <= self.pager_count:
            pager_start = 1
            pager_end = self.all_pager + 1
        # 总页码  > 11
        else:
            # 当前页如果<=页面上最多显示(11-1)/2个页码
            if self.current_page <= self.pager_count_half:
                pager_start = 1
                pager_end = self.pager_count + 1

            # 当前页大于5
            else:
                # 页码翻到最后
                if (self.current_page + self.pager_count_half) > self.all_pager:
                    pager_start = self.all_pager - self.pager_count + 1
                    pager_end = self.all_pager + 1

                else:
                    pager_start = self.current_page - self.pager_count_half
                    pager_end = self.current_page + self.pager_count_half + 1

        page_html_list = []
        self.params["page"] = 1
        first_page = '
  • 首页
  • ' % (self.base_url, self.params.urlencode(),) page_html_list.append(first_page) if self.current_page <= 1: prev_page = '
  • 上一页
  • ' else: self.params["page"] = self.current_page - 1 prev_page = '
  • 上一页
  • ' % (self.base_url, self.params.urlencode(),) page_html_list.append(prev_page) for i in range(pager_start, pager_end): # self.params : {"page":77,"title":"python","nid":1} self.params["page"] = i # {"page":72,"title":"python","nid":1} if i == self.current_page: temp = '
  • %s
  • ' % (self.base_url, self.params.urlencode(), i,) else: temp = '
  • %s
  • ' % (self.base_url, self.params.urlencode(), i,) page_html_list.append(temp) if self.current_page >= self.all_pager: next_page = '
  • 下一页
  • ' else: self.params["page"] = self.current_page + 1 next_page = '
  • 下一页
  • ' % (self.base_url, self.params.urlencode(),) page_html_list.append(next_page) self.params["page"] = self.all_pager last_page = '
  • 尾页
  • ' % (self.base_url, self.params.urlencode(),) page_html_list.append(last_page) return ''.join(page_html_list) # class Pagination(object): # # def __init__(self, data_num, current_page, url_prefix,params, per_page=10, max_show=4): # """ # 进行初始化. # :param data_num: 数据总数 # :param current_page: 当前页 # :param url_prefix: 生成的页码的链接前缀 # :param per_page: 每页显示多少条数据 # :param max_show: 页面最多显示多少个页码 # """ # self.data_num = data_num # self.per_page = per_page # self.max_show = max_show # self.url_prefix = url_prefix # # # 把页码数算出来 # self.page_num, more = divmod(data_num, per_page) # if more: # self.page_num += 1 # # try: # self.current_page = int(current_page) # except Exception as e: # self.current_page = 1 # # 如果URL传过来的页码数是负数 # if self.current_page <= 0: # self.current_page = 1 # # 如果URL传过来的页码数超过了最大页码数 # elif self.current_page > self.page_num: # self.current_page = self.page_num # 默认展示最后一页 # # # 页码数的一半 算出来 # self.half_show = max_show // 2 # # # 页码最左边显示多少 # if self.current_page - self.half_show <= 1: # self.page_start = 1 # self.page_end = self.max_show # elif self.current_page + self.half_show >= self.page_num: # 如果右边越界 # self.page_end = self.page_num # self.page_start = self.page_num - self.max_show # else: # self.page_start = self.current_page - self.half_show # # 页码最右边显示 # self.page_end = self.current_page + self.half_show # # # import copy # self.params=copy.deepcopy(params) # {"page":"12","title_startwith":"py","id__gt":"5"} # # # # @property # def start(self): # # 数据从哪儿开始切 # return (self.current_page - 1) * self.per_page # # @property # def end(self): # # 数据切片切到哪儿 # return self.current_page * self.per_page # # def page_html(self): # # 生成页码 # l = [] # # 加一个首页 # l.append('
  • 首页
  • '.format(self.url_prefix))
    # # 加一个上一页 # if self.current_page == 1: # l.append('
  • «
  • '.format(self.current_page))
    # else: # l.append('
  • «
  • '.format(self.url_prefix, self.current_page - 1))
    # # # # # {"page":"12","title_startwith":"py","id__gt":"5"} # "page=12&title_startwith=py&id__gt=5" # # # print(self.params.urlencode()) # for i in range(self.page_start, self.page_end + 1): # self.params["page"]=i # # {"page":"7","title_startwith":"py","id__gt":"5"} # "page=7&title_startwith=py&id__gt=5" # if i == self.current_page: # tmp = '
  • {1}
  • '.format(self.url_prefix, i)
    # else: # tmp = '
  • {2}
  • '.format(self.url_prefix, self.params.urlencode(),i)
    # l.append(tmp) # # # # # # # # # 加一个下一页 # if self.current_page == self.page_num: # l.append('
  • »
  • '.format(self.current_page))
    # else: # l.append('
  • »
  • '.format(self.url_prefix, self.current_page + 1))
    # # 加一个尾页 # l.append('
  • 尾页
  • '.format(self.url_prefix, self.page_num))
    # return "".join(l)

     

    ###############  查看列表页面    ###############

    
    "zh-CN">
    
        "UTF-8">
        Title
        "viewport" content="width=device-width, initial-scale=1">
        "stylesheet" href="/static/bootstrap/css/bootstrap.css">
        
    
        
    
    
    
    

    数据列表

    class="container">
    class="row">
    class="col-md-9"> "{{ add_url }}" class="btn btn-primary">添加数据 {#搜索框,只有配置了search_fields才会展示#} {% if showlist.config.search_fields %} {#没有写method,默认是一个get请求#}
    "" class="pull-right"> class="form-control" style="display: inline-block;width:200px" type="text" name="q" value="{{ showlist.config.key_word }}">
    {% endif %} {#构建这个表单,就是为了批量操作的,因为需要下面的列表数据,所以包到一起, #}
    "" method="post"> {% csrf_token %} class="table table-bordered table-striped"> {#表头#} {% for item in showlist.get_header %} {% endfor %} {#表数据#} {% for data in showlist.get_body %} {% for item in data %} {% endfor %} {% endfor %}
    {{ item }}
    {{ item }}
    {#筛选#}
    class="col-md-3"> {% if showlist.config.list_filter %}
    class="filter">

    "">Filter

    {% for filter_field,linktags in showlist.get_filter_linktags.items %}
    class="well">

    By {{ filter_field.upper }}

    {% for link in linktags %}

    {{ link|safe }}

    {% endfor %}
    {% endfor %}
    {% endif %}

     

    ###############  修改页面    ###############

    
    "zh-CN">
    
        "UTF-8">
        Title
        "viewport" content="width=device-width, initial-scale=1">
        "stylesheet" href="/static/bootstrap/css/bootstrap.css">
        
    
    
        
    
    
    
    
    

    编辑页面

    {% include 'form.html' %}

     

    ###############  删除页面    ###############

    
    "zh-CN">
    
        "UTF-8">
        Title
        "viewport" content="width=device-width, initial-scale=1">
    
    
    
    
    

    删除页面

    "" method="post"> {% csrf_token %} "{{ url }}">取消

     

    ###############  抽象form表单部分    ###############

    class="container">
    class="row">
    class="col-md-6 col-xs-8 col-md-offset-3">
    "" method="post" novalidate> {% csrf_token %} {% for field in form %}
    "position: relative"> {{ field }} class=" error pull-right">{{ field.errors.0 }} {% if field.is_pop %} {#如果是一个一对多多对多的字段,需要在字段的右侧放一个加号,需要弹出新的页面,来添加数据#} {#position,设置标签的位置,父标签是相对定位,子标签是绝对定位,#} {#你怎么知道一个字段是一对多多对多的字段??,根据字段的类型,如果是一对多,多对多,加一个is_pop的字段为true#} {#绑定一个点击事件,点击要跳转到一个url,#} "pop('{{ field.url }}')" style="position: absolute;right: -30px;top: 20px">"font-size: 28px">+ {% endif %}
    {% endfor %}

     

    ###############  新增页面   ###############

    
    "zh-CN">
    
        "UTF-8">
        Title
        "viewport" content="width=device-width, initial-scale=1">
        "stylesheet" href="/static/bootstrap/css/bootstrap.css">
        
    
    
        
    
    
    
    
    

    添加页面

    {% include 'form.html' %}

     

    ###############  pop页面    ###############

    
    "zh-CN">
    
        "UTF-8">
        Title
        "viewport" content="width=device-width, initial-scale=1">
    
    
    
    
    
    
    

     

     

    ###############  admin    ###############

     

    ###############  admin    ###############

    你可能感兴趣的:(crm项目-django-admin的重写-重点!)