• django初识


    web框架了解

        MVC
            Model       View       Controller
            数据库   模板文件    业务处理
        
        
        MTV
    
            Model    Template     View
            数据库   模板文件    业务处理

    django 

    1、django框架的安装

    pip3 install django

    2、Pycharm创建django 项目

    命令行:# django-admin startproject <工程名称 如s14day19_2> 

     3、目录结构解析

            s14day19_2
                - s14day19_2        # 对整个程序进行配置的目录
                    - init
                    - settings  # 配置文件:含模板、静态文件等路径配置
                    - url       # URL对应关系
                    - wsgi      # 遵循WSIG规范,uwsgi + nginx
                - manage.py     # 管理Django程序:
                                    - python manage.py 
                                    - python manage.py startapp xx
                                    - python manage.py makemigrations
                                    - python manage.py migrate
           - templates # 模板存放路径

    4、配置文件解析

    4.1settings.py

    # 模板配置

    TEMPLATES = [
        {
            'BACKEND': 'django.template.backends.django.DjangoTemplates',
            'DIRS': [os.path.join(BASE_DIR, 'templates')]

      .....
    # 静态文件路径配置。STATIFILES_DIRS = 元组
    STATICFILES_DIRS = (
        os.path.join(BASE_DIR,'static'),
    )
    """
    Django settings for s14day19_2 project.
    
    Generated by 'django-admin startproject' using Django 3.0.8.
    
    For more information on this file, see
    https://docs.djangoproject.com/en/3.0/topics/settings/
    
    For the full list of settings and their values, see
    https://docs.djangoproject.com/en/3.0/ref/settings/
    """
    
    import os
    
    # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
    BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    
    
    # Quick-start development settings - unsuitable for production
    # See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/
    
    # SECURITY WARNING: keep the secret key used in production secret!
    SECRET_KEY = 'o!n!^7e-u5x#+ziuagcro-gj-96l0_iy9+9z)apw@n%ku7+_3z'
    
    # SECURITY WARNING: don't run with debug turned on in production!
    DEBUG = True
    
    ALLOWED_HOSTS = []
    
    
    # Application definition
    
    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
    ]
    
    MIDDLEWARE = [
        'django.middleware.security.SecurityMiddleware',
        'django.contrib.sessions.middleware.SessionMiddleware',
        'django.middleware.common.CommonMiddleware',
        # 'django.middleware.csrf.CsrfViewMiddleware',
        'django.contrib.auth.middleware.AuthenticationMiddleware',
        'django.contrib.messages.middleware.MessageMiddleware',
        'django.middleware.clickjacking.XFrameOptionsMiddleware',
    ]
    
    ROOT_URLCONF = 's14day19_2.urls'
    
    TEMPLATES = [
        {
            'BACKEND': 'django.template.backends.django.DjangoTemplates',
            'DIRS': [os.path.join(BASE_DIR, 'templates')]
            ,
            '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',
                ],
            },
        },
    ]
    
    WSGI_APPLICATION = 's14day19_2.wsgi.application'
    
    
    # Database
    # https://docs.djangoproject.com/en/3.0/ref/settings/#databases
    
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.sqlite3',
            'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
        }
    }
    
    
    # Password validation
    # https://docs.djangoproject.com/en/3.0/ref/settings/#auth-password-validators
    
    AUTH_PASSWORD_VALIDATORS = [
        {
            'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
        },
        {
            'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
        },
        {
            'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
        },
        {
            'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
        },
    ]
    
    
    # Internationalization
    # https://docs.djangoproject.com/en/3.0/topics/i18n/
    
    LANGUAGE_CODE = 'en-us'
    
    TIME_ZONE = 'UTC'
    
    USE_I18N = True
    
    USE_L10N = True
    
    USE_TZ = True
    
    
    # Static files (CSS, JavaScript, Images)
    # https://docs.djangoproject.com/en/3.0/howto/static-files/
    
    STATIC_URL = '/static/'
    
    # 静态文件路径配置。STATIFILES_DIRS = 元组
    STATICFILES_DIRS = (
        os.path.join(BASE_DIR,'static'),
    )

    4.2 urls.py 配置请求访问url的对应处理逻辑

    如下为urls.py示例;from app01 import views 里面的app01 为具体的应用模块。

    app01模块通过命令行下 在项目根目录 执行命令# python manager.py startapp 【工程名称,如app01】创建

    from django.contrib import admin
    from django.urls import path
    from app01 import  views
    urlpatterns = [
        path('admin/', admin.site.urls),
        path(r'index', views.index),
        path(r'login', views.login),
    ]

    5、创建应用

    5.1 应用处理逻辑的创建

    cd 到django项目根目录,执行命令

    python manager.py startapp 【工程名称,如app01】

    应用目录生成文件如下

    5.2  应用.views 内定义具体的函数,来处理对应url的逻辑

    views.py示例如下; 负责对应url的http请求处理逻辑

    from django.shortcuts import render
    from django.shortcuts import redirect
    from django.shortcuts import HttpResponse
    
    # Create your views here.
    
    
    def index(request):
        return HttpResponse("Hello This is Index")
    
    def login(request):
        if request.method == "GET":
            return render(request, 'login.html')
        elif request.method == "POST":
            user = request.POST.get('user')
            pwd = request.POST.get('pwd')
            if user == 'zmd' and pwd == '123':
                return redirect('/index')
            else:
                return redirect('/login/')
        else:
            return redirect('/index')

     5.3模板

    django项目根目录内templates目录存放XXX.html 模板

    测试模板 

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <form action="/login/" method="POST">
            <p>
                <input type="text" name="user" placeholder="用户名">
            </p>
                 <p>
                <input type="password" name="pwd" placeholder="密码">
            </p>
            <p>
                <input type="submit" value="提交">
            </p>
        </form>
    </body>
    </html>
    login.html

    6、启动访问

     或者项目根目录下执行命令启动:

    python manage.py runserver 127.0.0.1:800

    详解知识点一:请求处理逻辑views

    FBV 方式:(F 代表函数;B代表django内部的base.py基础功能,V代表Views)

    1、获取post请求单条数据request.POST.get()

    def login(request):
        if request.method == "GET":
            return render(request, 'login.html')
        elif request.method == "POST":
            user = request.POST.get('user')
            pwd = request.POST.get('pwd')
            print('user:',user)
            if user == 'zmd' and pwd == '123':
                return redirect('/index')
            else:
                return redirect('/login/')
        else:
            return redirect('/index')

    2、获取多个数据例如前端checkbox的值--request.POST.getlist()

    返回列表

    def login(request):
        if request.method == "GET":
            return render(request, 'login.html')
        elif request.method == "POST":
            favor = request.POST.getlist('favor')
            print(favor)

    3、获取上传文件

    3.1前端form表单需添加enctype="multipart/form-data"

        <form action="/login/" method="POST" enctype="multipart/form-data">
            <p>
                <input type="file" name="file1">
            </p>
        </form>

    3.2 request获取文件request.FILES.get('前端表单文件标签name')

      获取文件对象:upload_file_obj = request.FILES.get('前端表单文件标签name')

        print(upload_file_obj) 会打印文件名,但本身他是文件对象,因为该对象内有__str__(self)方法,或者__repr__(self) 方法 ----->这里复习一下。

      获取对象文件名:文件对象.name

      文件二进制内容:文件对象.chunks()

    def login(request):
        if request.method == "GET":
            return render(request, 'login.html')
        elif request.method == "POST":
            upload_file_obj = request.FILES.get('file1')
            print('upload_file_obj:',upload_file_obj)
            print(upload_file_obj.name)
            upload_file_name = upload_file_obj.name
            f = open( upload_file_name, 'wb')
            for item in upload_file_obj.chunks():
                f.write(item)
            f.close()

    4、获取请求的其他信息

      request.environ  封装了所有用户请求信息

        获取客户端信息:request.environ['HTTP_USER_AGENT']
        获取Cookie:reqeust.COOKIES.get('username111')
        uri路径信息:request.path_info

       

        

      

     CBV方式:(C代表类Class;B代表django内部的base.py基础功能,V代表Views)

    1、views.py CBV模式 类的写法---继承django.views.View

    # CBV 模式
    from django.views import View
    
    class Home(View):
        # 继承 from django.views import View
        # 继承后可以定义的http请求方法有http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace'],详见View类
        def get(self,request):
            """定义路径对应的get请求方法"""
            print('Home GET')
            return render(request, 'home.html')
    
        def post(self,request):
            print('Home POST')
            return render(request, 'home.html')
    
        # Django 如何找到get post函数做对应url的处理呢?
        # 采用的是反射,hasattr,这些封装在dispatch函数中
        def dispatch(self, request, *args, **kwargs):
            # 可以重写父类的方法加入自定义的功能,此方法在get post 函数之前执行
            print('before in dispatch')
            # 重写父类的dispatch 方法,等于覆盖了父类方法,
            # 若需保留父类的方法能够执行,需要super 执行父类的该方法
            # 并且最终返回
            request_result = super(Home,self).dispatch(request, *args, **kwargs)
            # 处理完具体的GET POST请求
            print('after in dispatch')
            return request_result

    2、对应的urls.py 写法 :类名.as_view()

    from django.contrib import admin
    from django.urls import path
    from app01 import  views
    urlpatterns = [
        path('admin/', admin.site.urls),
        path(r'index', views.index),
        path(r'login/', views.login),
        # CBV
        path(r'home/',views.Home.as_view())
    ]

    3、访问效果

    before in dispatch
    Home GET
    after in dispatch
    [11/Jul/2020 13:22:39] "GET /home/ HTTP/1.1" 200 260
    before in dispatch
    Home POST
    after in dispatch
    [11/Jul/2020 13:22:48] "POST /home/ HTTP/1.1" 200 260

    4、dispatch特殊函数说明

    Django 如何找到get post函数做对应url的处理呢?
    原理采用的是反射,hasattr,这些封装在dispatch函数中;
    此方法在get post 函数之前执行,可以重写父类的dispatch方法加入自定义的功能
        # Django 如何找到get post函数做对应url的处理呢?
        # 采用的是反射,hasattr,这些封装在dispatch函数中
        def dispatch(self, request, *args, **kwargs):
            # 可以重写父类的方法加入自定义的功能,此方法在get post 函数之前执行
            print('before in dispatch')
            # 重写父类的dispatch 方法,等于覆盖了父类方法,
            # 若需保留父类的方法能够执行,需要super 执行父类的该方法
            # 并且最终返回
            request_result = super(Home,self).dispatch(request, *args, **kwargs)
            # 处理完具体的GET POST请求
            print('after in dispatch')
            return request_result

    服务端获取值:request的常用方法

      request.body  ---所有数据内容的原生值

    request.POST(request.body)

    request.FILES(request.body)

    request.GET

    request.XXX.getlist

    request.META

    request.method (值为POST,GET,PUT)

    request.path_info

    request.COOKIES

    request的所有方法

    [
     "COOKIES",
     "FILES",
     "GET",
     "META",
     "POST",
     "__class__",
     "__delattr__",
     "__dict__",
     "__dir__",
     "__doc__",
     "__eq__",
     "__format__",
     "__ge__",
     "__getattribute__",
     "__gt__",
     "__hash__",
     "__init__",
     "__init_subclass__",
     "__iter__",
     "__le__",
     "__lt__",
     "__module__",
     "__ne__",
     "__new__",
     "__reduce__",
     "__reduce_ex__",
     "__repr__",
     "__setattr__",
     "__sizeof__",
     "__str__",
     "__subclasshook__",
     "__weakref__",
     "_current_scheme_host",
     "_encoding",
     "_get_full_path",
     "_get_post",
     "_get_raw_host",
     "_get_scheme",
     "_initialize_handlers",
     "_load_post_and_files",
     "_mark_post_parse_error",
     "_messages",
     "_read_started",
     "_set_content_type_params",
     "_set_post",
     "_stream",
     "_upload_handlers",
     "body",
     "build_absolute_uri",
     "close",
     "content_params",
     "content_type",
     "encoding",
     "environ",
     "get_full_path",
     "get_full_path_info",
     "get_host",
     "get_port",
     "get_raw_uri",
     "get_signed_cookie",
     "headers",
     "is_ajax",
     "is_secure",
     "method",
     "parse_file_upload",
     "path",
     "path_info",
     "read",
     "readline",
     "readlines",
     "resolver_match",
     "scheme",
     "session",
     "upload_handlers",
     "user"
    ]

     服务端返回消息:

      return HttpResponse('str...')

      return render(request,'xxxx.html', {'key':value,xxx})

      return redirect('/xxx')

      response = HttpResponse(同上)/render(同上)/rediret(同上)

      response['name'] = 'value'    -->设置响应头

      response.set_cookie('key','value') --->设置cookie

      return response

      

    详解知识点二:模板语言

    {{ 变量名 }} 
    循环语句:
    {% for xx in <views字典传过来的key> %}
      ...
    {% endfor%}
    注意:%和{}之间不允许有空格

    模板语言内部变量:
      {{ forloop.counter }} 每循环一次该值自动+1
      {{ forloop.first }} True/False 是否第一次循环
      {{ forloop.last }} True/False 是否最后一次循环
      {{ forloop.revcounter }} 倒序计数器
      {{ forloop.revcounter0 }} 倒序计数器结尾为0
      {{ forloop.parentloop}} 父循环信息 (嵌套循环时)


    1、请求处理逻辑get post ....渲染的时候传递字典

    def func(request):
        return render(request, "index.html", {'current_user': "alex"})

    对应的index.html 

    <div>{{current_user}}</div>

    2、请求处理逻辑get post ....渲染的时候传递列表

    USER_LIST = [
        {'name': 'zmd', 'gender': 1, 'age': '22'},
        {'name': 'qjj', 'gender': 0, 'age': '20'},
        {'name': 'zmc', 'gender': 0, 'age': '2'},
    ]
    
    def index(request):
        return render(request,'index.html',{'user_list': USER_LIST})

    对应模板示例index.html

        <ul>
            {% for user in user_list %}
                <li>{{ user.name }} gender:{{ user.gender }} age: {{ user.age }}</li>
            {% endfor %}
        </ul>

    3、请求处理逻辑get post... 渲染模板时传递字典

    views 传递字典

    USER_DICT = {
        1: {'name': 'zmd', 'gender': 1, 'age': '22'},
        2: {'name': 'qjj', 'gender': 0, 'age': '20'},
        3: {'name': 'zmc', 'gender': 0, 'age': '2'},
    }
    
    def index(request):
        return render(request, 'index.html', {'user_dict': USER_DICT})

    对应html 字典可以直接使用python字典的对应方法,但是在html语法中不需要加()

    {% for key, value in user_dict.items %}
        <li>用户{{ key }} 姓名:{{ value.name }} gender:{{ value.gender }} 年龄:{{ value.age }} </li>
    {% endfor %}

     4. 模板内置变量{{ forloop.counter }}

      示例:此序号,for循环的次数计数器,展示第几个数据

    {% for host in hosts %}
        <li> 序号: {{ forloop.counter }} 主机名:{{ host.hostname }} 主机IP:{{ host.ip }} 端口{{ host.port }} 业务线ID:{{ host.b_id }}</li>
    {% endfor %}  

      示例效果

       

     

     

     

    详解知识点三:urls.py 路由系统(应用场景:页面跳转)

    路由系统,URL
        1、url(r'^index/$', views.index),    
           url(r'^home/$', views.Home.as_view()),
        2、url(r'^detail-(d+).html', views.detail),  
        3、url(r'^detail-(?P<nid>d+)-(?P<uid>d+).html', views.detail)
    注意:
       $为匹配的终止符,如果不写:有前缀相同的url,并且短的url在上,则后面的url被截胡,永远无法匹配到。
       例如:
       url(r'^index'),
       url(r'^index_add') 这条就无法匹配到了

    1、默认的问号传参,(http://xxxx/detail/?nid=xxxxxxxx),后台获取值request.GET.get('query name')可以以此做详情页面跳转

    这种默认传参无需urls.py路由做多余的配置。无论是get 还是post等等...后台直接request.method.get('query name') 或者request.method.getlist('query name') 即可获得。

    urls.py 无特殊配置

    from django.contrib import admin
    from django.urls import path
    from app01 import views
    
    urlpatterns = [
        path('admin/', admin.site.urls),
        path(r'index', views.index),
        path(r'detail/',views.Detail.as_view())
    ]

    views.py

    
    
    from django.shortcuts import render
    from django.shortcuts import redirect
    USER_DICT = {
    1: {'name': 'zmd', 'gender': 1, 'age': '22'},
    2: {'name': 'qjj', 'gender': 0, 'age': '20'},
    3: {'name': 'zmc', 'gender': 0, 'age': '2'},
    }
    def index(request):
    return render(request, 'index.html', {'user_dict': USER_DICT})

    class
    Detail(View): def get(self,request): userid = request.GET.get('nid') user = USER_DICT.get(userid) return render(request,'detail.html', {'user': user})

    index.html 改为a标签,点击跳转

        <ul>
            {% for key, user in user_dict.items %}
                <li><a href="/detail/?nid={{ key }}" target="_blank">{{ user.name }}</a></li>
            {% endfor %}
        </ul>

    detail.html

        <h1>详细信息</h1>
    
        <h6>用户名:{{ user.name }}</h6>
        <h6>性别:{{ user.gender }}</h6>
        <h6>年龄:{{ user.age }}</h6>

    2、url 正则分组匹配,

    2.1 动态url分组匹配处理;对应的views里面的获取分组的值需要有和分组数量相等的形参

    urls.py

    需要用django.conf.urls import url来匹配

    本例urls.py 里面(d+) 为第一个分组

    from django.conf.urls import url
    from app01 import views
    
    urlpatterns = [
        path('admin/', admin.site.urls),
        path(r'index', views.index),
        url(r'detail-(d+).html', views.Detail.as_view()),
    ]

    views.py 需要用一个参数接收请求参数url中的分组,比如使用nid,nid只是代表获取url中分组(即url中的小括号())顺序而已;

    class Detail(View):
    
        # def get(self,request):
        #     userid = request.GET.get('nid')
        #     user = USER_DICT.get(userid)
        #     return render(request,'detail.html', {'user': user})
    
        # url正则匹配url,的第一个正则匹配值使用nid接收,nid任意起名
        def get(self, request, nid):
            user = USER_DICT.get(nid)
            return render(request, 'detail.html', {'user': user})

    渲染的detail.html内容不做任何变动。只需要把index.html中<a></a>标签的跳转url 即: href="xxxx"更正匹配对应的urls里面的正则路径即可

    index.html

        <ul>
            {% for key, user in user_dict.items %}<li><a href="/detail-{{ key }}.html" target="_blank">{{ user.name }}</a></li>
            {% endfor %}
        </ul>

     2.2 url 正则匹配对分组命名,views里面获取url中的分组时,指定分组命名获取,无需按照顺序。

    url分组语法:(?P<变量名>xxxx正则表达式xxxx)

    urls.py 本示例:分组两个分别命名为uid和nid

    from django.conf.urls import url
    
    urlpatterns = [
        path('admin/', admin.site.urls),
        url(r'detail2-(?P<uid>d+)-(?P<nid>d+).html', views.Detail2.as_view()),
    ]

    view.py 示例指定分组变量名获取对应url对应的值,形参名要和url的分组名一致

    # CBV 模式
    from django.views import View
    
    class Detail2(View):
        def get(self,request, nid, uid):
            group_test_str = "uid=%s
     nid=%s" % (uid, nid)
            return HttpResponse(group_test_str)

     2.3 分组数量位置的场景。views.py中使用 *args **kwargs接收

    注意:url 正则分组同时有命名分组和非命名分组时,只可以获取到命名分组,也就是只有**kwargs能获取到值

    获取未知数量的命名分组:urls.py

    from django.contrib import admin
    from django.urls import path
    from app01 import views
    from django.conf.urls import url
    
    urlpatterns = [
        path('admin/', admin.site.urls),
        url(r'detail3-(?P<uid>d+)-(?P<nid>d+)-(?P<iDontKonwID>d+).html', views.Detail3.as_view()),
    ]

    views.py

    from django.views import View
    
    class Detail3(View):
        def get(self,request, *args, **kwargs):
            print(args)
            print(kwargs)
            all_args = str(args) + str(kwargs)
            return HttpResponse(all_args)

    示例请求:http://127.0.0.1:8000/detail3-3-8-888.html

    获取到分组值:(){'uid': '3', 'nid': '8', 'iDontKonwID': '888'}

    正则url阶段性总结:

    方式1、

    url(r'^detail-(d+)-(d+).html', views.detail),
    def func(request, nid, uid):
        pass
    def func(request, *args):
         args = (2,9)

    方式2、

    url(r'^detail-(?P<nid>d+)-(?P<uid>d+).html', views.detail)
    def func(request, nid, uid):
        pass
    或者
    def funct(request, **kwargs):
         kwargs = {'nid': 1, 'uid': 3}

    推荐采用方式二哦

    3、 url里面的name:对URL路由关系进行命名,(以后可以根据此名称生成自己想要的URL)

    等于将url命名:可以直接在views.py 和html模板中直接用别名代替URI,用起来相对比较方便

    3.1 views.py使用url别名示例:

    url(r'detail-(d+).html', views.Detail.as_view(), name='detail-test'),  该url别名命名为detail-test
    url(r'detail2-(?P<uid>d+)-(?P<nid>d+).html', views.Detail2.as_view()), 在Detail2的视图中跳转时指定url别名跳转
    如下为Detail2 示例
    注意:使用的别名的url中有几个分组,在使用别名过程中要对分组变量传值,如下的nid便是对如上的(d+)分组赋值,用来生成url
    class Detail2(View):
        def get(self,request, nid, uid):
            group_test_str = "uid=%s
     nid=%s" % (uid, nid)
            # return HttpResponse(group_test_str)
            return redirect('detail-test', nid)

    这样访问效果为Detail2 视图,跳转到Detail视图

    3.2 模板语言使用url别名示例: {% url "url的别名" 分组传值变量  %}"

    urls.py 中有几个分组,在使用url别名时要对分组变量赋值

    from django.contrib import admin
    from django.urls import path
    from app01 import views
    from django.conf.urls import url
    
    urlpatterns = [
        path('admin/', admin.site.urls),
        path(r'index', views.index),
    
        # CBV
    
        url(r'detail-(d+).html', views.Detail.as_view(), name='detail-test'),
    ]

      views.py 渲染的index.html文件中使用,

    def index(request):
        return render(request, 'index.html', {'user_dict': USER_DICT})

    index.html中使用  {% url "url别名" [分组变量传值 ... ... ] %}

    <li><a href="{% url "detail-test"  key  %}" target="_blank">{{ user.name }}</a></li>

    3.3 urls.py中 的url有正则分组时,html模板中传值可以使用 分组名=xxx 

    urls.py

        url(r'detail3-(?P<a>[a-z]+)--(?P<uid>d+)-(?P<nid>d+)-(?P<iDontKonwID>d+).html', views.Detail3.as_view(), name='detail3'),

    html文件

    <a href="{% url "detail3"  a="ccc" uid=1 nid=2 iDontKonwID=3  %}" target="_blank">{{ user.name }}</a>

    模板中取当前url路径 {% url request.path_info  %}

    4、 reverse() 通过uri 别名反向解析URI,如有分组别名使用args=(,..)元组或者kwargs={}字典 来传值

    若url没有正则分组,则直接reverse('url别名') 即可

    views.py

    from django.urls import reverse
    detail_url = reverse('detail-test', args=(2, ))

    对应的urls.py 里面的url别名:

    urlpatterns = [
        path('admin/', admin.site.urls),
        path(r'index', views.index),
        url(r'detail-(d+).html', views.Detail.as_view(), name='detail-test'),
    ]

     对于urls.py命名url内有正则分组命名views.py使用kwargs传值

    urls.py

    urlpatterns = [
        path('admin/', admin.site.urls),
        path(r'index', views.index),
     
        url(r'detail3-(?P<a>[a-z]+)--(?P<uid>d+)-(?P<nid>d+)-(?P<iDontKonwID>d+).html', views.Detail3.as_view(), name='detail3'),
    ]

    views.py

    def index(request):
        from django.urls import reverse
        detail_url = reverse('detail-test', args=(2, ))
        print(detail_url)
        # detail3_url = reverse("detail3", args=('aaa', 2, 3, 4))
        detail3_url = reverse("detail3", kwargs={'a':'bbb','uid':1, 'nid': 2, 'iDontKonwID':3})

     对应模板中使用 {% url "url别名"  分组名=值 %}

    <a href="{% url "detail3"  a="ccc" uid=1 nid=2 iDontKonwID=3  %}" target="_blank">{{ user.name }}</a>

       注: target="_blank" 在新标签页打开

    5、多级路由

            project/urls.py
            from django.conf.urls import url,include
                from django.contrib import admin
    
                urlpatterns = [
                    url(r'^cmdb/', include("app01.urls")),
                    url(r'^monitor/', include("app02.urls")),
                ]
                
            app01/urls.py
                from django.conf.urls import url,include
                from django.contrib import admin
                from app01 import views
    
                urlpatterns = [
                    url(r'^login/', views.login),
                ]
                
            app02/urls.py
                from django.conf.urls import url,include
                from django.contrib import admin
                from app02 import views
    
                urlpatterns = [
                    url(r'^login/', views.login),
                ]

     访问的时候,以cmdb/开头的都由app01下面的urls.py处理分发。例如:http://127.0.0.1:8000/cmdb/index

     6、命名空间

     定义带命名空间的url之后,使用namespace + name生成URL时候,应该如下:

      • views.py 里面:v = reverse('namespace名称:name名称', args=(url变量传值,..), kwargs={'pk':11}) 
      • 或者v = reverse('app_name名称:name名称', args=(url变量传值,..), kwargs={'pk':11}) 
      • html模板里面:{% url 'app01:detail' pk=12 pp=99 %}

     示例:project.urls.py

    urlpatterns = [
        path('admin/', admin.site.urls),
        url(r'cmdb/', include('app01.urls', namespace='hehe')),
    ]

    app01.urls.py 应用路径要配置上app_name='自定义应用名称'

    url(r'detail-(d+).html', views.Detail.as_view(), name='detail-test'),

    app01.views.py  reverse('namespace名称:name名称', args=(url变量传值,..), kwargs={'pk':11}) ;name的url分组未命名,通过args=(,)传值;命名通过kwargs={}传值

    reverse('hehe:detail-test', args=(nid, ))
    reverse('app01:detail-test', args=(nid, ))

     url分组命名传值

    # app01.urls.py
    url(r'detail-(?P<nid>d+).html', views.Detail.as_view(), name='detail-test'),
    
    #app01.views.py
    reverse('hehe:detail-test', kwargs={'nid': nid, })

    详解知识点四:models.py 数据库ORM框架

    功能:code first  不直接写数据库的sql语句,通过代码创建

      django这里通过类创建:继承modules 模块中的Model类

    1、基础配置(注册要连接数据库的app;配置数据库引擎)

     项目的settings.py 里面配置要找的所有modules.py

    1.1 注册要生成数据库的app

    主项目下 settings.py 配置要注册数据库连接的所有app;除了自己新建的app01 其余全部是django框架自己所要用到的,勿删!

    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'app01',
    ]

    1.2 配置数据库使用的引擎

    主项目下 settings.py 内的 DATABASES变量;默认采用的是本地的sqlite3

    sqlite3

    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.sqlite3',
            'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
        }
    }

    Mysql在此配置即可

    # https://docs.djangoproject.com/en/3.0/ref/settings/#databases
    DATABASES = {
        'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME':'dbname',
        'USER': 'root',
        'PASSWORD': 'xxx',
        'HOST': '',
        'PORT': '',
        }
    }
    # 由于Django内部连接MySQL时使用的是MySQLdb模块,而python3中还无此模块,所以需要使用pymysql来代替
      
    # 如下设置放置的与project同名的配置的 __init__.py文件中
      
    import pymysql
    pymysql.version_info = (1, 3, 13, "final", 0)
    pymysql.install_as_MySQLdb() 

    注意:如果使用mysql 可能报错django.core.exceptions.ImproperlyConfigured: mysqlclient 1.3.13 or newer is required; you have 0.9.3.

    解决方案参考:

    https://yuntianti.com/posts/fix-django3-mysqlclient-import-error/

    https://blog.csdn.net/weixin_45476498/article/details/100098297

    2、设计app用的数据库表 models.py

        app01 应用目录下 models.py

    from django.db import models
    
    # Create your models here.
    
    # app01_userinfo
    class UserInfo(models.Model):
        # id列,自增,主键
        # 用户名列,字符串类型,指定长度
        username = models.CharField(max_length=32)
        password = models.CharField(max_length=64)

    3、执行命令生成数据库(根据类自动创建数据表)

      项目根目录下执行命令生成数据库同步脚本

      python manage.py makemigrations 

      生成数据表

      python manage.py migrate

    4、数据库表常用字段类型一览

    from django.db import models
    
        password = models.CharField(max_length=64)
        models.BigIntegerField()
        models.IntegerField()
        models.EmailField()
        models.IPAddressField()
        models.DateField()
        models.DateTimeField()
        models.FloatField()
        models.TimeField()
      models.UrlField()
      models.AutoField(PrimaryKey=True) # 用来自定义自增列
    #等等....除了主要的int CharField DateTime...等数据库默认的以外都是django内部给admin用的
    AutoField(Field)
            - int自增列,必须填入参数 primary_key=True
    
        BigAutoField(AutoField)
            - bigint自增列,必须填入参数 primary_key=True
    
            注:当model中如果没有自增列,则自动会创建一个列名为id的列
            from django.db import models
    
            class UserInfo(models.Model):
                # 自动创建一个列名为id的且为自增的整数列
                username = models.CharField(max_length=32)
    
            class Group(models.Model):
                # 自定义自增列
                nid = models.AutoField(primary_key=True)
                name = models.CharField(max_length=32)
    
        SmallIntegerField(IntegerField):
            - 小整数 -32768 ~ 32767
    
        PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
            - 正小整数 0 ~ 32767
        IntegerField(Field)
            - 整数列(有符号的) -2147483648 ~ 2147483647
    
        PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
            - 正整数 0 ~ 2147483647
    
        BigIntegerField(IntegerField):
            - 长整型(有符号的) -9223372036854775808 ~ 9223372036854775807
    
        自定义无符号整数字段
    
            class UnsignedIntegerField(models.IntegerField):
                def db_type(self, connection):
                    return 'integer UNSIGNED'
    
            PS: 返回值为字段在数据库中的属性,Django字段默认的值为:
                'AutoField': 'integer AUTO_INCREMENT',
                'BigAutoField': 'bigint AUTO_INCREMENT',
                'BinaryField': 'longblob',
                'BooleanField': 'bool',
                'CharField': 'varchar(%(max_length)s)',
                'CommaSeparatedIntegerField': 'varchar(%(max_length)s)',
                'DateField': 'date',
                'DateTimeField': 'datetime',
                'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)',
                'DurationField': 'bigint',
                'FileField': 'varchar(%(max_length)s)',
                'FilePathField': 'varchar(%(max_length)s)',
                'FloatField': 'double precision',
                'IntegerField': 'integer',
                'BigIntegerField': 'bigint',
                'IPAddressField': 'char(15)',
                'GenericIPAddressField': 'char(39)',
                'NullBooleanField': 'bool',
                'OneToOneField': 'integer',
                'PositiveIntegerField': 'integer UNSIGNED',
                'PositiveSmallIntegerField': 'smallint UNSIGNED',
                'SlugField': 'varchar(%(max_length)s)',
                'SmallIntegerField': 'smallint',
                'TextField': 'longtext',
                'TimeField': 'time',
                'UUIDField': 'char(32)',
    
        BooleanField(Field)
            - 布尔值类型
    
        NullBooleanField(Field):
            - 可以为空的布尔值
    
        CharField(Field)
            - 字符类型
            - 必须提供max_length参数, max_length表示字符长度
    
        TextField(Field)
            - 文本类型
    
        EmailField(CharField):
            - 字符串类型,Django Admin以及ModelForm中提供验证机制
    
        GenericIPAddressField(Field)
            - 字符串类型,Django Admin以及ModelForm中提供验证 Ipv4和Ipv6
            - 参数:
                protocol,用于指定Ipv4或Ipv6, 'both',"ipv4","ipv6"
                unpack_ipv4, 如果指定为True,则输入::ffff:192.0.2.1时候,可解析为192.0.2.1,开启刺功能,需要protocol="both"
    
        URLField(CharField)
            - 字符串类型,Django Admin以及ModelForm中提供验证 URL
    
        SlugField(CharField)
            - 字符串类型,Django Admin以及ModelForm中提供验证支持 字母、数字、下划线、连接符(减号)
    
        CommaSeparatedIntegerField(CharField)
            - 字符串类型,格式必须为逗号分割的数字
    
        UUIDField(Field)
            - 字符串类型,Django Admin以及ModelForm中提供对UUID格式的验证
    
        FilePathField(Field)
            - 字符串,Django Admin以及ModelForm中提供读取文件夹下文件的功能
            - 参数:
                    path,                      文件夹路径
                    match=None,                正则匹配
                    recursive=False,           递归下面的文件夹
                    allow_files=True,          允许文件
                    allow_folders=False,       允许文件夹
    
        FileField(Field)
            - 字符串,路径保存在数据库,文件上传到指定目录
            - 参数:
                upload_to = ""      上传文件的保存路径
                storage = None      存储组件,默认django.core.files.storage.FileSystemStorage
    
        ImageField(FileField)
            - 字符串,路径保存在数据库,文件上传到指定目录
            - 参数:
                upload_to = ""      上传文件的保存路径
                storage = None      存储组件,默认django.core.files.storage.FileSystemStorage
                width_field=None,   上传图片的高度保存的数据库字段名(字符串)
                height_field=None   上传图片的宽度保存的数据库字段名(字符串)
    
        DateTimeField(DateField)
            - 日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]
    
        DateField(DateTimeCheckMixin, Field)
            - 日期格式      YYYY-MM-DD
    
        TimeField(DateTimeCheckMixin, Field)
            - 时间格式      HH:MM[:ss[.uuuuuu]]
    
        DurationField(Field)
            - 长整数,时间间隔,数据库中按照bigint存储,ORM中获取的值为datetime.timedelta类型
    
        FloatField(Field)
            - 浮点型
    
        DecimalField(Field)
            - 10进制小数
            - 参数:
                max_digits,小数总长度
                decimal_places,小数位长度
    
        BinaryField(Field)
            - 二进制类型
    字段
    更多字段....
    
    
    
    

    字段约束:

        字段的参数:
            null               -> 字段是否可以为空:True/False
            default            -> 默认值 :
            primary_key        -> 主键 :True/False
            db_column          -> 字段列名 : String
            db_index           -> 索引 : True/False
            unique               -> 唯一索引 :True/False
            unique_for_date    -> 
            unique_for_month
            unique_for_year
            auto_now           -> 创建时,自动生成时间
            auto_now_add       -> 更新时,自动更新为当前时间 : 触发条件 查询结果.first() 赋值给某一个对象 ,对象.字段名=新值;对象.save() 才会更新,否则不变。
                      不支持update()
         choices      -> 从已有选项中选择,赋值为一个嵌套的元组,元组内的子元组为具体选项
    on_delete
    =None, # 删除关联表中的数据时,当前表与其关联的field的行为 on_delete=models.CASCADE, # 删除关联数据,与之关联也删除 on_delete=models.DO_NOTHING, # 删除关联数据,什么也不做 on_delete=models.PROTECT, # 删除关联数据,引发错误ProtectedError # models.ForeignKey('关联表', on_delete=models.SET_NULL, blank=True, null=True) on_delete=models.SET_NULL, # 删除关联数据,与之关联的值设置为null(前提FK字段需要设置为可空,一对一同理) # models.ForeignKey('关联表', on_delete=models.SET_DEFAULT, default='默认值') on_delete=models.SET_DEFAULT, # 删除关联数据,与之关联的值设置为默认值(前提FK字段需要设置默认值,一对一同理) on_delete=models.SET, # 删除关联数据,

    4.1 修改表结构

      4.1.1 修改原有字段的约束:直接在应用models.py原有字段内修改,然后项目根目录重新执行python manager.py makemigrations; python manager.py migrate

      4.1.2.增加字段:在应用的models.py 对应的表结构类中增加,若增加字段前有数据,在执行python manager.py makemigrations 时;由于字段默认不允许为空会提示对已有数据如何设置。

        2.1) Provide a one-off default now (will be set on all existing rows with a null value for this column) 马上对已有数据设置新字段默认值
        2.2) Quit, and let me add a default in models.py   返回修改models.py设置字段默认值,例如设置新增字段允许为空:none=True.

      4.1.3.删除字段:直接删除,然后执行python manager.py makemigrations ; python manager.py migrate 即可删除。有数据的全部丢失

    4.2 特殊字段约束

            auto_now           -> 创建时,自动生成时间
            auto_now_add       -> 更新时,自动更新为当前时间 : 触发条件 查询结果.first() 赋值给某一个对象 ,对象.字段名=新值;对象.save() 才会更新,否则不变。
                      不支持update(fieldname='newValue')
         choices      -> 从已有选项中选择,赋值为一个嵌套的元组,元组内的子元组为具体选项

     choices 使用示例:本例user_type_choice 变量实际则没有写入到数据库,而是在内存中存放

    # app01_userinfo
    class UserInfo(models.Model):
        # id列,自增,主键
        # 用户名列,字符串类型,指定长度
        username = models.CharField(max_length=32)
        password = models.CharField(max_length=64)
    
        user_type_choices = (
            (1, '超级用户'),
            (2, '普通用户'),
            (3, '只读用户'),
        )
        user_type_id = models.IntegerField(choices=user_type_choices, default=3)

        说明:文字注释为django admin 后台管理端在管理对应的表数据的时候展示用。如下图

        

        blank=True/False    在django admin中是否可以为空

        verbose_name="xxx"     在django admin中显示的中文名称

        editable=True/False    在django admin是否可以被编辑,字段写上这个=False,admin管理时不显示该列

         error_messages     错误提示

         help_text       django admin中的提示

         validators        django form ,自定义错误信息

    4.3 表设计:外键关联

      示例:models.ForeignKey("UserGroup", to_field='gid', on_delete=models.CASCADE, null=True)

      注释:"UserGroup"           关联的表名,

         to_field='gid'          具体关联的列,

           on_delete=models.CASCADE,  当被关联的表中的字段删除时,本表字段处理动作设置

         null=True            是否可以为空

      注意:on_delete=models.CASCADE/models.SET_DEFAULT 需要本字段有对应的默认设置。例如是否允许为空。default值等......

      外键数据的查询:

      查询具体数据的外键值:外面在外表中对应的主键值---> 查询结果数据对象.外键字段名_id

      例如:
      models.py 中 userinfo表中的user_group字段,外键指向usergroup表中的gid字段
    class UserGroup(models.Model):
        gid = models.AutoField(primary_key=True)
        caption = models.CharField(max_length=32, unique=True)
        ctime = models.DateTimeField(auto_now_add=True, null=True)
        uptime = models.DateTimeField(auto_now=True, null=True)
    
    class UserInfo(models.Model):
        # id列,自增,主键
        # 用户名列,字符串类型,指定长度
        username = models.CharField(max_length=32, error_messages={'required': '必填项目必填项目'}, help_text='用户名')
        password = models.CharField(max_length=64)
    
        user_type_choices = (
            (1, '超级用户'),
            (2, '普通用户'),
            (3, '只读用户'),
        )
        user_type_id = models.IntegerField(choices=user_type_choices, default=3)
        user_group = models.ForeignKey("UserGroup", to_field='gid', on_delete=models.CASCADE, null=True)
    views.py中查询语句获取外键的主键值
    search_resu = models.UserInfo.objects.filter(username=username).first()
    print("%s 的用户组ID:%s" % (username, search_resu.user_group_id))

      views.py 中查询语句获取外键的表对应数据的其他字段:通过点 外键字段名 点 外键表有的字段即可。

      跨表查询举例:本表单条数据.外键字段名.外表字段名

    search_resu = models.UserInfo.objects.filter(username=username).first()
                print("%s 的用户组名:%s" % (username, search_resu.user_group.caption))
    
    #zmd2 的用户组名:运维
    #数据 为:
    #+-----+---------+----------------------------+----------------------------+
    #| gid | caption | ctime                      | uptime                     |
    #+-----+---------+----------------------------+----------------------------+
    #|   3 | 运维    | 2020-07-13 11:41:33.162318 | 2020-07-13 11:41:33.162318 |
    #+-----+---------+----------------------------+----------------------------+

     

        

    5、增删改查操作

    5.1 创建数据

    方式一:自定义数据库表类.objects.create(字段1='值1', 字段二='值2', .........) 直接写入到数据库中。

      示例views.py中创建新数据

    from app01 import models
    
    class OrmStudy(View):
        def get(self,request, action, username, pwd):
            if action == "create":
                create_resu = models.UserInfo.objects.create(username=username, password=pwd)
            # new_data = {'username': username, 'password': pwd}
            # create_resu = models.UserInfo.objects.create(**new_data) #这种写法一样
           .....

       

    方式二:

        1.先依照自定义表结构生成数据对象

          data1 = 自定义数据库表类(字段1='值1', 字段二='值2', .........)

        2.调用数据对象的save()方法提交到数据库

          data1.save()

    示例

    from app01 import models
    
    class OrmStudy(View):
        def get(self,request, action, username, pwd):
                data1 = models.UserInfo(username=username, password=pwd)
                data1.save()
      #后面省略....

       5.1.1  一对多外键创建数据

      示例:UserInfo 中的usergroup 字段外键关联UserGroup表中的gid字段,

         UserInfo 创建数据有两种方式:

                      1. user_group=UserGroup对象,例如usergroup=models.UserGroup.objects.filter(gid=xxx).first()

                      2.user_group_id=xxx (推荐用这种,避免重复向数据库查询)

         代码示例:

    class OrmStudy(View):
        def get(self,request, action, username, group_id):
            if action == "create":
                data1 = models.UserInfo(username=username, user_group_id=group_id)
                data1.save()
                #....省略return........

       5.1.2 多对多创建数据

       方式一:自定义关系表

    例:HostToApp表自己写,两个字段分别外键到要关联的表

    from django.db import models
    
    
    # Create your models here.
    class Business(models.Model):
        bid = models.AutoField(primary_key=True)
        business_name = models.CharField(max_length=128, null=False)
        code = models.CharField(max_length=32, null=True)
    
    
    class Host(models.Model):
        nid = models.AutoField(primary_key=True)
        hostname = models.CharField(max_length=32, db_index=True)
        ip = models.GenericIPAddressField(protocol="ipv4", db_index=True)
        port = models.IntegerField()
        b = models.ForeignKey(to="Business", to_field='bid', null=True, on_delete=models.SET_NULL)
    
    
    class Application(models.Model):
        name = models.CharField(max_length=32)
    
    
    class HostToApp(models.Model):
        hobj = models.ForeignKey(to='Host', to_field='nid',null=True, on_delete=models.SET_NULL)
        aobj = models.ForeignKey(to='Application', to_field='id', null=True, on_delete=models.SET_NULL)

      方式二:自动创建关系表---models.ManyToManyField("要关联的表"),自动关联主键

      第三张表名:

      第三张表字段:只有id,和关联表主键字段生成

    #方式二:自动创建关系表
    
    
    class Host(models.Model):
        nid = models.AutoField(primary_key=True)
        hostname = models.CharField(max_length=32, db_index=True)
        ip = models.GenericIPAddressField(protocol="ipv4", db_index=True)
        port = models.IntegerField()
        b = models.ForeignKey(to="Business", to_field='id')
        # db_index=True 表示创建索引
    
    
    class Application(models.Model):
        name = models.CharField(max_length=32)
        r = models.ManyToManyField("Host") #生成第三张表,非本表字段
        # 第三张表只有三列(id,application_id,host_id) 表名字为application_r
    
    
    #无法直接对第三张表进行操作,需要通过第二张表的某条数据对象.第三张表名.操作
    
    obj = Application.objects.get(id=1)
    #获取某条数据
    obj.name
    
    # 第三张表操作
    obj.r.add(1)
    #添加第三张表对应关系
    Application_id = 1
    host_id = 1
    obj.r.add(2)
    #添加第三张表对应关系
    Application_id = 1
    host_id = 2
    obj.r.add(2, 3, 4)
    #添加第三张表对应关系
    Application_id = 1
    host_id = 2;
    Application_id = 1
    host_id = 3;
    .....
    obj.r.add(*[1, 2, 3, 4])
    #同上
    
    obj.r.remove(1)
    obj.r.remove(2, 4)
    obj.r.remove(*[1, 2, 3])
    
    obj.r.clear()
    #清除Application.objects.get(id=1)的第三张表里面的所有对应数据
    
    obj.r.set([3, 5, 7])
    #清除Application.objects.get(id=1)的第三张表里面的所有对应数据,然后重新设置
    
    # 所有相关的主机对象“列表” QuerySet
    obj.r.all()

                   

    5.2 查询数据

      语法:自定义表的类名.objects.方法名()。

      返回值:<class 'django.db.models.query.QuerySet'> 可以理解为列表,列表内每个元素为具体的数据对象(自定义数据类的对象)

      返回值内部元素:

           一般:大部分为对象;

           特殊:values(['列名', ...]) 返回数据字典{字段名:值},

              value_list(['列名', ...]) 返回数据元组(字段名,字段值,字段名....)

              ['列名',...] 列名不传,默认返回所有字段。

      5.2.1方法名列举:

        all()  查询所有数据

        filter() 过滤,相当于mysql的sql语法中的where条件  

    查询所有数据

    search_resu = models.UserInfo.objects.all()
    for data in search_resu:
        print(data.username)

      细化过滤结果:

      返回值 QuerySet 对象下属方法:

    search_resu.first() 获取第一个数据对象,不存在为Null
    search_resu.last() 获取最后一个数据对象,不存在为Null
    search_resu.all() 获取所有值
    search_resu.get() 获取一个数据对象,不存在就报错
    search_resu.count() 查询结果的个数
    search_resu.query QuerySet结果对应的Sql语句
    search_resu.delete()
    search_resu.update()
    search_resu.update_or_create()
    search_resu.select_for_update()
    search_resu.exists()
    search_resu.values() 获取值,返回QuerySet列表对象,列表内部元素是字典,每个数据一个字典 例如:[{'id':2, 'username': 'zmd2', 'password': 'xxxx'},{...}...]【常用】
    values('id','name', ...)内部可以传递具体想要获取的字段.【常用】

    search_resu.value_list() 获取值,返回QuerySet列表,内部元素是元组,例如:(2,'user1','password1')
      ....
    本表字段值查询:
      data = search_resu.first()
      data.字段名
    举例
    #                   Mysql 数据库内容
    # +----+----------+----------+--------------+---------------+
    # | id | username | password | user_type_id | user_group_id |
    # +----+----------+----------+--------------+---------------+
    # |  2 | zmd2     | 123      |            3 |             3 |
    # +----+----------+----------+--------------+---------------+
    
    search_resu = models.UserInfo.objects.filter(username=username).first()
    print('查询结果:用户名:%s 密码:%s' % (search_resu.username, search_resu.password))
    
    # 查询结果:用户名:zmd2 密码:123
    5.2.2 filter() 过滤(了不起的双下划线) 增加过滤条件:大于小于、in、isnull、contains、range ...
    # 获取个数
            #
            # models.Tb1.objects.filter(name='seven').count()
    
            # 大于,小于
            #
            # models.Tb1.objects.filter(id__gt=1)              # 获取id大于1的值
            # models.Tb1.objects.filter(id__gte=1)              # 获取id大于等于1的值
            # models.Tb1.objects.filter(id__lt=10)             # 获取id小于10的值
            # models.Tb1.objects.filter(id__lte=10)             # 获取id小于10的值
            # models.Tb1.objects.filter(id__lt=10, id__gt=1)   # 获取id大于1 且 小于10的值
    
            # in
            #
            # models.Tb1.objects.filter(id__in=[11, 22, 33])   # 获取id等于11、22、33的数据
            # models.Tb1.objects.exclude(id__in=[11, 22, 33])  # not in
    
            # isnull
            # Entry.objects.filter(pub_date__isnull=True)
    
            # contains
            #
            # models.Tb1.objects.filter(name__contains="ven")
            # models.Tb1.objects.filter(name__icontains="ven") # icontains大小写不敏感
            # models.Tb1.objects.exclude(name__icontains="ven")
    
            # range
            #
            # models.Tb1.objects.filter(id__range=[1, 2])   # 范围bettwen and
    
            # 其他类似
            #
            # startswith,istartswith, endswith, iendswith,
    
            # order by
            #
            # models.Tb1.objects.filter(name='seven').order_by('id')    # asc
            # models.Tb1.objects.filter(name='seven').order_by('-id')   # desc
    
            # group by
            #
            # from django.db.models import Count, Min, Max, Sum
            # models.Tb1.objects.filter(c1=1).values('id').annotate(c=Count('num'))
            # SELECT "app01_tb1"."id", COUNT("app01_tb1"."num") AS "c" FROM "app01_tb1" WHERE "app01_tb1"."c1" = 1 GROUP BY "app01_tb1"."id"
    
            # limit 、offset
            #
            # models.Tb1.objects.all()[10:20]
    
            # regex正则匹配,iregex 不区分大小写
            #
            # Entry.objects.get(title__regex=r'^(An?|The) +')
            # Entry.objects.get(title__iregex=r'^(an?|the) +')
    
            # date
            #
            # Entry.objects.filter(pub_date__date=datetime.date(2005, 1, 1))
            # Entry.objects.filter(pub_date__date__gt=datetime.date(2005, 1, 1))
    
            # year
            #
            # Entry.objects.filter(pub_date__year=2005)
            # Entry.objects.filter(pub_date__year__gte=2005)
    
            # month
            #
            # Entry.objects.filter(pub_date__month=12)
            # Entry.objects.filter(pub_date__month__gte=6)
    
            # day
            #
            # Entry.objects.filter(pub_date__day=3)
            # Entry.objects.filter(pub_date__day__gte=3)
    
            # week_day
            #
            # Entry.objects.filter(pub_date__week_day=2)
            # Entry.objects.filter(pub_date__week_day__gte=2)
    
            # hour
            #
            # Event.objects.filter(timestamp__hour=23)
            # Event.objects.filter(time__hour=5)
            # Event.objects.filter(timestamp__hour__gte=12)
    
            # minute
            #
            # Event.objects.filter(timestamp__minute=29)
            # Event.objects.filter(time__minute=46)
            # Event.objects.filter(timestamp__minute__gte=29)
    
            # second
            #
            # Event.objects.filter(timestamp__second=31)
            # Event.objects.filter(time__second=2)
            # Event.objects.filter(timestamp__second__gte=31)
    
    # extra
        #
        # extra(self, select=None, where=None, params=None, tables=None, order_by=None, select_params=None)
        #    Entry.objects.extra(select={'new_id': "select col from sometable where othercol > %s"}, select_params=(1,))
        #    Entry.objects.extra(where=['headline=%s'], params=['Lennon'])
        #    Entry.objects.extra(where=["foo='a' OR bar = 'a'", "baz = 'a'"])
        #    Entry.objects.extra(select={'new_id': "select id from tb where id > %s"}, select_params=(1,), order_by=['-nid'])
    
        # F
        #
        # from django.db.models import F
        # models.Tb1.objects.update(num=F('num')+1)
    
    
        # Q
        #
        # 方式一:
        # Q(nid__gt=10)
        # Q(nid=8) | Q(nid__gt=10)
        # Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root')
        # 方式二:
        # con = Q()
        # q1 = Q()
        # q1.connector = 'OR'
        # q1.children.append(('id', 1))
        # q1.children.append(('id', 10))
        # q1.children.append(('id', 9))
        # q2 = Q()
        # q2.connector = 'OR'
        # q2.children.append(('c1', 1))
        # q2.children.append(('c1', 10))
        # q2.children.append(('c1', 9))
        # con.add(q1, 'AND')
        # con.add(q2, 'AND')
        #
        # models.Tb1.objects.filter(con)
    
    
        # 执行原生SQL
        #
        # from django.db import connection, connections
        # cursor = connection.cursor()  # cursor = connections['default'].cursor()
        # cursor.execute("""SELECT * from auth_user where id = %s""", [1])
        # row = cursor.fetchone()
    
    其他操作
    非常用操作
     5.2.3 跨表查询
    两种方式:
    1.外键字段下划线id为在本表数据库中实际存储的字段值(例下面的user_group_id)。     
    2.外键字段代表为第二张表的具体数据对象。封装了数据该有的字段属性。获取值可以一直.下去......     
    注:跨表设计
    通过外键,见(4.3 表设计:外键关联)
     例如:
      models.py 中 userinfo表中的user_group字段,外键指向usergroup表中的gid字段
    class UserGroup(models.Model):
        gid = models.AutoField(primary_key=True)
        caption = models.CharField(max_length=32, unique=True)
        ctime = models.DateTimeField(auto_now_add=True, null=True)
        uptime = models.DateTimeField(auto_now=True, null=True)
    
    class UserInfo(models.Model):
        # id列,自增,主键
        # 用户名列,字符串类型,指定长度
        username = models.CharField(max_length=32, error_messages={'required': '必填项目必填项目'}, help_text='用户名')
        password = models.CharField(max_length=64)
    
        user_type_choices = (
            (1, '超级用户'),
            (2, '普通用户'),
            (3, '只读用户'),
        )
        user_type_id = models.IntegerField(choices=user_type_choices, default=3)
        user_group = models.ForeignKey("UserGroup", to_field='gid', on_delete=models.CASCADE, null=True)
      跨表查询举例:
     1)views.py中查询语句获取外键的主键值
    search_resu = models.UserInfo.objects.filter(username=username).first()
    print("%s 的用户组ID:%s" % (username, search_resu.user_group_id))

    2) views.py 中查询语句获取外键的表对应数据的其他字段:

      通过外键字段名 点 外键表有的字段即可。(本表单条数据.外键字段名.外表字段名)

    search_resu = models.UserInfo.objects.filter(username=username).first()
                print("%s 的用户组名:%s" % (username, search_resu.user_group.caption))
    
    #zmd2 的用户组名:运维
    #数据 为:
    #+-----+---------+----------------------------+----------------------------+
    #| gid | caption | ctime                      | uptime                     |
    #+-----+---------+----------------------------+----------------------------+
    #|   3 | 运维    | 2020-07-13 11:41:33.162318 | 2020-07-13 11:41:33.162318 |
    #+-----+---------+----------------------------+----------------------------+
      3) html 模板中获取有外键对应的外表字段值

    models.py

    # Create your models here.
    class Business(models.Model):
        bid = models.AutoField(primary_key=True)
        business_name = models.CharField(max_length=128, null=False)
        code = models.CharField(max_length=32, null=True)
    
    
    class Host(models.Model):
        nid = models.AutoField(primary_key=True)
        hostname = models.CharField(max_length=32, db_index=True)
        ip = models.GenericIPAddressField(protocol="ipv4", db_index=True)
        port = models.IntegerField()
        b = models.ForeignKey(to="Business", to_field='bid', null=True, on_delete=models.SET_NULL)

    views.py 

    hosts = models.Host.objects.all()
    return render(request, 'app02_host_list.html', {'hosts': hosts})

    html 模板中 获取的结果

    {% for host in hosts %}
        <li> {{ host.hostname }} {{ host.ip }} {{ host.port }} {{ host.b.business_name }}</li>
    {% endfor %}
     
     5.2.4 跨表查询__指定字段 values() value_list()  (神奇的双下划线) 
      过滤跨表字段都用双下滑线

      示例:

        通过查询主机,获取主机所属业务线名称(主机所属业务线为外键字段)。

      models.py 数据结构

    class Host(models.Model):
        nid = models.AutoField(primary_key=True)
        hostname = models.CharField(max_length=32, db_index=True)
        ip = models.GenericIPAddressField(protocol="ipv4", db_index=True)
        port = models.IntegerField()
        b = models.ForeignKey(to="Business", to_field='bid', null=True, on_delete=models.SET_NULL)

      views.py 查询逻辑 

     

    from app02 import models
    
    host = models.Host.objects.filter(hostname='host1')
    host_b = host.values('b__business_name')
        return HttpResponse(host_b)
     5.2.5 反向跨表查询,所在表没有ForeiginKey字段

       B表某字段外键到A表

      A表内使用django提供的隐藏字段b表名__set 查询B表中哪些字段外键了自己主键。

     
     
     

     5.3 删除数据 (查询的结果.delete())

       返回值:<class 'tuple'> 为元组  示例:(0, {'app01.UserInfo': 0})

          第一个元素为删除的元素个数,第二个为删除删除的数据详细信息

      删除示例:

    class OrmStudy(View):
        def get(self,request, action, username, pwd):
            if action == 'delete':
                search_resu = models.UserInfo.objects.filter(username=username)
                delete_resu = search_resu.delete()
                print(type(delete_resu))
                print(delete_resu)
                return HttpResponse(delete_resu)

     5.4 更新数据(查询结果.update(field_name='new_value'))

     返回值:<class 'int'> 代表更新的数据条数

     代码示例

    class OrmStudy(View):
        def get(self,request, action, username, pwd):
            # .......
            elif action == 'update':
                search_resu = models.UserInfo.objects.filter(username=username)
                update_resu = search_resu.update(password=pwd)
                print(type(update_resu))
                return HttpResponse(update_resu)

     django 后台管理 admin

    1、初始化设置

      1. 设置密码:>python manage.py createsuperuser

      2.app01/admin.py 添加要管理的数据模块:

    from app01 import models
    admin.site.register(models.UserInfo)
    admin.site.register(models.UserGroup)

     2、登录管理后台
      http://127.0.0.1:8000/admin

      



    security-scan17.hb.ksyun

  • 相关阅读:
    获取文件扩展名(后缀)
    文件字节大小显示成M,G和K
    mybatis在Mapper的xml文件中的转义字符的处理
    Java反射中method.isBridge() 桥接方法
    MyBatis框架的使用及源码分析(十三) ResultSetHandler
    MyBatis框架的使用及源码分析(十二) ParameterHandler
    MyBatis框架的使用及源码分析(十一) StatementHandler
    MyBatis框架的使用及源码分析(十) CacheExecutor,SimpleExecutor,BatchExecutor ,ReuseExecutor
    MyBatis框架的使用及源码分析(九) Executor
    MyBatis框架的使用及源码分析(八) MapperMethod
  • 原文地址:https://www.cnblogs.com/zhangmingda/p/13279512.html
Copyright © 2020-2023  润新知