django-admin 页面效果,增删改查之[查]

 

这里涉及到的知识点有两个,

一个是get_field() 这里面写的是一个字符串,我们把得到的字符串放进去它返回的是一个类对象,这个字符串是有前提的,前提是这个字符串它要和我们的字段名长得一样才可以,比如我们的book表格,它里面的title字段,我们的title字段是我们的book表格实例化出来的对象,我们放到这个get_field里面的字符串也要是title,不过是加上引号的''title'',然后它会把这个加上引号的title返回给我们就是类对象,

 

我们一般在django里面自定义组件的时候会用到这个用法,比如,在django,admin里面我们要自定义页面所展示的字段名称,就会在注册表文件里面用到list_display,然后这个list_display它后面是一个列表,列表里面是一个个的字符串,这个时候这个字符串就是"title",我们得到了这个"title"之后就用它返回给我们类对象,在自定义组件里面就会需要这种用法,

 

 

 

还有一个是verbose_name() 它是放在我们的models.py文件里面的,我们在定义表格的时候,会在字段里面加上限制条件,然后在字段的限制条件里面我们把它加进去,verbose_name(),它是对我们的字段进行描述的,比如我们的book里面的title字段,我们可以写verbose_name="书名",像这样,如果我们不写verbose_name的话,它默认就是我们的title,我们在把字段展示到页面的时候,就可以使用这个参数去替代我们的title英文单词,

 

还有callable()里面传入一个变量,然后返回一个bool值,判断该变量是否是可调用的,可调用就是函数,否则就不是,

还有getattr()里面传入两个参数,一个是对象,另一个是字符串,我们判断该对象是否有该字符串的方法,返回的也是bool值,

下面我们来实现代码:

from django.db import models

# Create your models here.


class Book(models.Model):
    title = models.CharField(max_length=32, verbose_name='书名')  # 我们的verbose_name是对我们的字段进行描述的,
    # 这个描述信息是可加可不加的,如果不加的话就使用我们默认的title,如果加上的就显示我们这个描述信息,
    # 显示,是在我们的组件里面的内置方法里面显示的,

    def __str__(self):
        return self.title
model类注册文件

 

组件核心代码:

  1 from django.conf.urls import url
  2 from django.shortcuts import HttpResponse, render, redirect
  3 
  4 
  5 class ModelSubject(object):
  6     """
  7     我们在这里模拟admin源码里面的ModelAdmin,但是仅仅是其中的一个方法而已,
  8     就是增删改查生成url那一段的方法def get_urls()就是这个方法
  9     """
 10     list_display = []
 11 
 12     def __init__(self, model, site):
 13         self.model = model  # 当我们生成一个实例化对象的时候需要把model这个参数传进来,
 14         # 必须要传,它是位置参数,然后我们所传入的那个model就是我们在models.py里面定义的每一个表名也就是类名
 15         self.site = site
 16         self.namespace = '{}_{}'.format(self.model._meta.app_label, self.model._meta.model_name)
 17     # 我们这里的namespace是因为会频繁使用到所以就把它作为一个内置静态属性写入到这里,其他地方如果要调用它就直接使用self.namespace即可
 18     # .format的方法:'{}_{}'.format(a,b)
 19 
 20     def stand_li(self, request):
 21         # print(self.model)
 22         # 所以我们在这里可以获取到当前的url里面的表名,然后直接使用orm语句即可得到当前表格的所有信息
 23 
 24         # 生成表头数据
 25         # ['id','title','price',edit]
 26         header_list = []
 27         for field in self.list_display:
 28             if callable(field):
 29                 ret = field(self, is_header=True)
 30                 header_list.append(ret)
 31             else:
 32                 obj = self.model._meta.get_field(field)  # 我们的list_display里面是一个个的字符串,
 33                 # 把字符串放到get_field里面来可以把我们的字符串转换成类对象,
 34                 header_list.append(obj.verbose_name)  # 我们这里的verbose_name在model里面是内置方法,
 35                 # 我们的verbose_name本质上是对我们的字段进行描述的,比如我们的book里面的title可以在字段约束里面设
 36                 # verbose_name='书名',类似于这样,把它变成中文,然后我们在前端HTML模板里面渲染的时候就可以渲染出来中文了,
 37                 # 而不是使用默认的英文,当然了我们如果不设置verbose_name的值那么就使用默认的title作为字段名传到浏览器
 38 
 39 
 40         # 生成表单数据列表
 41         ret = self.model.objects.all()
 42         # print('self.list_display', self.list_display)
 43         data_list = []
 44         for obj in ret:  # 我们遍历这个queryset集合得到的obj是它的每一个对象
 45             temp = []
 46             for field in self.list_display:  # 我们遍历list_display得到每一个字符串
 47                 if callable(field):
 48                     res = field(self, obj)
 49                 else:
 50                     res = getattr(obj, field)  # 使用getattr方法去判断该对象是否具有,field属性方法,
 51                     # getattr里面需要两个参数(类对象,字符串属性方法)
 52                 temp.append(res)
 53             data_list.append(temp)
 54         print('data_list', data_list)
 55 
 56         """
 57         我们最终得到的数据类型是如下格式:列表套着列表
 58         [
 59         使用orm语句得到的每一个类对象,有几个表格就有几个对象
 60         [
 61         [1,'python',<a>编辑</a>],
 62         [2,'java',<a>编辑</a>],
 63         ]
 64         ]
 65         """
 66         # 生成表单数据
 67         return render(request, 'file/hello.html', locals())
 68 
 69     def add_view(self, request):
 70         return HttpResponse('add')
 71 
 72     def edit_view(self, request, id):
 73         return HttpResponse('edit')
 74 
 75     def dele_view(self, request, id):
 76         return HttpResponse('dele')
 77 
 78     def get_urls(self):
 79         temp = []
 80         temp.append(url(r'^$', self.stand_li, name='%s_standlist' % self.namespace))
 81         temp.append(url(r'^(\d+)/dele/', self.dele_view, name='%s_dele' % self.namespace))
 82         temp.append(url(r'^(\d+)/edit/', self.edit_view, name='%s_edit' % self.namespace))
 83         temp.append(url(r'^add/', self.add_view, name='%s_add' % self.namespace))
 84         return temp
 85 
 86     @property
 87     def urls(self):
 88         return self.get_urls()
 89 
 90 
 91 class Stark(object):
 92     """
 93     我们这里面的功能是可以跟上面的类写到一起去的,但是我们为了功能解耦,所以就分开写了,这里的主要功能就是
 94     生成registry的字典,把键值对生成,然后我们最终的结果是要得到一个实例化对象,供我们后面的程序调用,这里的类才是主要的,核心的代码块
 95     而我们上面的那个ModelSubject是辅助我们这里的功能,它之所以分发出去是为了便于扩展其他的功能,我们的自定义样式,
 96     还有很多的方法和参数,就像我们的admin里面的ModelAdmin一样,长达1400多行代码,单独把它分离出去便于功能的扩展
 97     """
 98 
 99     def __init__(self):
100         self._registry = {}  # 这里是定义一个私有属性,就是为了避免被子类修改
101 
102     def register(self, model, model_config=None):  # 我们是仿照着admin的源码写的组件,这里的model_config默认值是None,
103         # 我们在传参的时候,如果给它传值,那么就使用我们传入的值替换掉这个None
104         # 它的源码里面有这几个参数,我们也要按照顺序把这几个参数加进来
105         if not model_config:
106             model_config = ModelSubject  # 我们这里的model_config我们上面的类ModelSubject实例化出来的对象,
107             # 它是上面的类所实例化出来的对象,这一句写得明明白白的,这大白话再看不懂就真是白学了,
108         self._registry[model] = model_config(model, self)
109 
110     def get_urls(self):
111         li = []
112         for model, model_config in self._registry.items():  # 我们在这里所循环的model_config就是
113             # 我们往上数第四行所实例化出来的那个model_config,它是上面的ModelSubject这个类所实例化出来对象,
114             model_name = model._meta.model_name  # 这里的._meta.model_name是获取字符串格式的类名,
115             app_label = model._meta.app_label  # 这里的._meta.app_labe获取的是字符串格式的App名,都是为了跟url做匹配,
116             sli = url(r'%s%s/' % (app_label, model_name), (model_config.urls, None, None))  # 我们这里的model_config,
117             # 它后面的.urls是在调用一个私有方法,我们的私有方法就是使用.urls来调用,不用加上括号,
118             # 因为有@property这个装饰器在里面起到的作用,然后我们需要找到model_config这个实例对象是哪个类生成的,
119             # 然后找到该类所拥有的方法,从里面找到urls,届时,那个urls就是我们在这里调用的那个urls了,
120             # 所以关键的点就是我们的model_config,老师讲课的时候一再地强调过这个model_config从何而来,这个是关键,
121             li.append(sli)
122         return li
123 
124     # 我们最终的数据结构就是这样的,嵌套多层
125     # [
126     # url(
127     # r'',(
128     # [
129     # (url(r'',views.add)),
130     # (url(r'',views.edit)),
131     # ],
132     # none,none)
133     # )
134     # ]
135     @property
136     def urls(self):
137         return self.get_urls(), None, None
138 
139 
140 site = Stark()
App组件下的tool文件下的tag代码

 

一个App注册model代码:

 1 from file.tool.tag import site, ModelSubject
 2 from .models import *
 3 from django.utils.safestring import mark_safe
 4 from django.shortcuts import redirect
 5 from django.urls import reverse
 6 
 7 
 8 class AuthorConfig(ModelSubject):
 9     def edit(self, obj=None, is_header=False):
10         if is_header:
11             return '操作'
12         else:
13             # return mark_safe("<a href='/stark/two/author/%s/edit'>编辑</a>" % obj.pk)
14             return mark_safe("<a href='%s'>编辑</a>" % reverse('%s_edit' % self.namespace, args=(obj.pk,)))
15 
16     def dele(self, obj=None, is_header=False):
17 
18         if is_header:
19             return '操作'
20         else:
21             # return mark_safe("<a href='/stark/two/author/%s/dele'>删除</a>" % obj.pk)
22             return mark_safe("<a href='%s'>删除</a>" % reverse('%s_dele' % self.namespace, args=(obj.pk,)))
23 
24     list_display = ['id', 'name', 'age', edit, dele]
25 
26 
27 site.register(Author, AuthorConfig)
App1注册model文件

 

另一个App注册model代码:

 1 from file.tool.tag import site, ModelSubject
 2 from .models import *
 3 from django.utils.safestring import mark_safe
 4 from django.shortcuts import reverse
 5 # from django.urls import reverse  # 我们引用reverse的时候可以使用这两种方式去引用,
 6 
 7 
 8 class BookConfig(ModelSubject):
 9     def edit(self, obj=None, is_header=False):
10         if is_header:
11             return '操作'
12         # 把url改成反向解析: name='%s_%s_standlist' % app_model
13         return mark_safe("<a href='%s'>编辑</a>" % reverse('%s_edit' % self.namespace, args=(obj.pk,)))
14     # 我们的反向解析里面,需要有参数进行拼接,然后我们拼接的参数是我们在url里面的那个name属性的值,name='%s_%s_standlist' % app_model
15     # 按照这个格式我们来把参数一一拼接进去,我们在href里面直接写一个%s,然后再引号外面把reverse给拼接出来,
16     # 然后就是给reverse里面添加参数,它里面有2个参数,第一个参数是App的名字+表名,第二个是我们在使用编辑或者是删除的时候
17     # 需要找到的那个id值,使用args=(,)一个元祖的形式,
18 
19     def delete(self, obj=None, is_header=False):
20         if is_header:
21             return '操作'
22         # return mark_safe("<a href='/stark/one/book/%s/dele'>删除</a>" % obj.pk)
23         return mark_safe("<a href='%s'>删除</a>" % reverse('%s_dele' % self.namespace, args=(obj.pk,)))
24     list_display = ['id', 'title', edit, delete]
25 
26 
27 site.register(Book, BookConfig)
App2注册model文件

 

posted @ 2018-03-13 21:56  dream-子皿  阅读(199)  评论(0)    收藏  举报