Django之stark组件1

stark组件

stark组件是根据Django admin为原型写的一个组件,能够让我们告别增删改查.stark组件是可插拔试的组件,

移植性强,而且只用配置文件就能够得到想要的数据

一、stark组件路由分发

admin用这一条路由就实现了注册表单*4的url。

路由分发的原理:

知识一:admin之路由分发原理:
def text01(request):
    return  HttpResponse('text01')
def text02(request):
    return  HttpResponse('text02')
def text03(request):
    return  HttpResponse('text03')
urlpatterns = [
    path('chen/',(
            [path('text01/',text01),
             path('text02/',text02),
             path('text03/',text03),
             ],
            None,None))
]
        由一个路由分发出来三个 第一个none是namespace,第二个是项目名称
        
        一级:
        path('chen/',(
        [
        path()
        path()
        path()
        ],None,None))
        
由一个路由分发出来三个,第一个路由又可以分发出来两个,二级路由.

 第一个none是namespace,第二个是项目名称
 
    二级:
    path('chen/',(
        [
        path(
            [
                path(),
                path(),
            ],None,None))
        ]
        ,None,None))
        
路由分发原理

单例模式:

***公共的数据***
一个类只允许实例一个对象
***为了数据统一****

怎么生成单例模式?

方式一:__new__

        __new__
    class Singleton(object):
           _instance = None
                def __new__(cls, *args, **kwargs):
        # 第一次生成对象的时候走:
                if not cls._instance:
                cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs) 
        # 第二次走的时候直接走这里
                     return cls._instance  
class MyClass(Singleton):  
    a = 1

#那么每次实例对象的时候都是指向 同一个内存地址.
#实例MyClass的时候都是 同一个对象
View Code

方式二:python模块

python模块是天然的单例模式:

1.不管模块哪里导入,只要是再次导入都是从.pyc导入,都是一个内存地址
    因为模块在第一次导入时,会生成 .pyc 文件,当第二次导入时,
   就会直接加载 .pyc 文件,而不会再次执行模块代码。
2.我们只需把模块的对象实例化,每次调用的时候都调用这个对象,就可以获得一个单例对象了。

class StarkSite(object):
    """注册model对应的配置类(MondelStark或用户自定制)"""
    def __init__(self):
        self._registry={}
        #self--->site单例对象

    def register(self,model,stark_class=None):
        if not stark_class:
            stark_class=MondelStark
        self._registry[model] = stark_class(model,self)

    def get_urls(self):
        # self--->site单例对象
        temp=[]
        for model,stark_class_obj in self._registry.items():
            model_name=model._meta.model_name
            app_label =model._meta.app_label
            temp.append(path('%s/%s/'%(app_label,model_name),stark_class_obj.get_url_dispath))
            '''
            path('repository/book/'BookStark(book,).get_url_dispath)
            path('repository/author/'BookStark(author,).get_url_dispath)
            
            '''
        return temp

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

site=StarkSite()
单例

每次调用site就是单例对象

说完单例模式,再说回路由的分发:

stark.site就是一个单例,里面进行注册我们的models

为什么我们要用单例模式???

为了能够把model注册到同一个对象里面,我们就可以实现数据统一调度。

StarkSite形成单例类的代码:

#单例的类
class StarkSite(object):
    """注册model对应的配置类(MondelStark或用户自定制)"""
    def __init__(self):
        self._registry={}
        #self--->site单例对象

    def register(self,model,stark_class=None):
        if not stark_class:
            stark_class=MondelStark
        self._registry[model] = stark_class(model,self)

    def get_urls(self):
        # self--->site单例对象
        temp=[]
        for model,stark_class_obj in self._registry.items():
            model_name=model._meta.model_name
            app_label =model._meta.app_label
            temp.append(path('%s/%s/'%(app_label,model_name),stark_class_obj.get_url_dispath))
            '''
            path('repository/book/'BookStark(book,).get_url_dispath)
            path('repository/author/'BookStark(author,).get_url_dispath)
            
            '''
        return temp

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

在register()方法里面,我们在注册的前提

大前提!!!!!!!

***思考***

我们里在直接调用这个register方法?

那么里面注册了数据了吗?

答案是没有的,

***思路***

在每次开启项目的时候,能够自动执行某个py文件进行注册

from repository import models
from stark.server.stark import site
from stark.server.stark import MondelStark
引入
#我们需要在stark项目的app里:
from django.apps import AppConfig
from django.utils.module_loading import autodiscover_modules

class StarkConfig(AppConfig):
    name = 'stark'
    def ready(self):
        autodiscover_modules('stark',)


#每次启动都会执行每个项目的stark.py文件,那么一开启项目就把model注册了.


###########其他项目注册model##########
site.register(models.Book,BookStark)

site.register(models.Author,AuthorStark)

site.register(models.publish)
自动执行py文件

在其他项目stark.py我们可以自己进行配置类的书写

from stark.server.stark import MondelStark

class BookStark(MondelStark):
pass
View Code

如何通过模型类获得字符串名称,和该模型所在的app名称:

我们需要构建的是一级分发:

第一个是model所属项目的名称/第二个是model类的类名

(path('%s/%s'%(app_label,model_name),))

 for model,class_obj in admin.site._registry.items():

    print(model._meta.model_name) #打印出该模型的名称

    print(model._meta.app_label)  #打印出该模型的app的名称
    
View Code

二级分发我们需要写在配置类里面:

为什么不能写在单例?

从图中可以看出,如果是单例对象的话,每个model类对应的视图函数都是一样的

我们想要的是每一个model类都需要4个视图函数,

所以我们只能把二级分发放在配置类里面,让每个配置类都生成四个相对应的视图函数

    def url_dispath(self):
        # self--->stark_class_obj--->每一个单独的配置类.
        temp = []
        model_name = self.model._meta.model_name
        app_label = self.model._meta.app_label
        temp.extend([path('add/', self.add_view,name="%s_%s_add"%(app_label,model_name)),
                     re_path('^(d+)/delete/', self.delete_view,name="%s_%s_delete"%(app_label,model_name)),
                     re_path('^(d+)/change/', self.change_view,name="%s_%s_change"%(app_label,model_name)),
                     path('', self.show_list,name="%s_%s_list"%(app_label,model_name))])
        return temp


#起别名,目的是为了反向查询的时候能够查到相对应的url
二级分发

构建表结构:

自定制表头:

配置类继承了MondelStark的配置类

class BookStark(MondelStark):

    list_display=['id','name','price']

site.register(models.Book,BookStark)

 构建表格

 

构建表头知识补充:

#如果客户自定制了配置list_display 那么实例化的时候就先在用户自定义的类里面找
#有则返回给后端......没有再去他的父类里面找list_display为空.

属性的反射

属性和方法都可以进行反射

    ###################
    反射:
    class B(object):
        def__init__(self,name):
            self.name=name
    chen=B('chenxuming')
    s='name'
    
    ret=getattr(chen,s)
    print(ret)  ---->'chenxuming'
属性的反射

如何将表头换成中文:

val = self.config.model._meta.get_field(field).verbose_name
header_list.append(val)

class Book(models.Model):
    name = models.CharField(max_length=64,verbose_name='书名')
    price= models.IntegerField()
    
    name=Book._meta.get_field('name')
    #name拿到的是title字段的对象
    print(name)
    print(type(name))
    #可以取里面的属性
    name.max_length  --->64
        name.verbose_name--->'书名'
View Code

#判断是否是函数的字段
if callable():

from django.utils.safestring import mark_safe
mark_safe(安全调用标签)

构建表格的代码

    def new_list_display(self):
          ''''构建初始化列表的字段''   
        temp=[]
        temp.append(MondelStark.checkbox)
        temp.extend(self.list_display)
        temp.append(MondelStark.get_delete_msg)
        if not self.list_display_links:
            temp.append(MondelStark.get_edit_msg)
        return temp

    def get_headers(self):
        # 构建表头:      self.new_list_display=[checkbox,'name','price',delete,edit]
        header_list = []
        for field in  self.config.new_list_display:
            if callable(field):
                val = field(self.config, header=True)
                header_list.append(val)
            else:
                if field == '__str__':
                    val =  self.config.model_name.upper()
                    header_list.append(val)
                else:
                    val =  self.config.model._meta.get_field(field).verbose_name
                    header_list.append(val)
        return header_list


    def get_body(self):
        # 表数据的创建
        new_list = []
        for obj in self.data_list:
            item_list = []
            for item in  self.config.new_list_display:
                if callable(item):
                    val = item(self.config, obj)
                else:
                    val = getattr(obj, item)
                    if item in  self.config.list_display_links:
                        val = mark_safe('<a href="%s">%s</a>' % ( self.config.get_edit_url(obj), val))
                item_list.append(val)
            new_list.append(item_list)
        return new_list

[[数据],[数据],[数据]]

##########表头,部分表数据的函数#########

 def checkbox(self,obj=None,header=False):
        if header:
            return mark_safe('<input id="choice_all" type="checkbox">')

        return mark_safe('<input class="item" type="checkbox" name="selected_id" value="%s">'%obj.id)

    def get_edit_msg(self,obj=None,header=False):
        if header:
            return "操作"

        _url=self.get_edit_url(obj)
        return mark_safe('<a href="%s">编辑</a>' % _url)

    def get_delete_msg(self,obj=None,header=False):
        if header:
            return "操作"
        _url=self.get_delete_url(obj)
        return mark_safe('<a href="%s">删除</a>'%_url)
构建表格

增:

增和改都是基于ModelForm来实现的。

如果用户自定制

Stark_Model_Form=自定制modelform的类名
class BookStark(MondelStark):
    list_display=['id','name','price']
    Stark_Model_Form=ModelFormBook
    list_display_links = ['name']



class ModelFormBook(ModelForm):
    """自定制ModelForm类"""
    class Meta:
        model=models.Book
        fields='__all__'

        labels={
                'name':'书名',
                'price':'价格',
                'pub':'出版社',
                'author':'作者',
        }


    def get_model_class(self):
        '''判断是否自定制了ModelForm'''
        if not self.Stark_Model_Form:
            from django.forms import ModelForm
            class ModelDeMo(ModelForm):
                class Meta:
                    model = self.model
                    fields = '__all__'
            return ModelDeMo
        else:
            return self.Stark_Model_Form

    def add_view(self,request):
        '''增加的视图函数'''
        # self--->stark_class_obj--->每一个单独的配置类.
        ModelDeMo=self.get_model_class()
        if request.method=='GET':

            form =ModelDeMo()
            return render(request, 'oprate/add.html', {'form':form})

        if request.method=='POST':
            form = ModelDeMo(request.POST)
            if form.is_valid():
                form.save()
                return redirect(self.get_list_url())
            else:
                return render(request,'oprate/add.html',{'form':form})

###########前端#########
<form class="form-horizontal col-sm-7" method="post" novalidate>
    {% csrf_token %}
    {% for data in form  %}
        <label>{{ data.label }}</label>
        {{ data }}
        <div class="errors-form">{{ data.errors.0 }}</div>
    {% endfor %}

    <button type="submit" class="btn btn-success">提交</button>
</form>
add

改:

和增加差不多

    def change_view(self,request,nid):
        '''改 视图函数'''
        # self--->stark_class_obj--->每一个单独的配置类.
        ModelDeMo=self.get_model_class()
        change_obj=self.model.objects.filter(id=nid).first()
        if request.method=='GET':
            form=ModelDeMo(instance=change_obj)
            return render(request,'oprate/edit.html',{'form':form})

        if request.method=='POST':
            show_url = self.get_list_url()
            #instance=change_obj
            # form.save()
            #执行的是update操作
            form=ModelDeMo(data=request.POST,instance=change_obj)
            if form.is_valid():
                form.save()
                return redirect(show_url)
            else:
                return render(request, 'oprate/edit.html', {'form': form})



###前端###

<form class="form-horizontal col-sm-7" method="post" novalidate>
    {% csrf_token %}
    {% for data in form  %}
        <label>{{ data.label }}</label>
        {{ data }}
        <div class="errors-form">{{ data.errors.0 }}</div>
    {% endfor %}

    <button type="submit" class="btn btn-success">提交</button>
</form>
change

删:

删要注意的是需要跳转到一个页面,确保用户误点

    def delete_view(self,request,nid):
        # 删除视图函数
        # self--->stark_class_obj--->每一个单独的配置类.
        del_obj = self.model.objects.filter(id=nid).first()
        show_url = self.get_list_url()

        if request.method=='GET':

            return render(request,'oprate/delete.html',{'show_url':show_url})
        if request.method=='POST':
            if del_obj:
                del_obj.delete()
                return redirect(show_url)


###前端######

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>删除页面</h1>
<form action="" method="post" novalidate>
    {% csrf_token %}
    <input type="submit" value="确认删除">
    <a href="{{ show_url }}">取消</a>
</form>

</body>
</html>
View Code

 search

用户能够自己配置进行模糊查询

Q方法的补充

from django.db.models import Q

Q的两种玩法:

第一种:
查询字段必须是字段
    Book.objects.filter(Q(title='yuan')|Q(price=123))
    
第二种
查询字段可以是字符串:

#实例化一个Q对象
search_connction=Q()
#或查询默认是and
search_connction.connector='or'

for search_fiile in self.search_fiile   #self.search_fiile 用户自定制的['name','price']
    #append里面是一个元组
    #search_connction.children.append((search_fiile,'查询的内容'))
    search_connction.children.append((search_fiile+'__contains','查询的内容'))模糊查询

        data_list = self.model.objects.filter(search_list)
Q两种方法

stark实现search

需要自定制字段:

search_fields = ['name']
def get_search_connection(self,request):
        '''获取模糊查询的Q'''
        self.key_word=request.GET.get('q','')
        search_connction=Q()
        if self.key_word:
            search_connction.connector='or'
            for fields in self.search_fields:
                search_connction.children.append((fields+'__icontains',self.key_word))
        return search_connction


search_list=self.get_search_connection(request)

data_list = self.model.objects.filter(search_list)


##前端##
{% if showlist.config.search_fields %}
        <form action="" method="get" class="pull-right">
            <input type="text" name="q" value="{{ showlist.config.key_word }}"><button>查询</button>
        </form>
        {% endif %}
View Code

 

原文地址:https://www.cnblogs.com/chenxuming/p/9308049.html