Day65 crm项目stark组件之启动,注册,URL设计(仿照admin设计组件)

一、需求

仿照django的admin,开发自己的stark组件。实现类似数据库客户端的功能,对数据进行增删改查。

 

1.启动

2.注册

3.设计URL

二、实现

1、在settings配置中分别注册这三个app

# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'crmdj.apps.App01Config','stark.apps.StarkConfig',
]

注:python manage.py startapp  创建新项目

2、在crmdj的models文件中创建数据类

from django.db import models


class Author(models.Model):
    nid = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)
    age = models.IntegerField()

    def __str__(self):
        return self.name


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)
    # publishDate=models.DateField()
    price = models.DecimalField(max_digits=5, decimal_places=2)
    state = models.IntegerField(choices=[(1, "已出版"), (2, "未出版社")], default=1)
    # 与Publish建立一对多的关系,外键字段建立在多的一方
    publish = models.ForeignKey(to="Publish", to_field="nid", on_delete=models.CASCADE)
    # 与Author表建立多对多的关系,ManyToManyField可以建在两个模型中的任意一个,自动创建第三张表
    authors = models.ManyToManyField(to='Author', )

    def __str__(self):
        return self.title

ps: 进行数据库迁移, python manage.py makemigrations    ,   python manage.py migrate

 

3、扫描(加载)每一个app下的stark.py 

在每个app下创建stark.py,在项目启动时扫描每个app下的stark.py文件并执行

即在stark组件的apps.py中配置

from django.apps import AppConfig
from django.utils.module_loading import autodiscover_modules


class StarkConfig(AppConfig):
    name = 'stark'

    def ready(self):
        autodiscover_modules('stark')  #自动扫描

 

4、注册

仿照admin设置相关类,首先创建下面的文件

在执行admin.py文件时我们发现其实第一步就是导入admin,导入时通过单例模式生成了一个site对象,现在我们也来写一个类,生成一个单例对象

class StarkSite():
    '''
    全局类
    '''

    def __init__(self):
        self._registry = {}

    def register(self, model, admin_class=None):
        admin_class = admin_class or ModelStark
        self._registry[model] = admin_class(model)     #admin_class(model) 实例化一个配置类    
site = StarkSite()
 

在crmdj项目中的stark.py文件导入,这样我们也就得到了一个单例对象site,在注册时admin使用的是site对象的register方法,我们也学着他写一个register方法

from stark.service.sites import site

site.register(Book)
site.register(Publish)
site.register(Author)

这个方法的本质其实就是往self._registry这个字典中添加键值对,键就是我们的数据类(如Book类),值是一个类的对象,这个类就是我们要创建的第二个类,样式类

 

class ModelStark():
    '''
    默认配置类
    '''
    def __init__(self, model):
        self.model = model

    list_display = ("__str__")

self.model指的是什么?   就是用户访问的model

通过这个类我们控制页面展示的内容和样式

注册完成后,我们的site._registry字典中就有了我们注册类对应的键值对,接下来就要配置url了

 

5、url配置

admin中的url配置

from django.conf.urls import url
from django.contrib import admin


urlpatterns = [
    url(r'^admin/', admin.site.urls),

可以看到所有的url都是在admin.site.urls这个方法中生成的,我可以看看这个方法的源码

@property
def urls(self):
    return self.get_urls(), 'admin', self.name

其实就是做了一个分发,url是在self.get_urls()这个函数中生成的,接着看这个函数的主要代码

这里我们需要知道到是我们生成的url的格式都是admin/app名/表名,所以我们要想办法取到app名和表名拼接起来

for model, model_admin in self._registry.items():
    urlpatterns += [
        url(r'^%s/%s/' % (model._meta.app_label, model._meta.model_name), include(model_admin.urls)),
    ]

这里的model就是我们的数据类(如Book),如何通过他取到我们想要的呢

model._meta.app_label 取类所在的app名

model._meta.model_name 取类的名字

这样我们就成功拼接出了我们要的url,但是每个url下又有增删改查不同的url,这时又要再次进行分发,admin中使用了include方法,通过model_admin我们注册时样式类生成的对象下的url方法得到我们想要的

源码

def get_urls(self):
    from django.conf.urls import url
    def wrap(view):
        def wrapper(*args, **kwargs):
            return self.admin_site.admin_view(view)(*args, **kwargs)
        wrapper.model_admin = self
        return update_wrapper(wrapper, view)
    
   info = self.model._meta.app_label, self.model._meta.model_name
    urlpatterns = [
        url(r'^$', wrap(self.changelist_view), name='%s_%s_changelist' % info),
        url(r'^add/$', wrap(self.add_view), name='%s_%s_add' % info),
        url(r'^(.+)/history/$', wrap(self.history_view), name='%s_%s_history' % info),
        url(r'^(.+)/delete/$', wrap(self.delete_view), name='%s_%s_delete' % info),
        url(r'^(.+)/change/$', wrap(self.change_view), name='%s_%s_change' % info),
        # For backwards compatibility (was the change url before 1.9)
        url(r'^(.+)/$', wrap(RedirectView.as_view(
            pattern_name='%s:%s_%s_change' % ((self.admin_site.name,) + info)
        ))),
    ]
    return urlpatterns
@property
def urls(self):
    return self.get_urls()

其实和之前一样,只是做了又一次分发,并且对应了视图函数,这里我们先不看视图函数的内容,值得注意的是这一次的分发和视图函数都是写在样式类中的,而不是写在生成site的AdminStie类中

这样有什么好处呢,我们知道当我们要注册时,是可以自己定义一些属性的,其实要显示的页面也是可以自己定义的,所以讲这最后一层url分发和对应的函数写在样式类中可以方便我们进行自定义

看完了admin的做法,我们可以来写我们自己的代码了。

 

 

stark配置

首先在urls文件中配置

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),
]

 然后在我们创建的两个类中添加相关的代码,这里url对应的函数我们先简写  

默认配置类,starksite类,

from django.urls import path,re_path
from django.shortcuts import HttpResponse, render
from stark.templates import stark
from crmdj.models import *

class ModelStark():
    '''
    默认配置类
    '''
    def __init__(self, model):
        self.model = model

    list_display = ("__str__")
    def list_view(self, request):
        data = self.model.objects.all()
        return render(request, 'stark/list_view.html', {'list_display': ModelStark.list_display, 'data': data})

    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")

    @property
    def get_urls(self):
        temp = [
            path("", self.list_view),
            path("add/", self.add_view),
            re_path("(\d+)/change/", self.change_view),
            re_path("(\d+)/delete/", self.delete_view),
        ]
        print('--------', temp)
        return temp, None, None


class StarkSite():
    '''
    全局类
    '''

    def __init__(self):
        self._registry = {}

    def register(self, model, admin_class=None):
        admin_class = admin_class or ModelStark
        self._registry[model] = admin_class(model) # admin_class(model) 实例化一个配置类

    @property
    def urls(self):
        return self.get_urls(), None, None    # path('stark/', site.urls)

    def get_urls(self):
        #  动态为注册的模型类创建增删改查URL
        temp = []
        # {Book:ModelAdmin(Book),Publish:ModelAdmin(Publish)}
        for model, config_obj in self._registry.items():
            print("---->", model, config_obj)
            model_name = model._meta.model_name  #  获取模型name
            app_label = model._meta.app_label   # 获取app名字
            # print(model_name, app_label) # book crmdj
            temp.append(
                path("%s/%s/" % (app_label, model_name), config_obj.get_urls)  # 拼接路径,config_boj相当于
            )                                                              # admin_class or ModelStark的实例对象
        return temp
site = StarkSite()

 

posted @ 2019-04-12 17:11  addit  Views(83)  Comments(0)    收藏  举报