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

1、服务端获取值:

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的所有方法 print(dir(request))查看

1.1 查看请求头

  views.py

from django.shortcuts import render, redirect, HttpResponse
from django.views.decorators.csrf import csrf_exempt  # 免除CSRF跨站请求校验工具
from django.utils.decorators import method_decorator # 免除CSRF跨站请求校验工具


@method_decorator(csrf_exempt, name="dispatch") # 免除CSRF class FaultNotification(View): def post(self, request, *args, **kwargs): headers = request.headers print("headers:",headers) # 输出:headers: {'Content-Length': '0', 'Content-Type': 'text/plain', 'Cache-Control': 'no-cache', 'Postman-Token': '61277a1c-9f44-4a4b-996a-771893468275', 'User-Agent': 'PostmanRuntime/3.0.9', 'Accept': '*/*', 'Host': '127.0.0.1:8000', 'Accept-Encoding': 'gzip, deflate', 'Connection': 'keep-alive'}
1.2 获取请求body 体内容 request.body
    def post(self, request, *args, **kwargs):
        """
        :param request:请求体
        :param args:参数
        :param kwargs:
        :return: render渲染结果
        """
        """
        {
            "ProductType": "EBS",
            "FaultPhenomenon": "EBS_ReadWrite_Delay",
            "Reason": "KernelJam",
            "VolumeIds": {
                "XXXXXXX": {
                    "ReadDelaySec": 17,
                    "WriteDelaySec": 20
                },
                "YYYYYYYY": {
                    "ReadDelaySec": 15,
                    "WriteDelaySec": 13
                }
            }
        }
        """
        headers = request.headers
        content_type = headers.get("Content-Type")
        if content_type != "application/json":
            data = {"errorCode": 40002,
                    "errorMsg": "Content-Type Only application/json  supported"}
            response = HttpResponse(json.dumps(data), status=400, reason="Content-Type not supported")
        else:
            body_content = json.loads(request.body)
            print("body_content:", body_content)
            result_data = {"errorCode": 0,
                           "errorMsg": "OK"}
            response = HttpResponse(json.dumps(result_data))
            response.status_code = 200

        return response

 

 print(dir(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"
]

 

 

 

 

2、服务端返回消息设置:

  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

  2.1  设置状态码,以及状态码简要描述 HTTP协议 固定响应头中第二部分(状态码(数字和原因短语))

  在响应中,HTTP报文由HTTP版本、状态码(数字和原因短语)、HTTP首部字段3部分构成 : https://blog.csdn.net/Alexshi5/article/details/80379086

代码


from django.shortcuts import render, redirect, HttpResponse

class
FaultNotification(View): def get(self, request): data = {"errorCode": 40001, "errorMsg": "Request method 'POST' not supported"} response = HttpResponse(json.dumps(data), status=400, reason="method 'POST' not supported") # response.status_code = 400 # # response.status_text = "'POST' not supported" return response
  响应支持设置的字段,可以溯源代码查看

  content_type=None, status=None, reason=None, charset=None, headers=None

response.py 源代码如下,请参考

# response.py

class HttpResponseBase:
    """
    An HTTP response base class with dictionary-accessed headers.

    This class doesn't handle content. It should not be used directly.
    Use the HttpResponse and StreamingHttpResponse subclasses instead.
    """

    status_code = 200

    def __init__(self, content_type=None, status=None, reason=None, charset=None, headers=None):
        self.headers = ResponseHeaders(headers or {})
        self._charset = charset
        if content_type and 'Content-Type' in self.headers:
            raise ValueError(
                "'headers' must not contain 'Content-Type' when the "
                "'content_type' parameter is provided."
            )
        if 'Content-Type' not in self.headers:
            if content_type is None:
                content_type = 'text/html; charset=%s' % self.charset
            self.headers['Content-Type'] = content_type
        self._resource_closers = []
        # This parameter is set by the handler. It's necessary to preserve the
        # historical behavior of request_finished.
        self._handler_class = None
        self.cookies = SimpleCookie()
        self.closed = False
        if status is not None:
            try:
                self.status_code = int(status)
            except (ValueError, TypeError):
                raise TypeError('HTTP status code must be an integer.')

            if not 100 <= self.status_code <= 599:
                raise ValueError('HTTP status code must be an integer from 100 to 599.')
        self._reason_phrase = reason

 

 

 

 

详解知识点二:模板语言

{{ 变量名 }} 
循环语句:
{% 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\n 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\n 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, # 删除关联数据,
     related_name            # 设置外键字段时,可以指定被外键关联的表中反向查询本表数据的自定义字段名称 可参考:https://blog.csdn.net/wuliangtianzu/article/details/82656647
     through='表名' # ManyToManyField字段指定第三张表名,
through_filelds=('第三张表字段1', '第三张表字段二') 指定对应第三张表的字段名

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表中哪些字段外键了自己主键。

  自定义A表隐藏外键字段命名:在B表中设置A表反向查询B表数据的隐藏外键字段名:在B表中设置 related_name 属性

数据库查询优化

数据库查询优化

  优化:虽然减轻了数据库的压力,但查询速度大大的减慢

  ORM内所有的语句操作,默认都是惰性查询,只有你在真正的需要数据的时候才会走数据,

查询优化的关键字方法:select_related、only、prefentch_related、defer

Django数据库优化操作之select_related主动联表查询

例子如:

 

 

 

 如果不用select_related时。查询all()执行的结果中显示多条MySQL语句,

而select_related会一致性的做连表操作,一句MySQL语句即可,大大的减轻数据库的压力

all()查询的结果显示:

而select_relate的查询方法是一致性的连表操作

 

 

 

"""
select_related:会将括号内外键字段所关联的那张表  直接全部拿过来(可以一次性拿多张表)跟当前表拼接操作
从而降低你跨表查询 数据库的压力

注意select_related括号只能放外键字段(一对一和一对多)
res = models.Book.objects.all().select_related('外键字段1__外键字段2__外键字段3__外键字段4')
"""

Django数据库优化操作之perfetch_related非主动联表查询

  不直接连表,但是会以第一次查询的结果之上再次查询了另一张表操作,看似查询两次

 

 

"""
不主动连表操作(但是内部给你的感觉像是连表操作了),而是将book表中的publish全部拿出来,在取publish表中将id对应的所有的数据取出
res = models.Book.objects.prefetch_related('publish')
括号内有几个外键字段 就会走几次数据库查询操作 
   
"""

 

Django数据库优化操作之only方法

  加only参数是从查询结果中只取某个字段,封装做成对象的形式,不再频繁的走数据库,从而减轻数据库的压力

 

 

 

上述r.title在查询时,即使循环也只是走了一次数据库查询,而r.price,没有的字段时,会循环的频繁走数据库

Django数据库优化操作之defer方法

  与only刚好相反,会将不是括号内的所有字段信息查询出来;如果点的是括号内的字段会频繁的走数据库查询;

如果不是字段内的反而点一次只查询一次,也是为了排除在外,然后起到优化的作用

 

 

 

 

 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

  

 

posted on 2020-07-10 15:33  zhangmingda  阅读(306)  评论(0编辑  收藏  举报

导航