##CRM版本一实现功能



#1、新建一个stark组件
    组件就是应用
   一个项目可以有多个应用
   一个应用可以用在多个项目中
#2、参考admin源码 实现路由分发
        
#3、数据展示
    表头展示
    表单展示
    
#4、自定义数据列
    
#5、反向解析



#掌握技术点
from app01 import models
models.Book._meta.app_label  #获得模型表所在的应用名'app01'
models.Book._meta.model_name  #获得模型表对应的字符串名'book'
    
from app01 import models
models.Book._meta.get_field('title')
    <django.db.models.fields.CharField: title>  # 获取字段对象
models.Book._meta.get_field('title').verbose_name '书名'
models.Book._meta.get_field('price').verbose_name  # 获取字段对象verbose_name属性 当你没有指定的时候默认是字段字符串名'price'



  ##models 模型表结构




pythone客户管理系统开发项目源码 python crm 源码_ViewUI

pythone客户管理系统开发项目源码 python crm 源码_后端_02

from django.db import models


# Create your models here.
class Author(models.Model):
    nid = models.AutoField(primary_key=True)
    name=models.CharField( max_length=32)
    age=models.IntegerField()
    # 与AuthorDetail建立一对一的关系
    authorDetail=models.OneToOneField(to="AuthorDetail",on_delete=models.CASCADE)

    def __str__(self):
        return self.name

class AuthorDetail(models.Model):
    nid = models.AutoField(primary_key=True)
    birthday=models.DateField()
    telephone=models.BigIntegerField()
    addr=models.CharField( max_length=64)


    def __str__(self):
        return self.addr

class Publish(models.Model):
    nid = models.AutoField(primary_key=True)
    name=models.CharField( max_length=32)
    city=models.CharField( max_length=32)
    email=models.EmailField()

    def __str__(self):
        return self.name

class Book(models.Model):
    nid = models.AutoField(primary_key=True)
    title = models.CharField(max_length=32,verbose_name='书名')
    publishDate=models.DateField(verbose_name='出版日期')
    price=models.DecimalField(max_digits=5,decimal_places=2, verbose_name='价格')
    # 与Publish建立一对多的关系,外键字段建立在多的一方
    publish=models.ForeignKey(to="Publish",to_field="nid",on_delete=models.CASCADE)  # django 2.0版本必须写 1.0默认
    # 与Author表建立多对多的关系,ManyToManyField可以建在两个模型中的任意一个,自动创建第三张表
    authors=models.ManyToManyField(to='Author',)

    def __str__(self):
        return self.title


View Code


  ##修改启动文件 C:\starkpro\stark\apps.py



启动
    django一启动就要执行每一个应用下的stark.py(单独新建的一个文件)文件(django默认会启动admin.py文件)

配置文件中注册
    INSTALLED_APPS = [
        'stark.apps.StarkConfig',
    ]
在StarkConfig类中 固定写ready方法
    from django.apps import AppConfig
    from django.utils.module_loading import autodiscover_modules

    class StarkConfig(AppConfig):
        name = 'stark'

        def ready(self):
            # 项目启动就会自动查找每一个应用下的stark.py文件
            return autodiscover_modules('stark')



  ##注册源码



#模拟Django应用程序下每一个admin.py文件注册功能

#路径:
    C:\starkpro\stark\service\stark.py
#基础注册模板:
    
    class ModelStark(object):
        def __init__(self,model):
            self.model = model
    class StarkSite(object):
        def __init__(self, name='admin'):
            self._registry = {}  # model_class class -> admin_class instance

        def register(self, model, admin_class=None, **options):
            if not admin_class:
                admin_class = ModelStark
            self._registry[model] = admin_class(model)
        @property
        def urls(self):
            return self.get_urls(), None, None
    site = StarkSite()
#配置路由urls:注意:自定义生成的site对象点urls,这里的urls不是属性而是一个方法被property修饰的方法
    from django.conf.urls import url
    from django.contrib import admin
    from stark.service.stark import site
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^stark/', site.urls),
    ]



  ##开始实现一级路由分发:C:\starkpro\stark\service\stark.py



from django.conf.urls import url
from django.shortcuts import HttpResponse
class ModelStark(object):
    def __init__(self,model):
        self.model = model
class StarkSite(object):
    def __init__(self, name='admin'):
        self._registry = {}  # model_class class -> admin_class instance

    def register(self, model, admin_class=None, **options):
        if not admin_class:
            admin_class = ModelStark
        self._registry[model] = admin_class(model)
    def test(self,request):
        return HttpResponse('test')
    def get_urls(self):
        #先定义一个列表,因为要给调用者返回列表
        tmp = []
        #循环字典_registry
        for model_class,config_obj in self._registry.items():
            # print(model_class) #<class 'app01.models.Author'> 类字符串
            # print(config_obj) #<stark.service.stark.ModelStark object at 0x000001A79CC58C18> 配置类对象

            #获得模型表所在的应用名
            app_label = model_class._meta.app_label
            # 获得模型表对应的字符串名
            model_name = model_class._meta.model_name
            tmp.append(
                url(r'^%s/%s/'%(app_label,model_name),self.test)
            )
        return tmp
    @property
    def urls(self):
        return self.get_urls(), None, None

site = StarkSite()



  ##stark二级路由设计



用配置对象解决二级路由。解决的问题是:不同表对应不同的对象,展示到页面上的内容也不一样,一次不能直接使用同一对象site来进行路由二级分发,不然不同路径内容却是一样的

操作文件:C:\starkpro\stark\service\stark.py
from django.conf.urls import url
from django.shortcuts import HttpResponse
class ModelStark(object):
    def __init__(self,model):
        self.model = model #self.model是指拿到当前对象所对应的模型表名,即四张表对应都不一样
    def list_view(self, request):
        #查看self.model  <class 'app01.models.Book'> 那张表查看就代表谁
        print(self.model)
        return HttpResponse('list')

    def add_view(self, request):
        return HttpResponse('add')

    def edit_view(self, request, id):
        return HttpResponse('edit')

    def delete_view(self, request, id):
        return HttpResponse('delete')
    @property
    def urls(self): #此处的self是指配置类对象
        tmp = [
            url(r'^$',self.list_view),
            url(r'^add/',self.add_view),
            url(r'^edit/(\d+)/',self.edit_view),
            url(r'^delete/(\d+)/',self.delete_view),
        ]

        return tmp,None,None
class StarkSite(object):
    def __init__(self, name='admin'):
        self._registry = {}  # model_class class -> admin_class instance

    def register(self, model, admin_class=None, **options):
        if not admin_class:
            admin_class = ModelStark
        self._registry[model] = admin_class(model)
    def test(self,request):
        return HttpResponse('test')
    def get_urls(self):
        #先定义一个列表,因为要给调用者返回列表
        tmp = []
        #循环字典_registry
        for model_class,config_obj in self._registry.items():
            # print(model_class) #<class 'app01.models.Author'> 类字符串
            # print(config_obj) #<stark.service.stark.ModelStark object at 0x000001A79CC58C18> 配置类对象

            #获得模型表所在的应用名
            app_label = model_class._meta.app_label
            # 获得模型表对应的字符串名
            model_name = model_class._meta.model_name
            tmp.append(
                url(r'^%s/%s/'%(app_label,model_name),config_obj.urls)
            )
        return tmp
    @property
    def urls(self):
        return self.get_urls(), None, None

site = StarkSite()



  ##动态展示数据:



def list_view(self, request):
    #查看self.model  <class 'app01.models.Book'> 那张表查看就代表谁
    # print(self.model)

    queryset = self.model.objects.all()
    # 表头展示
    header_list = []
    for field in self.list_display:
        if field == '__str__': #当用户没有指定list_display 默认展示当前表的大写名字
            val = self.model._meta.model_name.upper()
        else:
            val = self.model._meta.get_field(field).verbose_name
        header_list.append(val)
    #表单展示
    body_list = [] #格式定义 [[obj1.title,obj1.price],[obj2.title,obj2.price],[]]

    for obj in queryset:
        tmp = []
        for field in self.list_display:#注意这里的list_display查找顺序,先查自己的,在查全局的,然后循环要展示的字段
            val = getattr(obj,field) #通过反射获取obj对象中field字段所对应的值

            tmp.append(val)

        body_list.append(tmp)


    return render(request,'stark/list_view.html',locals())
    

#前端:
    <div class="container">
    <div class="row">
        <h2 class="text-center">数据展示</h2>
        <table class="table table-striped table-bordered table-hover">
            <div class="col-md-8 col-md-offset-2">
                <thead>
                    <tr>
                        {% for foo in header_list %}
                        <td>{{ foo }}</td>
                        {% endfor %}
                    </tr>
                </thead>
                <tbody>
                {% for body in body_list %}
                    <tr>
                        {% for  foo in body %}
                            <td>
                                {{ foo }}
                            </td>
                        {% endfor %}
                    </tr>
                {% endfor %}
                </tbody>
            </div>
        </table>
</div>
</div>



  ##自动生成数据:



1、通过给定函数参数默认值,来对函数附加额外功能
2、checkbox、编辑、删除 默认所有的表都生成这三个字段

在注册stark文件
from stark.service.stark import site,ModelStark
from app01 import models
from django.utils.safestring import mark_safe
site.register(models.Author)
site.register(models.AuthorDetail)

class BookConfig(ModelStark):

    list_display = ['title','price','publishDate']
site.register(models.Book,BookConfig)
site.register(models.Publish)

C:\starkpro\stark\service\stark.py
from django.conf.urls import url
from django.shortcuts import HttpResponse,render,redirect
from django.utils.safestring import mark_safe


class ModelStark(object):
    list_display = ['__str__',]
    def __init__(self,model):
        self.model = model #self.model是指拿到当前对象所对应的模型表名,即四张表对应都不一样

    def check_box(self,is_header=False):
        if is_header:
            return '选择'
        return mark_safe('<input type="checkbox"/>')
    def edit_col(self,is_header=False):
        if is_header:
            return '编辑'
        return mark_safe('<a href=''>编辑</a>')
    def delete_col(self,is_header=False):
        if is_header:
            return '删除'
        return mark_safe('<a href=''>删除</a>')

    def get_new_list(self):
        tmp=[]
        tmp.append(ModelStark.check_box)
        tmp.extend(self.list_display)
        tmp.append(ModelStark.edit_col)
        tmp.append(ModelStark.delete_col)
        return tmp
    def list_view(self, request):
        #查看self.model  <class 'app01.models.Book'> 那张表查看就代表谁
        # print(self.model)

        queryset = self.model.objects.all()
        # 表头展示
        header_list = []
        for field_or_func in self.get_new_list():
            if isinstance(field_or_func,str):
                if field_or_func == '__str__': #当用户没有指定list_display 默认展示当前表的大写名字
                    val = self.model._meta.model_name.upper()
                else:
                    val = self.model._meta.get_field(field_or_func).verbose_name
            else:
                val = field_or_func(self,is_header=True)
            header_list.append(val)
        #表单展示
        body_list = [] #格式定义 [[obj1.title,obj1.price],[obj2.title,obj2.price],[]]

        for obj in queryset:
            tmp = []
            for field_or_func in self.get_new_list():#注意这里的list_display查找顺序,先查自己的,在查全局的,然后循环要展示的字段
                if isinstance(field_or_func,str):
                    val = getattr(obj,field_or_func) #通过反射获取obj对象中field字段所对应的值
                else:
                    val = field_or_func(self)
                tmp.append(val)

            body_list.append(tmp)


        return render(request,'stark/list_view.html',locals())

    def add_view(self, request):
        return HttpResponse('add')

    def edit_view(self, request, id):
        return HttpResponse('edit')

    def delete_view(self, request, id):
        return HttpResponse('delete')
    @property
    def urls(self): #此处的self是指配置类对象
        tmp = [
            url(r'^$',self.list_view),
            url(r'^add/',self.add_view),
            url(r'^edit/(\d+)/',self.edit_view),
            url(r'^delete/(\d+)/',self.delete_view),
        ]

        return tmp,None,None
class StarkSite(object):
    def __init__(self, name='admin'):
        self._registry = {}  # model_class class -> admin_class instance

    def register(self, model, admin_class=None, **options):
        if not admin_class:
            admin_class = ModelStark
        self._registry[model] = admin_class(model)
    def test(self,request):
        return HttpResponse('test')
    def get_urls(self):
        #先定义一个列表,因为要给调用者返回列表
        tmp = []
        #循环字典_registry
        for model_class,config_obj in self._registry.items():
            # print(model_class) #<class 'app01.models.Author'> 类字符串
            # print(config_obj) #<stark.service.stark.ModelStark object at 0x000001A79CC58C18> 配置类对象

            #获得模型表所在的应用名
            app_label = model_class._meta.app_label
            # 获得模型表对应的字符串名
            model_name = model_class._meta.model_name
            tmp.append(
                url(r'^%s/%s/'%(app_label,model_name),config_obj.urls)
            )
        return tmp
    @property
    def urls(self):
        return self.get_urls(), None, None

site = StarkSite()



  ##反向解析



1、二级urls取别名:
    def __init__(self,model):
        self.model = model #self.model是指拿到当前对象所对应的模型表名,即四张表对应都不一样
        self.app_label = self.model._meta.app_label  #直接给对象初始化应用名
        self.model_name = self.model._meta.model_name #直接给对象初始化表名
     @property
    def urls(self): #此处的self是指配置类对象
        tmp = [
            url(r'^$',self.list_view,name="%s_%s_%s"%(self.app_label,self.model_name,'list')),#应用名+表明+操作
            url(r'^add/',self.add_view,name="%s_%s_%s"%(self.app_label,self.model_name,'add')),
            url(r'^edit/(\d+)/',self.edit_view,name="%s_%s_%s"%(self.app_label,self.model_name,'edit')),
            url(r'^delete/(\d+)/',self.delete_view,name="%s_%s_%s"%(self.app_label,self.model_name,'delete')),
        ]
2、后端用到 reserse  obj为一个对象,因为编辑和删除时需要用到id,在访问的url链接中也会拼接一个id,所以再表单渲染那执行函数的时候传入obj
        def get_reverse_url(self,type,obj=None):
            if obj:
                _url = reverse("%s_%s_%s" % (self.app_label, self.model_name, type), args=(obj.pk,))
            else:
                _url = reverse("%s_%s_%s" % (self.app_label, self.model_name, type))
            return _url
            
        def edit_col(self,is_header=False,obj=None):
            if is_header:
                return '编辑'
            _url = self.get_reverse_url('edit',obj)
            return mark_safe('<a href="%s">编辑</a>'%_url)

        def delete_col(self,is_header=False,obj=None):
            if is_header:
                return '删除'
            _url =  self.get_reverse_url('delete',obj)
            return mark_safe('<a href="%s">删除</a>'%_url)
3、函数根据参数传入的不同返回不同的结果