• stark组件


    一 . 需求 

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

    二 . 实现思路 

      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',
        'app01.apps.App01Config',
        'app02.apps.App02Config',
        'stark.apps.StarkConfig',
    ]
    # (名字无所谓,叫stark纯属好记,清晰)

    注 : python manage.py startapp app02      创建新项目(stark 同理)

    2 . 在app01和app02的model文件中创建数据类型

     app01/models.py

    from django.db import models

    # Create your models here.
    from django.contrib.auth.models import AbstractUser

    class UserInfo(models.Model):
    """
    用户信息
    """
    nid = models.AutoField(primary_key=True)
    nickname = models.CharField(verbose_name='昵称', max_length=32)
    telephone = models.CharField(max_length=11, null=True, unique=True)
    avatar = models.FileField(upload_to = 'avatars/',default="/avatars/default.png")
    create_time = models.DateTimeField(verbose_name='创建时间', auto_now_add=True)
    blog = models.OneToOneField(to='Blog', to_field='nid',null=True)

    def __str__(self):
    return self.nickname

    class Blog(models.Model):

    """
    博客信息
    """
    nid = models.AutoField(primary_key=True)
    title = models.CharField(verbose_name='个人博客标题', max_length=64)
    site = models.CharField(verbose_name='个人博客后缀', max_length=32, unique=True)
    theme = models.CharField(verbose_name='博客主题', max_length=32)
    #
    # def __str__(self):
    # return self.title
    class Category(models.Model):
    """
    博主个人文章分类表
    """
    nid = models.AutoField(primary_key=True)
    title = models.CharField(verbose_name='分类标题', max_length=32)
    blog = models.ForeignKey(verbose_name='所属博客', to='Blog', to_field='nid')

    def __str__(self):
    return self.title
    class Tag(models.Model):

    nid = models.AutoField(primary_key=True)
    title = models.CharField(verbose_name='标签名称', max_length=32)
    blog = models.ForeignKey(verbose_name='所属博客', to='Blog', to_field='nid')
    def __str__(self):
    return self.title
    class Article(models.Model):

    nid = models.AutoField(primary_key=True)
    title = models.CharField(max_length=50, verbose_name='文章标题')
    desc = models.CharField(max_length=255, verbose_name='文章描述')

    comment_count= models.IntegerField(default=0)
    up_count = models.IntegerField(default=0)
    down_count = models.IntegerField(default=0)

    create_time = models.DateTimeField(verbose_name='创建时间')

    homeCategory = models.ForeignKey(to='Category', to_field='nid', null=True)
    #siteDetaiCategory = models.ForeignKey(to='SiteCategory', to_field='nid', null=True)

    user = models.ForeignKey(verbose_name='作者', to='UserInfo', to_field='nid')
    tags = models.ManyToManyField(
    to="Tag",
    through='Article2Tag',
    through_fields=('article', 'tag'),
    )


    def __str__(self):
    return self.title
    class ArticleDetail(models.Model):
    """
    文章详细表
    """
    nid = models.AutoField(primary_key=True)
    content = models.TextField()
    article = models.OneToOneField(to='Article', to_field='nid')

    class Article2Tag(models.Model):
    nid = models.AutoField(primary_key=True)
    article = models.ForeignKey(verbose_name='文章', to="Article", to_field='nid')
    tag = models.ForeignKey(verbose_name='标签', to="Tag", to_field='nid')

    class Meta:
    unique_together = [
    ('article', 'tag'),
    ]

    def __str__(self):
    v=self.article.title+"----"+self.tag.title
    return v

    app01/models.py

    app01/models.py

     app02/models.py
    from django.db import models
    
    # Create your models here.
    class Book(models.Model):
        title=models.CharField(max_length=32,verbose_name="标题")

       注 : python manage.py makemigrations      (同步数据库)

        python manage.py migrate 

    3 . 在(不确定当前APP中的app.py文件中添加   目的:让项目一运行先把所有app里面所有叫stark的加载一遍

    复制代码
    from django.apps import AppConfig
    from django.utils.module_loading import autodiscover_modules
    
    class AppConfig(AppConfig):
        
        name = "app01"
    
        def ready(self):
            
            autodiscover_modules("stark",)

    实现在Django项目启动时,扫描每个APP项目下的stark.py文件的文件, 执行其中的代码,注册每个APP下的model,为每个model生成增删改查四条URL.

      流程图说明一切 (~ ̄▽ ̄)~ 

    4 . 注册 

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

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

    复制代码
    class StarkSite(object):
        
        def __init__(self):
            self._registry = {}
        
    site = StarkSite()
    复制代码

       在app01 和 app02 的 stark.py 文件中导入 

    from stark.service.stark import site

       这样我们也就得到了一个单例对象 site, 在注册时 admin使用的是site对象的 register 方法,所以我们也要写一个 register 方法 . 

    复制代码
    class StarkSite(object):
    
        def __init__(self):
            self._registry={}
    
        def register(self,model,modle_stark=None):
            if not modle_stark:
                modle_stark=ModelStark
    
            self._registry[model]=modle_stark(model)
    site = StarkSite()
    复制代码

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

    class ModelStark(object):
    
        def __init__(self, model, site):
            self.model = model
            self.site = site

       注意 : self.model 指的是什么?  self 指的是什么? 

        self  : 当前访问模型表的配置类对象

        self.model : 当前访问模型表(如 Book 表)

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

        前戏完成之后我们就可以在app01 和app02的stark.py文件中开始注册了

    复制代码
    #app01
    
    from stark.service.stark import site
    
    from .models import *
    
    class UserInfoConfig(ModelStark):
        list_display = ["nickname", "telephone"]
    
    site.register(UserInfo,UserInfoConfig)
    site.register(Blog)
    site.register(Article)
    site.register(Category)
    site.register(Tag)
    
    
    
    #app02
    from stark.service.stark import site
    from .models import *
    
    class BookConfig(ModelStark):
        list_display = ["title"]
    
    site.register(Book,BookConfig)
    复制代码

          注册完成后,我们的 site._registry字典中就有了我们注册类对应的键值对.

    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() 这个函数中,生成的,

    复制代码
    def get_urls(self):
            from django.conf.urls import url, include
            # Since this module gets imported in the application's root package,
            # it cannot import models from other applications at the module level,
            # and django.contrib.contenttypes.views imports ContentType.
            from django.contrib.contenttypes import views as contenttype_views
    
            def wrap(view, cacheable=False):
                def wrapper(*args, **kwargs):
                    return self.admin_view(view, cacheable)(*args, **kwargs)
                wrapper.admin_site = self
                return update_wrapper(wrapper, view)
    
            # Admin-site-wide views.
            urlpatterns = [
                url(r'^$', wrap(self.index), name='index'),
                url(r'^login/$', self.login, name='login'),
                url(r'^logout/$', wrap(self.logout), name='logout'),
                url(r'^password_change/$', wrap(self.password_change, cacheable=True), name='password_change'),
                url(r'^password_change/done/$', wrap(self.password_change_done, cacheable=True),
                    name='password_change_done'),
                url(r'^jsi18n/$', wrap(self.i18n_javascript, cacheable=True), name='jsi18n'),
                url(r'^r/(?P<content_type_id>d+)/(?P<object_id>.+)/$', wrap(contenttype_views.shortcut),
                    name='view_on_site'),
            ]
    
            # Add in each model's views, and create a list of valid URLS for the
            # app_index
            valid_app_labels = []
            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)),
                ]
                if model._meta.app_label not in valid_app_labels:
                    valid_app_labels.append(model._meta.app_label)
    
            # If there were ModelAdmins registered, we should have a list of app
            # labels for which we need to allow access to the app_index view,
            if valid_app_labels:
                regex = r'^(?P<app_label>' + '|'.join(valid_app_labels) + ')/$'
                urlpatterns += [
                    url(regex, wrap(self.app_index), name='app_list'),
                ]
            return urlpatterns
    复制代码

    这里我们知道我们要生成的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分发和对应的函数写在样式类中可以方便我们进行自定义

    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),
    ]
    复制代码

    然后在我们 sites.py文件中添加相关代码.简写

    复制代码
    from django.conf.urls import url
    from django.shortcuts import HttpResponse, render
    
    
    class ModelStark(object):
    
        def __init__(self, model, site):
            self.model = model
            self.site = site
    
        def change_list(self, request):
            ret = self.model.objects.all()
            return render(request, "stark/change_list.html", locals())
    
        def add_view(self, request):
            return HttpResponse("add_view")
    
        def del_view(self, request, id):
            return HttpResponse("del_view")
    
        def change_view(self, request, id):
            return HttpResponse("change_view")
    
        def get_url_func(self):
            temp = []
            temp.append(url("^$", self.change_list))
            temp.append(url("^add/$", self.add_view))
            temp.append(url("^(d+)/delete/$", self.del_view))
            temp.append(url("^(d+)/change/$", self.change_view))
            return temp
    
        @property
        def urls(self):
            return self.get_url_func(), None, None
    
    
    class StarkSite(object):
        
        def __init__(self):
            self._registry = {}
    
        def register(self, model, model_config=None):
            if not model_config:
                model_config = ModelStark
    
            self._registry[model] = model_config(model, self)
    
        def get_urls(self):
            temp = []
            for model, model_config in self._registry.items():
                model_name = model._meta.model_name
                app_label = model._meta.app_label
                u = url("^%s/%s/" % (app_label, model_name), model_config.urls)
                temp.append(u)
            return temp
    
        @property
        def urls(self):
            return self.get_urls(), None, None
        
    site = StarkSite()
    复制代码

    反向解析,别名的使用.

    在设置url对应的视图函数时,我们可以给这个url添加一个别名,在使用时可以通过这个别名反向生成url,这样既可以使url有修改,只要别名不变我们就不用修改代码.

    增加别名时要注意 : 由于每一个数据类都生成增删改查四条url,所以在写别名的时候应该有区别,不然会引起混淆,所以我们设计别名的格式应该是 -- app名_表名_*

    复制代码
    def get_url_func(self):
        temp = []
        model_name = self.model._meta.model_name
        app_label = self.model._meta.app_label
        app_model = (app_label, model_name)
        temp.append(url("^$", self.change_list, name="%s_%s_list" % app_model))
        temp.append(url("^add/$", self.add_view, name="%s_%s_add" % app_model))
        temp.append(url("^(d+)/delete/$", self.del_view, name="%s_%s_delete" % app_model))
        temp.append(url("^(d+)/change/$", self.change_view, name="%s_%s_change" % app_model))
        return temp
    @property
    def urls(self):
        return self.get_url_func(), None, None
    复制代码

    list_display_links

    复制代码
        def new_list_display(self):
            temp=[]
            temp.append(ModelStark.checkbox)
            temp.extend(self.list_display)#把数据打散,用append是把整个列表放进去
            #---------------------有list_display_links则不显示编辑字段
            if not self.list_display_links:
                temp.append(ModelStark.edit)
    print('sssssssssssssssssssssssssssss',self.list_display_links)
            temp.append(ModelStark.deletes)
         
            return temp
    复制代码

    新语法

    from app1.models import Book
    
    obj = Book._meta.get_field("title")
    
       # obj 为 一个field 对象       打印结果: <django.db.models.fields.CharField: title>
    
    print(obj.verbose_name)   
    #  默认打印为“title” ,如果模型类中设置为该字段设置了,verbose_name="书籍名称”
    #则会打印书籍名称
  • 相关阅读:
    【芯片】国产MCU替代ST芯片调查
    【生产线】包装如何防止配件漏装
    【标准】运输振动试验
    【bat】批量提取文件夹内文件的名称
    【VBA】从批量excel文件中获取数据
    【滤波器】抗混叠滤波器
    【元器件】晶振TCXO、OCXO
    【C】三点求抛物线顶点
    德卡T10读卡器 读取身份证号码和身份证UID
    C# 执行查询语句,返回DataSet
  • 原文地址:https://www.cnblogs.com/xyhh/p/10856883.html
Copyright © 2020-2023  润新知