10.19stark组件开发(三)

  2018-10-19 15:42:15

2018-10-19 18:21:33

我觉得现在主要是学一种解决问题的思路,也就是逻辑或者说是算法!!!!

要有对代码的感触!要用面向对象对类进行封装!!Django源码写的就是很6

明天看完stark 然后整理Django !!周末啦!

过不久还得回学校!!!难得的在家清静!珍惜吧!

越努力,越幸运!!!永远不要高估自己!!

 

.model._meta的用法!

通过字段获取QuerySet对象

通过字段获取 app和表的名字!

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

这次新增了自定义过滤功能!
新学了上面两个知识点!
在源码上都有相应的注释!很好看懂!
不难就是有点绕!!

server/stark.py
from django.conf.urls import url
from django.shortcuts import render, redirect
from django.urls import reverse
from django.utils.safestring import mark_safe
from django.forms import ModelForm
from stark.utils.page import Pagination
from django.db.models import Q
from django.db.models.fields.related import ForeignKey
from django.db.models.fields.related import ManyToManyField
import copy


class ShowList(object):
    # 这是一个配置类的对象初始化
    def __init__(self, config, data_list, request):
        self.config = config
        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=3, pager_count=11,)
        self.page_data = self.data_list[self.pagination.start:self.pagination.end]
        # actions   获取actions这个配置类的列表
        self.actions = self.config.actions  # [patch_init,]

    # 处理filter字段连接
    def get_filter_linktags(self):
        """用了两次for循环,在算法上有点缀余!不过可以用类或函数封装只是懒-.-能力欠缺!"""
        print("list_filter:", self.config.list_filter)
        link_dic = {}
        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)
            print("filter_field", filter_field)  # "publish"
            # 通过_meta.get_field方法,获取该表名对象
            filter_field_obj = self.config.model._meta.get_field(filter_field)

            print("filter_field_obj", filter_field_obj)
            print(type(filter_field_obj))
            # print("rel...",filter_field_obj.rel.to.objects.all())

            # 判断一下 如果是多对多或一对多类型的
            if isinstance(filter_field_obj, ForeignKey) or isinstance(filter_field_obj, ManyToManyField):
                # 拿到表的所有QuerySet对象
                data_list = filter_field_obj.rel.to.objects.all()  # 【publish1,publish2...】
            else:
                # 这个则是自定义过滤字段
                data_list = self.config.model.objects.all().values("pk", filter_field)
                print("data_list", data_list)

            temp = []
            # 处理 全部标签
            if params.get(filter_field):
                # 如果url如果存在参数 则del
                del params[filter_field]
                temp.append("<a href='?%s'>全部</a>" % params.urlencode())
            else:
                # 反之加上class 增加颜色
                temp.append("<a  class='active' href='#'>全部</a>")

            # 处理 数据标签
            for obj in data_list:
                # 循环列表中每个QuerySet的对象然后取到相应的值
                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"},....]
                    pk = obj.get("pk")
                    text = obj.get(filter_field)
                    params[filter_field] = text

                _url = params.urlencode()
                if cid == str(pk) or cid == text:
                    link_tag = "<a class='active' href='?%s'>%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

    # 获取下拉框 用户配置的action_list
    def get_action_list(self):
        temp = []
        for action in self.actions:
            #  [{"name":""patch_init,"desc":"批量初始化"}]
           temp.append({
               "name": action.__name__,
               "desc": action.short_description
           })
        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__)
                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:
                    # header_list.append(field)
                    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:
            temp = []
            for filed in self.config.new_list_play():  # ["__str__",]      ["pk","name","age",edit]
                if callable(filed):
                    val = filed(self.config, obj)
                else:
                    field_obj = self.config.model._meta.get_field(filed)
                    if isinstance(field_obj, ManyToManyField):
                        # getattr()仅取到Object, 然后.all() 则可以取到对象
                        ret = getattr(obj, filed).all()
                        t = []
                        for obj in ret:
                            t.append(str(obj))
                        val = ",".join(t)

                    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("<a href='%s'>%s</a>" % (_url, val))

                temp.append(val)

            new_data_list.append(temp)
        return new_data_list


class ModelStark(object):
    # 默认的list_play[]
    list_display = ["__str__", ]
    list_display_links = []
    modelform_class = None
    search_fields = []
    actions = []
    list_filter = []

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

    # 默认的批量删除action
    def patch_delete(self, request, queryset):
        queryset.delete()
    patch_delete.short_description = "批量删除"

    # 配置表头: 删除 编辑,复选框
    def edit(self, obj=None, header=False):
        """编辑"""
        if header:
            return "操作"
        # return mark_safe("<a href='%s/change'>编辑</a>"%obj.pk)
        _url = self.get_change_url(obj)
        return mark_safe("<a href='%s'>编辑</a>" % _url)

    def deletes(self, obj=None, header=False):
        """删除"""
        if header:
            return "操作"
        # return mark_safe("<a href='%s/change'>编辑</a>"%obj.pk)
        _url = self.get_delete_url(obj)
        return mark_safe("<a href='%s'>删除</a>" % _url)

    def checkbox(self, obj=None, header=False):
        """复选框"""
        if header:
            return mark_safe('<input id="choice" type="checkbox">')
        # value的值不能写死,
        return mark_safe('<input class="choice_item" type="checkbox" name="selected_pk" value="%s">' % obj.pk)

    # 获取配置类的表头信息
    def get_modelform_class(self):
        """获取表的配置类"""
        if not self.modelform_class:
            # 如果表的配置类为空
            class ModelFormDemo(ModelForm):
                class Meta:
                    model = self.model
                    fields = "__all__"
                    labels = {
                        ""
                    }
            return ModelFormDemo
        else:
            return self.modelform_class

    # 添加的视图函数
    def add_view(self, request):
        ModelFormDemo = self.get_modelform_class()
        if request.method == "POST":
            form = ModelFormDemo(request.POST)
            if form.is_valid():
                form.save()
                return redirect(self.get_list_url())

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

        form = ModelFormDemo()

        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):
        ModelFormDemo = self.get_modelform_class()
        edit_obj = self.model.objects.filter(pk=id).first()
        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, "add_view.html", locals())
        form = ModelFormDemo(instance=edit_obj)
        return render(request, "change_view.html", locals())

    # 搜索的视图函数
    def get_serach_conditon(self, request):
        key_word = request.GET.get("q", "")
        self.key_word = key_word
        search_connection = Q()
        if key_word:
            # self.search_fields # ["title","price"]
            search_connection.connector = "or"
            # 用Q的这种添加方法可以添加字符串
            for search_field in self.search_fields:
                # search_field+"__contains"  ---->  title__contains="o"   就是title字段里面包含字母o的
                search_connection.children.append((search_field + "__contains", key_word))
        return search_connection

    # 过滤filter的视图函数
    def get_filter_condition(self, request):
        filter_condition = Q()
        for filter_field, val in request.GET.items():
            if filter_field in self.list_filter:
                filter_condition.children.append((filter_field, val))
        return filter_condition

    # 查看的视图函数
    def list_view(self, request):
        if request.method == "POST":  # action
            print("POST:", request.POST)
            action = request.POST.get("action")  # patch_init
            selected_pk = request.POST.getlist("selected_pk")
            action_func = getattr(self, action)
            queryset = self.model.objects.filter(pk__in=selected_pk)
            ret = action_func(request, queryset)
            # return ret
        # 获取search的Q对象
        search_connection = self.get_serach_conditon(request)

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

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

        # 按这ShowList展示页面
        showlist = ShowList(self, data_list, request)

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

    #  获取用户配置类里面的list_play[]
    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

    # 获取用户配置类里面的actions 这个列表
    def new_actions(self):
        temp=[]
        temp.append(ModelStark.patch_delete)
        temp.extend(self.actions)
        return temp

    """把url进行反向解析,解耦到各自的函数中,函数中直接返回了对应的url"""
    # 获取修改页面的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

    # 获删除改页面的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

    # 获取添加页面的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

    # 获取查看页面的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

    # 二级url分发函数
    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)))
        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)))
        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)

    # 一级分发url函数
    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


# 创建stark的一个单例对象
site = StarkSite()

app01/stark.py

from stark.service.stark import site,ModelStark

from django.urls import reverse
from .models import *


from django.utils.safestring import mark_safe

from django.forms import ModelForm
from django.forms import widgets as wid


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

        labels={
            "title":"书籍名称",
            "price":"价格"
        }

from django.shortcuts import HttpResponse

class BookConfig(ModelStark):
    # 自定义展示列表
    list_display = ["title","price","publishDate","publish","authors"]
    # 自定义设置字段为连接
    list_display_links = ["title"]
    modelform_class=BookModelForm
    # 自定义搜索字段
    search_fields=["title","price"]

    def patch_init(self, request, queryset):
        print(queryset)
        queryset.update(price=123)

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

    patch_init.short_description = "批量初始化"

    # 自定义处理函数
    actions = [patch_init]

    # 自定义筛选字段
    list_filter=["title","publish","authors",]


site.register(Book,BookConfig)






site.register(Publish)
site.register(Author)
site.register(AuthorDetail)

list.html

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.css">
    <script src="/static/js/jquery-1.12.4.min.js"></script>

    <style>
        .filter a{
            text-decoration: none;
            color: grey;
        }

        .active{
            color: rebeccapurple!important;
        }
    </style>
</head>
<body>

<h4>数据列表</h4>


<div class="container">
    <div class="row">
        <div class="col-md-9">
            <a href="{{ add_url }}" class="btn btn-primary">添加数据</a>

            {% if showlist.config.search_fields %}
                     <form action="" class="pull-right">
                        <input class="form-control" style="display: inline-block;width:200px" type="text" name="q" value="{{ showlist.config.key_word }}"><button class="btn btn-default">search</button>
                    </form>
            {% endif %}

            <form action="" method="post">
                    {% csrf_token %}
                    <select name="action"  class="form-control" id="" style="width: 200px;margin: 8px 2px;display: inline-block;vertical-align: -1px">
                         <option value="">---------------</option>
                        {% for item in showlist.get_action_list %}
                            <option value="{{ item.name }}">{{ item.desc }}</option>
                        {% endfor %}

                    </select><button type="submit" class="btn btn-success">Go</button>
                    <table class="table table-bordered table-striped">
                        <thead>
                             <tr>
                                 {% for item in showlist.get_header %}
                                   <th>{{ item }}</th>
                                 {% endfor %}

                             </tr>

                        </thead>
                        <tbody>
                             {% for data in showlist.get_body %}

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

                              </tr>
                             {% endfor %}

                        </tbody>
                    </table>
                        <nav class="pull-right">
                            <ul class="pagination">
                               {{ showlist.pagination.page_html|safe }}
                            </ul>
                        </nav>

            </form>
        </div>

        <div class="col-md-3">
            <div class="filter">
                <h4 style="">Filter</h4>
                {% for filter_field,linktags in showlist.get_filter_linktags.items %}
                   <div class="well">
                         <p>By {{ filter_field.upper }}</p>
                         {% for link in linktags %}
                         <p>{{ link|safe }}</p>
                         {% endfor %}
                   </div>
                {% endfor %}


            </div>
        </div>
    </div>
</div>



<script>

   $("#choice").click(function () {

     if($(this).prop("checked")){
           $(".choice_item").prop("checked",true)
     }else {
           $(".choice_item").prop("checked",false)
     }

   })

</script>
</body>
</html>

贴上笔记

stark


   分页
       分页组件
       保存搜索条件
   
   search
       
   action
   
   
   filter:
      
      
            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.to.objects.all())
self.config.model._meta.get_field(filter_field) 通过字符串找到拿到该名字表的对象
只要属性里面有 (to=) 就可以用
filter_field_obj.rel.to 拿到关联表 class对象

 

posted @ 2018-10-19 18:24  我想喝杨枝甘露~  阅读(148)  评论(0编辑  收藏  举报