Skip to main content

10行代码完成一张表的增删改查

Project description

django-faster

django-faster 10行代码实现一张表的增删改查

1 知识储备

1.1 创建项目

  • 创建django项目

    创建一个空文件夹用户存放django项目
    
    django-admin startproject faster  # faster 是项目名称
    
  • 创建两个django app

    cd faster
    
    python manage.py startapp fast 
    
    python manage.py startapp testapp 
    
  • 创建成功后的项目目录结构

    --demo 
      --faster
        --fast
          --migrations
          --__init__.py
          --admin.py
          --apps.py
          --models.py
          --tests.py
          --views.py
        --testapp
          --migrations
          --__init__.py
          --admin.py
          --apps.py
          --models.py
          --tests.py
          --views.py
        --faster
          --__init__.py
          --asgi.py
          --settings.py
          --urls.py
          --wsgi.py
        --manage.py
    

1.2 django程序启动前预留的钩子

  • faster/testapp/apps/

    from django.apps import AppConfig
    
    
    class TestappConfig(AppConfig):
        default_auto_field = "django.db.models.BigAutoField"
        name = "testapp"
    
    class AppConfig:
    	def ready(self):
            """
            Override this method in subclasses to run code when Django starts.
            在子类重写这个方法,当django启动时,执行这个方法中的代码
            """
            
    
  • 测试

    class TestappConfig(AppConfig):
        default_auto_field = "django.db.models.BigAutoField"
        name = "testapp"
        def ready(self):
            print('django启动前我被执行了')
    
    F:\auth_demo\faster\testapp\apps.py changed, reloading.
    django启动前我被执行了
    Watching for file changes with StatReloader
    Performing system checks...
    
    System check identified no issues (0 silenced).
    
    You have 18 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions.
    Run 'python manage.py migrate' to apply them.
    September 11, 2022 - 10:46:56
    Django version 4.1.1, using settings 'faster.settings'
    Starting development server at http://127.0.0.1:8000/
    Quit the server with CTRL-BREAK.
    

1.3 django路由分发的本质

首先说一下视图的类型,从视图的类型划分,有CBV和FBV即类视图和函数视图,一般类视图适合用于生成restful风格的API。函数视图使用比较简单。

1.3.1 路由的两种基本使用方式:

  • 方式一:

    这是最简单的路由设置,直接在项目文件夹下面的urls.py中配置路由规则和视图函数,浏览器访问http://127.0.0.1:8000/test/ 就会返回驶入函数的返回值。

    faster/faster/urls.py

    from django.contrib import admin
    from django.urls import path
    from testapp import views
    
    
    urlpatterns = [
        path("admin/", admin.site.urls),
        path('test/', views.test)
    ]
    

    faster/testapp/views.py

    from django.shortcuts import HttpResponse
    
    
    def test(request):
        return HttpResponse('test!')
    
  • 方式二

    使用include分发路由

    faster/faster/urls.py

    from django.contrib import admin
    from django.urls import path, include
    
    urlpatterns = [
        path("admin/", admin.site.urls),
        # 路由以test开头,那么分发到testapp的urls模块中,namespace用于反向生成url
        path('test/', include('testapp.urls', namespace='test'))
    ]
    

    faster/testapp/urls.py

    from django.urls import path
    
    from . import views
    
    app_name = 'test_app'
    
    urlpatterns = [
        path("home/", views.test, name='home'),
    ]
    

    faster/testapp/views.py

    from django.shortcuts import HttpResponse, reverse
    
    
    def test(request):
        # 如果没有路由分发,反向生成url只需要使用name属性即可
        # 如果有路由分发,反向生成url需要 'namespace:name' 这种格式
        url = reverse('test:home')
        print(url) # 输出 /test/home/
        return HttpResponse('test!')
    

1.3.2 路由分发的本质

  • include函数的源码:

    def include(arg, namespace=None):
        app_name = None
        if isinstance(arg, tuple):
            # Callable returning a namespace hint.
            try:
                urlconf_module, app_name = arg
            except ValueError:
                if namespace:
                    raise ImproperlyConfigured(
                        "Cannot override the namespace for a dynamic module that "
                        "provides a namespace."
                    )
                raise ImproperlyConfigured(
                    "Passing a %d-tuple to include() is not supported. Pass a "
                    "2-tuple containing the list of patterns and app_name, and "
                    "provide the namespace argument to include() instead." % len(arg)
                )
        else:
            # No namespace hint - use manually provided namespace.
            urlconf_module = arg
        if isinstance(urlconf_module, str):
            urlconf_module = import_module(urlconf_module)
        patterns = getattr(urlconf_module, "urlpatterns", urlconf_module)
        app_name = getattr(urlconf_module, "app_name", app_name)
        if namespace and not app_name:
            raise ImproperlyConfigured(
                "Specifying a namespace in include() without providing an app_name "
                "is not supported. Set the app_name attribute in the included "
                "module, or pass a 2-tuple containing the list of patterns and "
                "app_name instead.",
            )
        namespace = namespace or app_name
        # Make sure the patterns can be iterated through (without this, some
        # testcases will break).
        if isinstance(patterns, (list, tuple)):
            for url_pattern in patterns:
                pattern = getattr(url_pattern, "pattern", None)
                if isinstance(pattern, LocalePrefixPattern):
                    raise ImproperlyConfigured(
                        "Using i18n_patterns in an included URLconf is not allowed."
                    )
        return (urlconf_module, app_name, namespace)
    

    整个逻辑很简单,做了一些判断,关键是return,返回了一个含有三个元素的元组,分别是url配置信息的文件路径、应用名称、命名空间

  • 路由分发的方式一

    faster/faster/urls.py

    from django.contrib import admin
    from django.urls import path, include
    from testapp import urls
    
    urlpatterns = [
        path("admin/", admin.site.urls),
        #path('test/', include('testapp.urls', namespace='test'))
        path('test/', (urls, None, None)) # urls是python的模块,python中一切皆对象,所以模块也是对象
    ]
    

    faster/testapp/urls.py

    from django.urls import path
    
    from . import views
    
    app_name = 'test_app'
    
    urlpatterns = [
        path("home/", views.test, name='home'),
    ]
    

    faster/testapp/views.py

    from django.shortcuts import HttpResponse, reverse
    
    
    def test(request):
        return HttpResponse('test!')
    
  • 路由分发的方式二

    faster/faster/urls.py

    from django.contrib import admin
    from django.urls import path, include
    from testapp import views
    
    urlpatterns = [
        path("admin/", admin.site.urls),
        path('level1/', ([path('item1/', ([path('content/', views.content1), ], None, None)),
                          path('item2/', ([path('content/', views.content2), ], None, None))
                          ], None, None))
    ]
    

    faster/testapp/views.py

    from django.shortcuts import HttpResponse, reverse
    
    
    def content1(request):
        return HttpResponse('content1')
    
    
    def content2(request):
        return HttpResponse('content2')
    

    路由分发结果如下:

    http://127.0.0.1:5000/level1/

    -----------------------------------------item1/

    --------------------------------------------------content/

    -----------------------------------------item2/

    --------------------------------------------------content/

1.5 自动在app包中查找某个模块并执行

1.5.1 python中的包和模块

==包==---是一个包含_init_.py文件的文件夹

模块---就是一个后缀名为py的文件

--testapp # Python中的包
      --migrations
      --__init__.py 
      --admin.py   # 从这往下都是Python中的模块
      --apps.py
      --models.py
      --tests.py
      --views.py

Python中一切皆对象,包和模块也是对象。

1.5.2 django-admin源码浅析

大家在使用django-admin的时候

第一步是在每个app的admin.py下面将模型类注册到site中。

faster/test_app/apps.py

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


class TestappConfig(AppConfig):
    default_auto_field = "django.db.models.BigAutoField"
    name = "testapp"

    def ready(self):
        autodiscover_modules('test')

        

faster/test_app/test.py

def func():
    print('我被调用了')

func()

执行结果:

F:\.venvs\py3.10\.venv\Lib\site-packages\django\urls\conf.py changed, reloading.
我被调用了
Watching for file changes with StatReloader
Performing system checks...

System check identified no issues (0 silenced).

You have 18 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions.
Run 'python manage.py migrate' to apply them.
September 11, 2022 - 19:22:05
Django version 4.1.1, using settings 'faster.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CTRL-BREAK.

1.6 单例模式

  • 方式一:通过包的方式

    通过利用Python模块导入的特性:在Python中,如果已经导入过的文件再次被重新导入时候,python不会再重新解释一遍,而是选择从内存中直接将原来导入的值拿来用。

    a.py

    class Foo:
        def __init__(self, a=1):
            self.a = a
    
     
    foo = Foo() # foo就是一个单例
    
    # 单  一个
    # 例  对象
    

    b.py

    import a
    
    print(a.foo)  # <a.Foo object at 0x00000205C1787C40>
    
    print(a.foo)  # <a.Foo object at 0x00000205C1787C40>
    
  • 方式二:通过重写__new__方法的方式

    # 实例是通过类创建的,类创建实例要先调用类的__new__方法,然后再执行__init__方法
    
    class SingleTon:
    
        def __new__(cls, *args, **kwargs):
            if not hasattr(cls, '_instance'):
                cls._instance = super().__new__(cls, *args, **kwargs)
            return cls._instance
    
    
    s1 = SingleTon()
    s2 = SingleTon()
    
    print(s1)
    print(s2)
    

1.7 简述元类

几乎所有面向对象的语音中,都有类和对象的概念。

对象是由类创建出来的,类规范了对象的状态和方法。

但是你有考虑过类是由什么创建的吗?类都是由元类创建的,type是所有类的默认元类。

继承和实例化是两个概念。

同时需要注意以下以下几个特殊方法和内部函数:

  • _new_() 创建一个实例对象
  • _init_() 实例化一个实例对象
  • _call_() 实例() 会执行实例的类的 __call__方法
  • isinstance(obj, cls) obj是不是cls的实例对象
  • issubclass(cls1, cls2) cls1是不是cls2的子类

1.8 django中获取app名称和模型类

通过模型类的_meta属性获取到模型类所属的app名称和模型名称(小写字母)

models.UserInfo._meta.app_label  # app名称
models.UserInfo._meta.model_name  # 数据表名称,模型类转换成小写形式

1.9 方法和函数的区别

  • 函数

    def xxx():
    	pass 
    
    print(type(xxx))  #<class 'function'>
    
  • 方法

    class Foo:
        def test(self):
            pass
    
    
    f = Foo()
    
    print(type(f.test)) # <class 'method'>
    
  • 特殊的函数定义:

    class Foo:
        def test(self):
            pass
    
    print(type(Foo.test)) #<class 'function'>
    
  • 如何判断一个对象属于哪个类,类==实例化==得到对象,实例化(创造)关系与继承关系一定要分清楚,否则学不明白面向对象,概念不清晰更别提应用了,面向对象是那么的灵活。所以基础概念一定要牢固

    from types import FunctionType, MethodType
    
    
    def xxx():
        pass
    
    
    class Foo:
        def test(self):
            pass
    
    
    f = Foo()
    
    if __name__ == '__main__':
        print(isinstance(Foo.test, MethodType))  # False
        print(isinstance(xxx, FunctionType))  # True
        print(isinstance(f.test, FunctionType))  # False
    

1.10 生成器与yield

  • 生成器表达式

    a = (i for i in range(100))
    
    b = [i for i in range(100)]
    
    print(a)  # <generator object <genexpr> at 0x000001D2763004A0>
    
    print(type(a))  # <class 'generator'>
    
    print(type(b))  # <class 'list'>
    
    import sys
    
    print(sys.getsizeof(a))  # 104
    
    print(sys.getsizeof(b))  # 920
    

    从运行结果可以开出,生成器可以大量节省系统内存,并且生成器是特殊的迭代器,可以使用for循环遍历出里面的元素

    举个例子:

    小红和小绿都很喜欢吃面包,小红从工厂直接买回来100块,放在家里堆起来,小绿则是饿了的时候去商店买一块,小红就类似与列表,把所有的元素都放到内存中,小绿就类似于生成器,需要的时候才来取。

  • yield实现生成器

    def xxx():
        yield 1
    
    
    print(xxx())  # <generator object xxx at 0x000001F0EC9304A0>
    
    print(next(xxx()))  # 1
    
  • 生成器还有一些其他用法,如,send、next、throw、yield from、协程等,本组件开发暂时用不到,就不多说了。

1.11 反射

反射是静态面向对象语言具有的特性,比如Java就严重依赖反射。

Python同样具有反射的特性,只要使用内建方法中的getattr(obj, attr)

class Foo:
    # 类变量
    x = 123

    @classmethod
    def f1(cls):
        print('类方法')

    @staticmethod
    def f2():
        print('静态方法')

    def f3(self):
        print('实例方法')

    def __init__(self, name='foo'):
        # 实例变量
        self.name = name


foo = Foo()

getattr(foo, 'f1')()
getattr(foo, 'f2')()
getattr(foo, 'f3')()

print(getattr(Foo, 'x'))
print(getattr(foo, 'name'))
print(getattr(foo, 'x'))

除了getattr之后还有

  • setattr

    setattr(obj, attr, value)  等价于  obj.attr = value
    
  • hasattr

    hasattr(obj, attr)   返回True  or   False
    
  • delattr

    delattr(obj, attr)  删除obj的attr属性
    

1.12 装饰器

  • 语法糖写法

    import time
    
    
    def wrapper(func):
        print('装饰器执行的时机有点特殊')
        print(func.__name__)
    
        def inner(*args, **kwargs):
            print('start...')
            start_time = time.time()
            result = func(*args, **kwargs)
            print(f'end...total use{time.time() - start_time} s')
            return result
    
        inner.__name__ = func.__name__
        return inner
    
    
    @wrapper
    def func1():
        time.sleep(2)
        print('就是玩')
    
    
    @wrapper
    def func2():
        time.sleep(1)
        print('还得玩')
    
    
    func1()
    
    print(func1.__name__)
    
    func2()
    
    print(func2.__name__)
    
    • 关键点1:

      文件被执行的时候就会被调用。

    • 关键点2:

      装饰器会改变原函数的元信息

  • 非语法糖写法

    wrapper(func1)()
    # 与语法糖相同
    

1.13 组合查询Q对象

1.14 request.GET 对象

2 faster组件使用说明

首先需要注册app:

项目文件夹/settings.py

INSTALLED_APPS = [
    ###
    'fast',
]
TEMPLATES = [
    {
        "BACKEND": "django.template.backends.django.DjangoTemplates",
        "DIRS": [],
        "APP_DIRS": True,
        "OPTIONS": {
            "context_processors": [
                "django.template.context_processors.debug",
                "django.template.context_processors.request",
                "django.contrib.auth.context_processors.auth",
                "django.contrib.messages.context_processors.messages",
            ],
            'libraries': {  # Adding this section should work around the issue.
                'staticfiles': 'django.templatetags.static',
            },
        },
    },
]

在你的app中创建一个fast.py模块:

--testapp

----fast.py

所有的配置都将写在fast.py中

--testapp

​ ----models.py

class UserInfo(models.Model):
    """
    用户模型
    """
    user_name = models.CharField(verbose_name='用户名', max_length=32)
    password = models.CharField(verbose_name='密码', max_length=32)
    mobile = models.CharField(verbose_name='手机号', max_length=11)
    token = models.OneToOneField(verbose_name='token', to='UserToken', on_delete=models.SET_NULL, null=True, blank=True)
    depart = models.ForeignKey(verbose_name='部门', to='Depart', on_delete=models.SET_NULL, null=True, blank=True)

    def __str__(self):
        return self.user_name

2.1 入门示例

  • fast.py

    from fast.service.main import site, FastHandler, get_choice_text
    from . import models
    from django import forms
    
    
    class HandlerUserInfo(FastHandler):
        list_display = [FastHandler.display_checkbox, 'id', 'user_name', 'mobile', FastHandler.display_edit, FastHandler.display_delete]
    
        add_model_form_class = UserInfoModelForm
    
        has_add_btn = True
    
        per_page_count = 2
    
        order_list = ['-user_name']
    
        action_list = [FastHandler.action_multi_delete, ]
    
        search_list = ['user_name__contains']
        
    site.register(models.UserInfo, HandlerUserInfo)
    

.

2.2 列表功能-list_display

在继承FastHandler的类变量中添加list_diaplay可以定制需要显示的列:

除去常规字段,比如’id‘、'user_name'、’mobile‘

还可以配置特殊字段:

  • FastHandler.display_checkbox :

    image-20220916093417342

  • FastHandler.display_edit

    image-20220916093450209

  • FastHandler.display_delete

    image-20220916093514673

2.3 新增按钮-has_add_btn & add_model_form_class

  • has_add_btn 默认为True , 将其修改为False,界面不具备新增功能。

  • add_model_form_class,新增字段的form表单,可以自定义modelform

    class UserInfoModelForm(forms.ModelForm):
        class Meta:
            model = models.UserInfo
            fields = '__all__'
    
        def clean_user_name(self):
            user_name = self.cleaned_data['user_name']
            if user_name != 'kobe':
                raise forms.ValidationError('user_name 验证错误')
            return user_name
    

    自定义modelform,设置add_model_form_class = 类名即可,本实例中可以写成:add_model_form_class = UserInfoModelForm

2.4 按字段排序-order_list

  • order_list

    • ['id', ] 按id升序排
    • ['-id',] 按id降序排
    • ['id', '-user_name'] 按id升序排,user_name 降序排
    • ['c1','c2','c3',......] 按多个字段排

2.5 关键词搜索

  • search_list
    • ['user_name__contains'] 等价于sql中的like
    • ['user_name'] 需要精准匹配上
    • 其他django ORM filter语法

2.6 分页

  • per_page_count 必须为整型

    per_page_count = 1 每页显示1条

    per_page_count = 3 每页显示3条

    以此类推。。。。

2.7 批量操作

  • action_list = [FastHandler.action_multi_delete, ]

    目前只支持批量删除

    image-20220916094846740

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

django-faster-2.0.tar.gz (10.2 kB view hashes)

Uploaded Source

Built Distribution

django_faster-2.0-py3-none-any.whl (9.2 kB view hashes)

Uploaded Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page