博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Django:URL,Views,Template,Models
阅读量:6957 次
发布时间:2019-06-27

本文共 54268 字,大约阅读时间需要 180 分钟。

准备工作:熟悉Django命令行工具

django-admin.py 是Django的一个用于管理任务的命令行工具,常用的命令整理如下:

<1> 创建一个django工程 : django-admin.py startproject mysite

  当前目录下会生成mysite的工程,目录结构如下:

  

  • manage.py ----- Django项目管理工具,通过它可以调用django shell和数据库等。
  • settings.py ---- 包含了项目的默认设置,包括数据库信息,调试标志以及其他一些工作的变量。
  • urls.py ----- 负责把URL模式映射到应用程序。

<2>在mysite目录下创建blog应用: python manage.py startapp blog

  目录结构如下:

  

<3>启动django项目:python manage.py runserver 8080

  这样我们的django就启动起来了!

<4>生成同步数据库的脚本:python manage.py makemigrations  

                     同步数据库:  python manage.py migrate   

  

   注意:在开发过程中,数据库同步误操作之后,难免会遇到后面不能同步成功的情况,解决这个问题的一个简单粗暴方法是把migrations目录下

        的脚本(除__init__.py之外)全部删掉,再把数据库删掉之后创建一个新的数据库,数据库同步操作再重新做一遍。

<5>当我们访问http://127.0.0.1:8080/admin/时,会出现:

  所以我们需要为进入这个项目的后台创建超级管理员:python manage.py createsuperuser设置好用户名和密码后便可登录啦!

<6>清空数据库:python manage.py  flush

<7>查询某个命令的详细信息: django-admin.py  help  startapp

       admin 是Django 自带的一个后台数据库管理系统。

<8>启动交互界面 :python manage.py  shell

     这个命令和直接运行 python 进入 shell 的区别是:你可以在这个 shell 里面调用当前项目的 models.py 中的 API,对于操作数据,还有一些小测试非常方便。

<9> 终端上输入python manage.py 可以看到详细的列表,在忘记子名称的时候特别有用

一、URL(路由系统)

浏览器会自动给url后加一个“/”django会自动给路由的正则表达式前面加一个“/”django会给任何不带“/”结尾的url语句添加“/”(可设置)短路路由规则:匹配到第一条就忽略后面所有!所以路由顺序很重要!

1.普通路由

url(r'^index/',views.index),

2.正则路由

url(r'^page/\d+', views.page),

3.正则加括号

提供参数传递,按顺序接收,接收到的都是字符串

# urls.pyurl(r'^page/(\d+)', views.page),

 

# views.pydef page(request, index):page = indexreturn HttpResponse("page: 第%s页" % page)

4.正则加括号加指定参数名

提供指定参数传递,按参数名字进行接收,顺序可变,但参数名必须相同,接收到的都是字符串

urls.py

url(r'^page/(?P
\d+)/(?P
\d+)', views.page), 

views.py

def page(request, page, number):p = pagen = numberreturn HttpResponse("page: 第%s页 第%s条" %(p, n))

5.分级路由include

在app01中新建urls文件

from django.conf.urls import includeurl(r'index/', include(app01.urls)), 

二、Views(视图函数)

http请求中产生两个核心对象:

        http请求:HttpRequest对象

        http响应:HttpResponse对象

1. HttpRequest对象的属性和方法

1 from django.shortcuts import render,HttpResponse 2  3 # Create your views here. 4 def index(request): 5     #request.POST 6     #request.GET 7     #return HttpResponse("hello world!") 8     #1.path:请求页面的全路径,不包括域名 9     print(request.path)10 11     #2.get_full_path:请求页面的全路径,包括域名12     print(request.get_full_path())13 14     #3.method:请求中使用的HTTP方法15     #if req.method == "GET":16     #   do_something()17     #elseif req.method=="POST":18     #   do_something_else()19     #GET: 包含所有HTTP GET参数的类字典对象20     # POST:包含所有HTTP POST参数的类字典对象21     # 服务器收到空的POST请求的情况也是可能发生的,也就是说,表单form通过22     # HTTP POST方法提交请求,但是表单中可能没有数据,因此不能使用23     #if req.POST来判断是否使用了HTTP POST方法;应该使用 if req.method=="POST"24 25     #4.COOKIES:包含所有cookies的标准Python字典对象;keys和values都是字串。26 27     #5.FILES:包含所有上传文件的类字典对象;28     # FILES中的每一个Key都是 标签中name属性的值,29     # FILES中的每一个value同时也是一个标准的python字典对象,包含下面三个Keys:30     #     filename:上传文件名,用字符串表示31     #     content_type:上传文件的Content Type32     #     content:上传文件的原始内容33     34     #6.user:是一个django.contrib.auth.models.User对象,代表当前登陆的用户。如果访问用户当前35     # 没有登陆,user将被初始化为django.contrib.auth.models.AnonymousUser的实例。你可以通36     # 过user的is_authenticated()方法来辨别用户是否登陆:37     # if req.user.is_authenticated();38     # 只有激活Django中的AuthenticationMiddleware时该属性才可用39     40     # 7.session:唯一可读写的属性,代表当前会话的字典对象;自己有激活Django中的session支持时该属性才可用。
Http Request对象的属性和方法

2. HttpResponse对象的属性和方法

  HttpRequest对象是由django自动创建的,HttpResponse对象需要我们自己创建,每个view请求处理方法必须返回一个HttpResponse对象。

  HttpResponse类在django.http.HttpResponse

  在HttpResponse对象上扩展的常用方法:

页面渲染:render()(推荐), render_to_response()页面跳转:redirect("路径")locals():可以直接将函数中所有的变量传给模板
1 /*--------------------register.html-------------------*/ 2  3     
4

用户名

5

密码

6

7 8
9 10 11 /*--------------------login.html---------------------*/12 13
14

姓名

15

性别

16

邮箱

17

18
19 /*--------------------user_page.html--------------*/20 21

用户{
{ name }}你好

22 23 /*---------------------blog\urls.py------------------*/24 from django.contrib import admin25 from django.urls import path26 from django.conf.urls import url27 28 from blog import views29 30 urlpatterns = [31 # path('admin/', admin.site.urls),32 33 url(r'register/',views.register,name="register"),34 url(r'^login',views.login,name="login"),35 url(r'^user_page',views.user_page,name="user_page")36 ]37 /*----------------------views.py-----------------------*/38 from django.shortcuts import render,HttpResponse,render_to_response,redirect39 40 # Create your views here.41 user_list=[]42 def register(request):43 if request.method == "POST":44 username=request.POST.get("username",None)45 password=request.POST.get("password",None)46 print("username:",username)47 if username:48 user_list.append(username)49 return redirect("/blog/login/")50 #redirect方法进行页面跳转时,地址栏URL会跟改为跳转页面的,此处为http://127.0.0.1/blog/login51 #return render(request,"login.html")52 #在此处用render方法进入页面,地址栏URL不会改变,仍然为http;//127.0.0.1/blog/index53 54 return HttpResponse("username is None")55 return render(request,"register.html")56 #或者render_to_response("register.html")57 def login(request):58 if request.method=="POST":59 user=request.POST.get("username",None)60 if user in user_list:61 name=user62 return redirect("/blog/user_page/")63 return HttpResponse("username does not exist")64 65 return render(request, "login.html")66 67 def user_page(request):68 69 return render(request,"user_page.html",locals())
注册-登录-用户首页流程模拟

三、Template(模板系统)

在html文件中使用模板语言

1. 普通变量

{
{var}}

调用数组元素:(圆点加下标)

list1 = [1,2,3]{
{list.0}}{
{list.1}}{
{list.2}}

调用字典元素: (圆点加键值)

dict1 = {"k1":"v1","k2":"v2"}{
{dict1.k1}}{
{dict1.k2}}
1 # 1.句点用于访问列表索引: 2  3 >>> from django.template import Template, Context 4 >>> t = Template('Item 2 is {
{ items.2 }}.') 5 >>> c = Context({
'items': ['apples', 'bananas', 'carrots']}) 6 >>> t.render(c) 7 'Item 2 is carrots.' 8 9 # 2.句点用于访问字典索引:10 11 >>> from django.template import Template, Context12 >>> person = {
'name': 'Sally', 'age': '43'}13 >>> t = Template('{
{ person.name }} is {
{ person.age }} years old.')14 >>> c = Context({
'person': person})15 >>> t.render(c)16 'Sally is 43 years old.'17 18 #3.句点访问对象属性,如 Python 的 datetime.date 对象有year,month 和 day 几个属性,可#以在模板中使用句点来访问这些属性:19 20 >>> from django.template import Template, Context21 >>> import datetime22 >>> d = datetime.date(1993, 5, 2)23 >>> d.year24 199325 >>> d.month26 527 >>> d.day28 229 >>> t = Template('The month is {
{ date.month }} and the year is {
{ date.year }}.')30 >>> c = Context({
'date': d})31 >>> t.render(c)32 'The month is 5 and the year is 1993.'33 34 # 4.句点通过实例变量访问自定义类属性,这个方法适用于任意的对象。35 36 >>> from django.template import Template, Context37 >>> class Person(object):38 ... def __init__(self, first_name, last_name):39 ... self.first_name, self.last_name = first_name, last_name40 >>> t = Template('Hello, {
{ person.first_name }} {
{ person.last_name }}.')41 >>> c = Context({
'person': Person('John', 'Smith')})42 >>> t.render(c)43 'Hello, John Smith.'44 45 #5. 句点也可以用来引用对象的方法。例如,每个 Python 字符串都有 upper() 和 isdigit()方法,你在模板中可以使用同样的句点语法来调用它们:46 >>> from django.template import Template, Context47 >>> t = Template('{
{ var }} -- {
{ var.upper }} -- {
{ var.isdigit }}')48 >>> t.render(Context({
'var': 'hello'}))49 'hello -- HELLO -- False'50 >>> t.render(Context({
'var': '123'}))51 '123 -- 123 -- True'
View Code
1 0#  语法格式:{
{obj|filter:param}} 1 #1. add :给变量加上相应的值 2 #2. addslashes :给变量中的引号前加上斜线 3 #3. capfirst:首字母大写 4 #4. cut:从字符串中移除指定的字符 5 #5. date:格式化日期字符串 6 #6. default :如果值是False,就替换成设置的默认值,否则就是用本来的值 7 #7. default_if_none: 如果值是None,就替换成设置的默认值,否则就使用本来的值 8 #实例: 9 10 #value1="aBcDe"11 {
{ value1|upper }}
12 13 #value2=514 {
{ value2|add:3 }}
15 16 #value3='he llo wo r ld'17 {
{ value3|cut:' ' }}
18 19 #import datetime20 #value4=datetime.datetime.now()21 {
{ value4|date:'Y-m-d' }}
22 23 #value5=[]24 {
{ value5|default:'空的' }}
25 26 #value6='跳转'27 28 {
{ value6 }}29 30 {% autoescape off %}31 {
{ value6 }}32 {% endautoescape %}33 34 {
{ value6|safe }}
35 36 {
{ value6|striptags }}37 38 #value7='1234'39 {
{ value7|filesizeformat }}
40 {
{ value7|first }}
41 {
{ value7|length }}
42 {
{ value7|slice:":-1" }}
43 44 #value8='http://www.baidu.com/?a=1&b=3'45 {
{ value8|urlencode }}
46 value9='hello I am yuan'
模板变量的filter使用

2. if语句

{% if %}标签判断一个条件表达式,如果是“true”,即它存在、不为空并且不是false的boolean值,系统则会显示{% if %}和{% endif %}间的所有内容

{% if 判断 %}......{% else %} ......{% endif %}

3. for循环

{% for %}标签按顺序遍历一个序列中的各个元素,每次循环模板系统都会渲染{% for %}和{% endfor %}之间的所有内容

{% for i in data %}......{% endfor %}

django内置特殊的用于for循环的变量:

forloop.counterforloop.counter0forloop.firstforloop.last
1 forloop.counter表示循环的次数,它从1开始计数,第一次循环设为1 2  3     {% for item in todo_list %} 4         

{

{ forloop.counter }}: {
{ item }}

5 {% endfor %} 6 forloop.counter0 类似于forloop.counter,但它是从0开始计数,第一次循环设为0 7 forloop.revcounter 8 forloop.revcounter0 9 forloop.first当第一次循环时值为True,在特别情况下很有用:10 #{% empty %}判断列表是否为空11 12 {
{li }}13 {% for i in li %}14
  • {
    { forloop.counter0 }}----{
    { i }}
  • 15 {% empty %}16
  • this is empty!
  • 17 {% endfor %}18 19 # [11, 22, 33, 44, 55]20 # 0----1121 # 1----2222 # 2----3323 # 3----4424 # 4----55
    View Code

    4.特殊标签

    (1) {%csrf_token%}:csrf_token标签,用于防治跨站攻击验证。注意如果你在view的index里用的是render_to_response方法,该标签不会生效

    其实,{%csrf_token%}是会生成一个input标签,和其他表单标签一起提交给后台。

    (2) {% url  '路由别名' %}:  引用路由配置的地址

    1 
    2
    3
    4 {%csrf_token%}5
    View Code

    (3) {% with %}:用更简单的变量名替代复杂的变量名

    {% with total=fhjsaldfhjsdfhlasdfhljsdal %} {
    { total }} {% endwith %}

    (4) {% verbatim %}: 禁止render

    {% verbatim %}         {
    { hello }}{% endverbatim %}

    (5) {% load %}: 加载标签库 

    5. 内置函数

    lower  first  last  divisibleby 等等。例如:{
    { “AAA”|lower}} 使用管道符引用函数名,左边的‘AAA’自动当作参数传递给lower函数又或:判断当前循环的次数是否能被2整除{% if forloop.counter0|divisibleby:"2" %} {% else %} {% endif %}

    6. 自定义filter和simple_tag

    1.在settings中的INSTALLED_APPS配置当前app,不然django无法找到自定义的simple_tag.

    2.在app中创建templatetags模块(必须的)

    3.创建任意 .py 文件,如:my_tags.py

    4.在使用自定义simple_tag和filter的html文件中导入之前创建的 my_tags.py :{% load my_tags %}

    5.使用simple_tag和filter(如何调用)

    1 /*-------------------my_tag.py-----------------*/ 2 from django import template 3 from django.utils.safestring import mark_safe 4 register = template.Library()   #register的名字是固定的,不可改变 5 @register.filter          #只能传递一个参数,能用在逻辑控制语句中     6 def filter_multi(v1,v2): 7     return  v1 * v2 8  9 @register.simple_tag #参数不限,但不能用在逻辑控制语句中10 def simple_tag_multi(v1,v2):11     return  v1 * v212 13 /*---------------使用my_tag的html------------*/14 {% load my_tag %}15 # num=1216 {
    { num|filter_multi:2 }} #调用自定义filter2417 {% simple_tag_multi 2 5 %}#调用自定义simple_tag
    自定义filter和simple_tag函数

    7. 继承模板

    {% extends "xxxx.html" %}

    8. 重写模板

    在母版和子版式中使用同样的:{% block 取个名字 %}    (每个子版专属的代码){% endbloack %}

    9.导入html代码

    {% include "xxx.html" %}

    与继承模板不同的是,导入的是xxx.html的完全代码,因此xxx.html中最好没有头部,title等代码,只有实际的功能代码。

    四、models

    1.数据库配置

     django默认支持sqlite,mysql, oracle,postgresql数据库。

    1.sqlite: django默认使用sqlite数据库,默认自带sqlite的数据库驱动 , 引擎名称:django.db.backends.sqlite3

    2.mysql:引擎名称:django.db.backends.mysql

    3.常用的mysql驱动:MySQLdb(又名mysql_python,不支持python3.+,由pymysql替代),mysqlclient,mysql_connector_python(纯python的mysql驱动程序,由oracle官方维护)

    4.在django的项目中会默认使用sqlite数据库,在settings里有如下设置

    1 DATABASES = {2     'default': {3         'ENGINE': 'django.db.backends.sqlite3',4         'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),5                 }6 }
    View Code

    如果我们想要更改数据库,需要修改如下

    DATABASES = {      'default': {          'ENGINE': 'django.db.backends.mysql',          'NAME': 'mydatabase',          'USER': 'mydatabaseuser',          'PASSWORD': 'mypassword',          'HOST': '127.0.0.1',          'PORT': '3306',      }  }
    View Code

    NAME即数据库的名字,在mysql连接前该数据库必须已经创建,而上面的sqlite数据库下的db.sqlite3则是项目自动创建 ;

    USER和PASSWORD分别是数据库的用户名和密码。 设置完后,再启动我们的Django项目前,我们需要激活我们的mysql。

    然后,启动项目会报错:no module named MySQLdb ,这是因为django默认你导入的驱动是MySQLdb,可是MySQLdb

    对于py3有很大问题,所以我们需要的驱动是PyMySQL 所以,我们只需要找到项目名文件下的__init__,在里面写入:

    import pymysql pymysql.install_as_MySQLdb() 问题解决!

    如果使用的驱动是mysql官网驱动:mysql_connector_python,则database settings中需要将engine设置为

    'ENGINE': 'mysql.connector.django',然后改驱动会自动适配Django

    5.通过Django两条命令创建数据库和表

    python3 manage.py makemigrations

    python3 manage.py migrate

    2. Django ORM语法

    (1)基础类型

    from django.db import modelsclass userinfo(models.Model):    name = models.CharField(max_length=30)    email = models.EmailField()    memo = models.TextField()
    View Code

    (2)连表类型

    一对多:models.ForeignKey("其他表")多对多:models.ManyToManyField("其他表")一对一:models.OneToOneField("其他表")
    View Code

    (3) 字段类型

    <1> CharField        #字符串字段, 用于较短的字符串.        #CharField 要求必须有一个参数 maxlength, 用于从数据库层和Django校验层限制该字段所允许的最大字符数.<2> IntegerField       #用于保存一个整数.<3> FloatField        # 一个浮点数. 必须 提供两个参数:        #        # 参数    描述        # max_digits    总位数(不包括小数点和符号)        # decimal_places    小数位数                # 举例来说, 要保存最大值为 999 (小数点后保存2位),你要这样定义字段:                #                # models.FloatField(..., max_digits=5, decimal_places=2)                # 要保存最大值一百万(小数点后保存10位)的话,你要这样定义:                #                # models.FloatField(..., max_digits=19, decimal_places=10)                # admin 用一个文本框()表示该字段保存的数据.<4> AutoField        # 一个 IntegerField, 添加记录时它会自动增长. 你通常不需要直接使用这个字段;         # 自定义一个主键:my_id=models.AutoField(primary_key=True)        # 如果你不指定主键的话,系统会自动添加一个主键字段到你的 model.<5> BooleanField        # A true/false field. admin 用 checkbox 来表示此类字段.<6> TextField        # 一个容量很大的文本字段.        # admin 用一个 部件表示该字段保存的数据(一个文件上传部件) .     #注意:在一个 model 中使用 FileField 或 ImageField 需要以下步骤:            #(1)在你的 settings 文件中, 定义一个完整路径给 MEDIA_ROOT 以便让 Django在此处保存上传文件.             # (出于性能考虑,这些文件并不保存到数据库.) 定义MEDIA_URL 作为该目录的公共 URL. 要确保该目录对             #  WEB服务器用户帐号是可写的.            #(2) 在你的 model 中添加 FileField 或 ImageField, 并确保定义了 upload_to 选项,以告诉 Django            # 使用 MEDIA_ROOT 的哪个子目录保存上传文件.你的数据库中要保存的只是文件的路径(相对于 MEDIA_ROOT).             # 出于习惯你一定很想使用 Django 提供的 get_<#fieldname>_url 函数.举例来说,如果你的 ImageField             # 叫作 mug_shot, 你就可以在模板中以 {
    { object.#get_mug_shot_url }} 这样的方式得到图像的绝对路径.<12> URLField # 用于保存 URL. 若 verify_exists 参数为 True (默认), 给定的 URL 会预先检查是否存在( 即URL是否被有效装入且 # 没有返回404响应). # admin 用一个 文本框表示该字段保存的数据(一个单行编辑框)<13> NullBooleanField # 类似 BooleanField, 不过允许 NULL 作为其中一个选项. 推荐使用这个字段而不要用 BooleanField 加 null=True 选项 # 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    BooleanField(Field)        - 布尔值类型    NullBooleanField(Field):        - 可以为空的布尔值    CharField(Field)        - 字符类型        - 必须提供max_length参数, max_length表示字符长度    TextField(Field)        - 文本类型    EmailField(CharField):        - 字符串类型,Django Admin以及ModelForm中提供验证机制    IPAddressField(Field)        - 字符串类型,Django Admin以及ModelForm中提供验证 IPV4 机制    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)        - 二进制类型
    字段类型

    (4)参数类型

    <1> null : 数据库中字段是否可以为空    <2> blank: django的 Admin 中添加数据时是否可允许空值    <3> default:设定缺省值    <4> editable:如果为假,admin模式下将不能改写。缺省为真    <5> primary_key:设置主键,如果没有设置django创建表时会自动加上:        id = meta.AutoField('ID', primary_key=True)        primary_key=True implies blank=False, null=False and unique=True. Only one        primary key is allowed on an object.    <6> unique:数据唯一    <7> verbose_name: Admin中字段的显示名称    <8> help_text:   Admin中该字段的提示信息    <9> validator_list: 有效性检查。非有效产生 django.core.validators.ValidationError 错误    <10> db_column:   数据库中字段的列名    <11>db_index :  数据库中字段是否可以建立索引,如果为真将为此字段创建索引    <12>choices:一个用来选择值的2维元组。第一个值是实际存储的值,第二个用来方便进行选择。                如SEX_CHOICES= (( ‘F’,'Female’),(‘M’,'Male’),)                gender = models.CharField(max_length=2,choices = SEX_CHOICES)     <13>error_messages:      自定义错误信息(字典类型),从而定制想要显示的错误信息;                        字典健:null, blank, invalid, invalid_choice, unique, and unique_for_date                        如:{
    'null': "不能为空.", 'invalid': '格式错误'}
    参数类型

    (5)多表关系及参数

    ForeignKey(ForeignObject) # ForeignObject(RelatedField)        to,                         # 要进行关联的表名        to_field=None,              # 要关联的表中的字段名称        on_delete=None,             # 当删除关联表中的数据时,当前表与其关联的行的行为                                        - models.CASCADE,删除关联数据,与之关联也删除                                        - models.DO_NOTHING,删除关联数据,引发错误IntegrityError                                        - models.PROTECT,删除关联数据,引发错误ProtectedError                                        - models.SET_NULL,删除关联数据,与之关联的值设置为null(前提FK字段需要设置为可空)                                        - models.SET_DEFAULT,删除关联数据,与之关联的值设置为默认值(前提FK字段需要设置默认值)                                        - models.SET,删除关联数据,                                                      a. 与之关联的值设置为指定值,设置:models.SET(值)                                                      b. 与之关联的值设置为可执行对象的返回值,设置:models.SET(可执行对象)                                                        def func():                                                            return 10                                                        class MyModel(models.Model):                                                            user = models.ForeignKey(                                                                to="User",                                                                to_field="id"                                                                on_delete=models.SET(func),)        related_name=None,          # 反向操作时,使用的字段名,用于代替 【表名_set】 如: obj.表名_set.all()        related_query_name=None,    # 反向操作时,使用的连接前缀,用于替换【表名】     如: models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名')        limit_choices_to=None,      # 在Admin或ModelForm中显示关联数据时,提供的条件:                                    # 如:                                            - limit_choices_to={
    'nid__gt': 5} - limit_choices_to=lambda : {
    'nid__gt': 5} from django.db.models import Q - limit_choices_to=Q(nid__gt=10) - limit_choices_to=Q(nid=8) | Q(nid__gt=10) - limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root') db_constraint=True # 是否在数据库中创建外键约束 parent_link=False # 在Admin中是否显示关联数据 OneToOneField(ForeignKey) to, # 要进行关联的表名 to_field=None # 要关联的表中的字段名称 on_delete=None, # 当删除关联表中的数据时,当前表与其关联的行的行为 ###### 对于一对一 ###### # 1. 一对一其实就是 一对多 + 唯一索引 # 2.当两个类之间有继承关系时,默认会创建一个一对一字段 # 如下会在A表中额外增加一个c_ptr_id列且唯一: class C(models.Model): nid = models.AutoField(primary_key=True) part = models.CharField(max_length=12) class A(C): id = models.AutoField(primary_key=True) code = models.CharField(max_length=1) ManyToManyField(RelatedField) to, # 要进行关联的表名 related_name=None, # 反向操作时,使用的字段名,用于代替 【表名_set】 如: obj.表名_set.all() related_query_name=None, # 反向操作时,使用的连接前缀,用于替换【表名】 如: models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名') limit_choices_to=None, # 在Admin或ModelForm中显示关联数据时,提供的条件: # 如: - limit_choices_to={
    'nid__gt': 5} - limit_choices_to=lambda : {
    'nid__gt': 5} from django.db.models import Q - limit_choices_to=Q(nid__gt=10) - limit_choices_to=Q(nid=8) | Q(nid__gt=10) - limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root') symmetrical=None, # 仅用于多对多自关联时,symmetrical用于指定内部是否创建反向操作的字段 # 做如下操作时,不同的symmetrical会有不同的可选字段 models.BB.objects.filter(...) # 可选字段有:code, id, m1 class BB(models.Model): code = models.CharField(max_length=12) m1 = models.ManyToManyField('self',symmetrical=True) # 可选字段有: bb, code, id, m1 class BB(models.Model): code = models.CharField(max_length=12) m1 = models.ManyToManyField('self',symmetrical=False) through=None, # 自定义第三张表时,使用字段用于指定关系表 through_fields=None, # 自定义第三张表时,使用字段用于指定关系表中那些字段做多对多关系表 from django.db import models class Person(models.Model): name = models.CharField(max_length=50) class Group(models.Model): name = models.CharField(max_length=128) members = models.ManyToManyField( Person, through='Membership', through_fields=('group', 'person'), ) class Membership(models.Model): group = models.ForeignKey(Group, on_delete=models.CASCADE) person = models.ForeignKey(Person, on_delete=models.CASCADE) inviter = models.ForeignKey( Person, on_delete=models.CASCADE, related_name="membership_invites", ) invite_reason = models.CharField(max_length=64) db_constraint=True, # 是否在数据库中创建外键约束 db_table=None, # 默认创建第三张表时,数据库中表的名称unique_together #联合唯一,自己创建多对多第三章表时,加上此约束后,创建的表与默认创建的表相同#class UserToTag(models.Model):# # nid = models.AutoField(primary_key=True)# u = models.ForeignKey(to='User')# t = models.ForeignKey(to='Tag')# ctime = models.DateField()# class Meta:# unique_together=[# ('u','t'),# ]
    View Code

    3. Django ORM表操作

    (1)单表的增,删,改,查

    /*--------------------------index.html-------------------------*/    
    Title
    标题

    {
    % for book in book_list %}

    {

    { book.title }} {
    { book.author }} {
    { book.price }}

    {
    % endfor %}
    /*-----------------------models.py---------------------------*/from django.db import models# Create your models here.class UserInfo(models.Model): user=models.CharField(max_length=32) pwd=models.CharField(max_length=32)class book(models.Model): author=models.CharField(max_length=32) price=models.IntegerField() date=models.DateField() title=models.CharField(max_length=100) def __str__(self): return self.title/*-----------------------view.py------------------------------*/from django.shortcuts import render,HttpResponsefrom blog.models import *# Create your views here.def index(request): return render(request,"index.html")#-----------------增-------------------def addbook(request): #法一 book.objects.create(author="马尔克斯",price=88,date="2014-3-3",title="百年孤独") #法二 b=book(author="狄更斯",price=66,date="2011-2-4",title="艰难时世") b.save() return HttpResponse("书籍信息添加成功")#-----------------删-------------------def delete(request): book.objects.filter(id=9).delete() return HttpResponse("书籍信息删除成功")#-----------------改---------------------def update(request): #法一 book.objects.filter(author="高尔基").update(price=99) #法二 b=book.objects.get(author="狄更斯") b.price=77 b.save() return HttpResponse("书籍信息修改成功")#------------------------------------------#<1> 法一修改不能用get的原因是:update是QuerySet对象的方法,# get返回的是一个model对象,它没有update方法,而filter返回的是一个# QuerySet对象(filter里面的条件可能有多个条件符合,比如name='alvin',# 可能有两个name='alvin'的行数据)。#<2>update方法直接设定对应字段属性,save方法会将所有属性重新设定一遍,效率低,# 故推荐使用update方法#--------------------------------------------
    View Code

    练习所用book表单

    每次对表的操作想看见对应的sql实现语句,可在settings.py里加入日志记录配置

    LOGGING = {    'version': 1,    'disable_existing_loggers': False,    'handlers': {        'console':{            'level':'DEBUG',            'class':'logging.StreamHandler',        },    },    'loggers': {        'django.db.backends': {            'handlers': ['console'],            'propagate': True,            'level':'DEBUG',        },    }}
    View Code

     查询API

    # 查询相关API:#  <1>filter(**kwargs):      它包含了与所给筛选条件相匹配的对象#  <2>all():                 查询所有结果#  <3>get(**kwargs):         返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误。#-----------下面的方法都是对查询的结果再进行处理:比如 objects.filter.values()--------#  <4>values(*field):        返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列 model的实例化对象,而是一个可迭代的字典序列                                     #  <5>exclude(**kwargs):     它包含了与所给筛选条件不匹配的对象#  <6>order_by(*field):      对查询结果排序#  <7>reverse():             对查询结果反向排序#  <8>distinct():            从返回结果中剔除重复纪录#  <9>values_list(*field):   它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列#  <10>count():              返回数据库中匹配查询(QuerySet)的对象数量。# <11>first():               返回第一条记录# <12>last():                返回最后一条记录#  <13>exists():             如果QuerySet包含数据,就返回True,否则返回False。#扩展查询,有时候DJANGO的查询API不能方便的设置查询条件,提供了另外的扩展查询方法extra:#extra(select=None, where=None, params=None, tables=None,order_by=None, select_params=None(1)  Entry.objects.extra(select={
    'is_recent': "pub_date > '2006-01-01'"})(2) Blog.objects.extra( select=SortedDict([('a', '%s'), ('b', '%s')]), select_params=('one', 'two'))(3) q = Entry.objects.extra(select={
    'is_recent': "pub_date > '2006-01-01'"}) q = q.extra(order_by = ['-is_recent'])(4) Entry.objects.extra(where=['headline=%s'], params=['Lennon'])
    查询API
    def select(request):    # book_list=book.objects.all()    # book.objects.all()支持切片操作    # book_list = book.objects.all()[::2]#切片    # book_list = book.objects.all()[::-1]#切片    # book_list = book.objects.first()    # book_list = book.objects.last()    # book_list = book.objects.get(id=2)  # 只能取出一条记录时才不报错,取出的是单个元素,不能进行循环    # ret1=book.objects.filter(author="高尔基").values("title","price")    # ret2=book.objects.filter(author="yuan").values_list("name","price")    # book_list=book.objects.exclude(author="yuan").values("name","price")    # book_list= book.objects.all().values("name").distinct()    # book_count= book.objects.all().values("name").distinct().count()    # print("ret1:",ret1)    # 万能的  __    book_list=book.objects.filter(price__gt=50).values("name","price")#price__gt=50代表价格大于50    # book_list = book.objects.filter(name__contains="P").values_list("name", "price")    return render(request,"index.html",{
    "book_list":book_list})
    查询API的使用

     (2)一对多表的增、删、改、查

    练习所用表单

    book表

    author表

    publish表

    book_author表

    /*---------------------------models.py---------------------*/from django.db import models# Create your models here.class book(models.Model):    author=models.CharField(max_length=32)    price=models.IntegerField()    date=models.DateField()    title=models.CharField(max_length=100)    publish=models.ForeignKey("Publish",on_delete=models.CASCADE)    def __str__(self):        return self.titleclass Publish(models.Model):    name=models.CharField(max_length=100)    city=models.CharField(max_length=100)/*--------------------------views.py---------------------------*/def addbook(request):    #一对多    #法一由于绑定一对多的字段,比如publish,存到数据库中的字段名叫publish_id,所以我们可以直接给这个    #字段设定对应值    #book.objects.create(author="马尔克斯",price=88,date="2014-3-3",title="百年孤独",publish_id=2)    #法二    #<1>先获取要绑定的Publisher对象:    #pub_obj = Publish.objects.get(id=2)    #print("-------pub_obj:",pub_obj)    #<2>将 publish_id=2 改为  publish=pub_obj    #book.objects.create(author="马尔克斯",price=88,date="2014-1-3",title="霍乱时期的爱情",publish=pub_obj)    return HttpResponse("书籍信息添加成功")def select(request):    #法一 通过对象    book_obj=book.objects.get(title="童年")    #book_obj.publish是一个书籍对象对应的一个publish object ,数据类型是models下publish类的一条与name="童年"的publish_id相同的实例对象,    #可以通过调用对象属性查看相应信息    # print(book_obj.publish.name)    # print(book_obj.publish.city)    #需求查询吉林出版社出版的所有书籍    # pub_obj=Publish.objects.filter(name="吉林出版社")[0]    # print("pub_obj:",pub_obj)    # print(pub_obj.book_set.all().values("title","price"))    # 法二通过filter和values的双下滑线语法查询    # 需求:查询所有安徽人民出版社出版的书籍    # ret = book.objects.filter(publish__name="安徽人民出版社").values("title", "price")    # print("ret:", ret)    #需求:查询童年这本书出版社的名字    #ret=Publish.objects.filter(book__title="童年").values('name')    #ret=book.objects.filter(title="童年").values("publish__name")    #需求:查询出版社在北京的出版社出版的书籍名字    #ret=book.objects.filter(publish__city="北京").values("title")    #需求:查询在2014年上半年出版的书对应的出版社名字    ret=book.objects.filter(date__gt="2014-01-01",date__lt="2014-07-01").values("publish__name")    print("ret:", ret)    return render(request,"书籍修改成功")
    一对多增,删,改,查

    (3)多对多表的增、删、改、查

    /*-----------------------models.py---------------------------------*/from django.db import models# Create your models here.class book(models.Model):    #author=models.CharField(max_length=32)    price=models.IntegerField()    date=models.DateField()    title=models.CharField(max_length=100)    publish=models.ForeignKey("Publish",on_delete=models.CASCADE)    #author= models.ManyToManyField("Author")#自己创建中间表,不用ManyToManyField字段参数类型    def __str__(self):        return self.titleclass Publish(models.Model):    name=models.CharField(max_length=100)    city=models.CharField(max_length=100)    def __str__(self):        return self.nameclass Author(models.Model):    name=models.CharField(max_length=32)    age=models.IntegerField(default=20)    def __str__(self):        return self.nameclass Book_Author(models.Model):    book=models.ForeignKey("book",on_delete=models.CASCADE)    author=models.ForeignKey("Author",on_delete=models.CASCADE)/*---------------------------views.py---------------------------*/#创建多对多关系author= models.ManyToManyField("Author")(推荐)/*-----------------------------增--------------------------------*/#多对多(ManyToManyField()):    author1=Author.objects.get(id=1)    author2=Author.objects.filter(name='alvin')[0]    book=book.objects.get(id=1)    book.authors.add(author1,author2)    #等同于:    book.authors.add(*[author1,author2])    book.authors.remove(*[author1,author2])    #-------------------    book=models.book.objects.filter(id__gt=1)    authors=models.Author.objects.filter(id=1)[0]    authors.book_set.add(*book)    authors.book_set.remove(*book)    #-------------------    book.authors.add(1)    book.authors.remove(1)    authors.book_set.add(1)    authors.book_set.remove(1)#注意: 如果第三张表是通过models.ManyToManyField()自动创建的,那么绑定关系只有上面一种方式#     如果第三张表是自己创建的:     class Book_Author(models.Model):            author=models.ForeignKey("Author")            book=  models.ForeignKey("book")#     那么就还有一种方式:            author_obj=models.Author.objects.filter(id=2)[0]            book_obj  =models.book.objects.filter(id=3)[0]            s=models.Book_Author.objects.create(author_id=1,book_id=2)            s.save()            s=models.book_Author(author=author_obj,book_id=1)            s.save()/*--------------------------------删--------------------------------*/#多对多:remove()和clear()方法#正向    book_obj = models.book.objects.filter(id=1)#删除第三张表中和id=1关联的所有关联信息    book_obj.author.clear()        #清空与book中id=1 关联的所有数据    book.author.remove(2)  #可以为id    book.author.remove(*[1,2,3,4])     #可以为列表,前面加*#反向    author = models.Author.objects.filter(id=1)    author.book_set.clear() #清空id=1 关联的所有数据 /*-------------------------------查--------------------------------*/#多对多查询(ManyToManyField()):#ret=models.Book.objects.filter(title='Python').values('author__name')#print(ret)#ret=models.Book.objects.filter(author__name="alex").values('title')#print(ret)#ret=models.Author.objects.filter(book__title='Python').values('name','price')
    View Code

    (4)表操作总结

    0.一对多,外键一定是建在'多'的那张表1. 类代表数据库表2. 类的对象代指数据库的一行记录3. FK字段代指关联表中的一行数据(类的对象)4. 自动生成的第三章表中命名为FK_id的字段代表的是对应关联表的id5. ManyToMany字段,自动生成第三张表:依赖关联表对第三张表进行操作6.一对多: 正向查询用"FK字段",反向查询用"小写类名_set",跨表用双下划线7.多对多:正向查询用"M2M字段",其他同一对多,如果未自己创建第三章多对多关系表,无法直接用对象8.数据库获取数据.all  .filter 输出为[obj,obj],即一个个对象组成的列表.values     输出为[{},{}],即一个个字典组成的列表,字典中为所选字段的键值对.values_list 输出为[(),()],即一个个元组组成的列表,元组中为所选字段和对应的值
    View Code
    """book包含字段: id     price   date    title   publish_id(ForeignKey)     authors(ManyToManyField)"""    #1. 类代表数据库表    #2. 类的对象代指数据库的一行记录    #3. FK字段代指关联表中的一行数据(类的对象)    #4. 自动生成的第三章表中命名为FK_id的字段代表的是对应关联表的id    #5. ManyToMany字段,自动生成第三张表:依赖关联表对第三张表进行操作    #6. 正向查询用"FK字段",反向查询用"小写类名_set"    #<1> ret = book.objects.all()        #返回为QuerySet对象,对象由一个个book类的对象(即一条条记录)组成QuerySet列表        #< QuerySet[ < book: bookobject(1) >, < book: bookobject(2) >, < book: bookobject(3) >, < book: book object(4) >, < book: bookobject(5) >,        #< book: bookobject(6) >, < book: bookobject(7) >, < book: bookobject(8) >, < book: bookobject(9) >, < book: bookobject(10) >, < book: bookobject(11) >] >        #在models book 加入下面两句,返回为:        #def __str__(self):        #    return self.title        #
    ,
    ,
    ,
    ,
    , #
    ,
    ,
    ,
    ,
    ,
    ]> #<2> 对通过ret = book.objects.all()拿到的QuerySet进行循环遍历 # ret=book.objects.all() # for item in ret: # print(item.id,item.price,item.date,item.title,item.publish_id,item.publish.id) # #跨表 # print(item.publish.id,item.publish.name,item.publish.city) #<3> 删除 #pid=input("请输入出版社ID") #book.objects.filter(publish_id=pid).delete()#删除publish_id为对应输入id的book记录 #pname=input("请输入出版社名字") #book.objects.filter(publish__name=pname).delete()#删除出版社为输入出版社名发布的所有book记录 #<4> ret=book.objects.all().values("id","title") #返回QuerySet对象,对象由一个个所选字段组成的字典构成QuerySet列表 #ret: < QuerySet[{'id': 1, 'title': '战争与和平'}, {'id': 2, 'title': '百年孤独'}, {'id': 3, 'title': '巴黎圣母院'}, # {'id': 4,'title': '童年'}, {'id': 5, 'title': '霍乱时期的爱情'}, {'id': 6, 'title': '我们家的猫'}, {'id': 7, 'title': '在人间'}, # {'id': 8,'title': '我的大学'}, {'id': 9, 'title': '艰难时世'}, {'id': 10, 'title': '红与黑'}, {'id': 11, 'title': 'python程序设计教程'}] > #<5> ret=book.objects.all().values_list("id","title") #返回QuerySet对象,对象由一个个所选字段值组成的元祖构成QuerySet列表 #ret:
    View Code

     (5)聚合查询

    from django.db.models import Avg,Min,Sum,Max从整个查询集生成统计值。比如,你想要计算所有在售书的平均价钱。Django的查询语法提供了一种方式描述所有图书的集合。>>> Book.objects.all().aggregate(Avg('price')){
    'price__avg': 34.35}aggregate()子句的参数描述了我们想要计算的聚合值,在这个例子中,是Book模型中price字段的平均值aggregate()是QuerySet 的一个终止子句,意思是说,它返回一个包含一些键值对的字典。键的名称是聚合值的标识符,值是计算出来的聚合值。键的名称是按照字段和聚合函数的名称自动生成出来的。如果你想要为聚合值指定一个名称,可以向聚合子句提供它:>>> Book.objects.aggregate(average_price=Avg('price')){
    'average_price': 34.35}如果你也想知道所有图书价格的最大值和最小值,可以这样查询:>>> Book.objects.aggregate(Avg('price'), Max('price'), Min('price')){
    'price__avg': 34.35, 'price__max': Decimal('81.20'), 'price__min': Decimal('12.99')}
    aggregate(*args,**kwargs)

     (6)分组查询

    from django.db.models import Avg,Min,Sum,Max#必须导入上面聚类函数,否则会报错ret=book.objects.values("publish__name").annotate(Min('price'))    #
    annotate

     (7)F查询和Q查询

    # F 使用查询条件的值,专门取对象中某列值的操作    # from django.db.models import F    #让所有书的价格加10    # book.objects.values(price=F(price)+10)# Q 构建搜索条件    from django.db.models import Q    #1 Q对象(django.db.models.Q)可以对关键字参数进行封装,从而更好地应用多个查询    q1=models.Book.objects.filter(Q(title__startswith='P')).all()    print(q1)#[
    ,
    ] # 2、可以组合使用&,|操作符,当一个操作符是用于两个Q的对象,它产生一个新的Q对象。 Q(title__startswith='P') | Q(title__startswith='J') # 3、Q对象可以用~操作符放在前面表示否定,也可允许否定与不否定形式的组合 Q(title__startswith='P') | ~Q(pub_date__year=2005) # 4、应用范围: # Each lookup function that takes keyword-arguments (e.g. filter(), # exclude(), get()) can also be passed one or more Q objects as # positional (not-named) arguments. If you provide multiple Q object # arguments to a lookup function, the arguments will be “AND”ed # together. For example: Book.objects.get( Q(title__startswith='P'), Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)) ) #sql: # SELECT * from polls WHERE question LIKE 'P%' # AND (pub_date = '2005-05-02' OR pub_date = '2005-05-06') # import datetime # e=datetime.date(2005,5,6) #2005-05-06 # 5、Q对象可以与关键字参数查询一起使用,不过一定要把Q对象放在关键字参数查询的前面。 # 正确: Book.objects.get( Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)), title__startswith='P') # 错误: Book.objects.get( question__startswith='P', Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)))
    F查询和Q查询

     (8)QuerySet

    #惰性机制:#所谓惰性机制:Publisher.objects.all()或者.filter()等都只是返回了一个QuerySet(查询结#果集对象),它并不会马上执行sql,而是当调用QuerySet的时候才执行。#QuerySet特点:可迭代,可切片<1>Django的queryset是惰性的     Django的queryset对应于数据库的若干记录(row),通过可选的查询来过滤。例如,下面的代码会得到数据库中名字为‘Dave’的所有的人:person_set = Person.objects.filter(first_name="Dave")     上面的代码并没有运行任何的数据库查询。你可以使用person_set,给它加上一些过滤条件,或者将它传给某个函数,这些操作都不会发送给数据库。这是对的,因为数据库查询是显著影响web应用性能的因素之一。<2>要真正从数据库获得数据,你可以遍历queryset或者使用if queryset,总之你用到数据时就会执行sql.   为了验证这些,需要在settings里加入 LOGGING(验证方式)        obj=models.Book.objects.filter(id=3)        # for i in obj:        #     print(i)        # if obj:        #     print("ok")<3>queryset是具有cache的     当你遍历queryset时,所有匹配的记录会从数据库获取,然后转换成Django的model。这被称为执行(evaluation).这些model会保存在queryset内置的cache中,这样如果你再次遍历这个queryset,     你不需要重复运行通用的查询。        obj=models.Book.objects.filter(id=3)        # for i in obj:        #     print(i)                          ## models.Book.objects.filter(id=3).update(title="GO")                          ## obj_new=models.Book.objects.filter(id=3)        # for i in obj:        #     print(i)   #LOGGING只会打印一次<4> 简单的使用if语句进行判断也会完全执行整个queryset并且把数据放入cache,虽然你并不需要这些数据!为了避免这个,可以用exists()方法来检查是否有数据:            obj = Book.objects.filter(id=4)            #  exists()的检查可以避免数据放入queryset的cache。            if obj.exists():                print("hello world!")<5>当queryset非常巨大时,cache会成为问题     处理成千上万的记录时,将它们一次装入内存是很浪费的。更糟糕的是,巨大的queryset可能会锁住系统进程,让你的程序濒临崩溃。要避免在遍历数据的同时产生queryset cache,可以使用iterator()方法来获取数据,处理完数据就将其丢弃。        objs = Book.objects.all().iterator()        # iterator()可以一次只从数据库获取少量数据,这样可以节省内存        for obj in objs:            print(obj.name)        #BUT,再次遍历没有打印,因为迭代器已经在上一次遍历(next)到最后一次了,没得遍历了        for obj in objs:            print(obj.name)     #当然,使用iterator()方法来防止生成cache,意味着遍历同一个queryset时会重复执行查询。所以使用iterator()的时候要当心,确保你的代码在操作一个大的queryset时没有重复执行查询总结:    queryset的cache是用于减少程序对数据库的查询,在通常的使用下会保证只有在需要的时候才会查询数据库。使用exists()和iterator()方法可以优化程序对内存的使用。不过,由于它们并不会生成queryset cache,可能会造成额外的数据库查询。
    View Code

     (9)QuerySet对象的源码里的方法总结

    def all(self)    # 获取所有的数据对象def filter(self, *args, **kwargs)    # 条件查询    # 条件可以是:参数,字典,Qdef exclude(self, *args, **kwargs)    # 条件查询    # 条件可以是:参数,字典,Qdef select_related(self, *fields)     性能相关:表之间进行join连表操作,一次性获取关联的数据。     model.tb.objects.all().select_related()     model.tb.objects.all().select_related('外键字段')     model.tb.objects.all().select_related('外键字段__外键字段')def prefetch_related(self, *lookups)    性能相关:多表连表操作时速度会慢,使用其执行多次SQL查询在Python代码中实现连表操作。            # 获取所有用户表            # 获取用户类型表where id in (用户表中的查到的所有用户ID)            models.UserInfo.objects.prefetch_related('外键字段')            from django.db.models import Count, Case, When, IntegerField            Article.objects.annotate(                numviews=Count(Case(                    When(readership__what_time__lt=treshold, then=1),                    output_field=CharField(),                ))            )            students = Student.objects.all().annotate(num_excused_absences=models.Sum(                models.Case(                    models.When(absence__type='Excused', then=1),                default=0,                output_field=models.IntegerField()            )))def annotate(self, *args, **kwargs)    # 用于实现聚合group by查询    from django.db.models import Count, Avg, Max, Min, Sum    v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id'))    # SELECT u_id, COUNT(ui) AS `uid` FROM UserInfo GROUP BY u_id    v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id')).filter(uid__gt=1)    # SELECT u_id, COUNT(ui_id) AS `uid` FROM UserInfo GROUP BY u_id having count(u_id) > 1    v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id',distinct=True)).filter(uid__gt=1)    # SELECT u_id, COUNT( DISTINCT ui_id) AS `uid` FROM UserInfo GROUP BY u_id having count(u_id) > 1def distinct(self, *field_names)    # 用于distinct去重    models.UserInfo.objects.values('nid').distinct()    # select distinct nid from userinfo    注:只有在PostgreSQL中才能使用distinct进行去重def order_by(self, *field_names)    # 用于排序    models.UserInfo.objects.all().order_by('-id','age')def 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']) def reverse(self): # 倒序 models.UserInfo.objects.all().order_by('-nid').reverse() # 注:如果存在order_by,reverse则是倒序,如果多个排序则一一倒序 def defer(self, *fields): models.UserInfo.objects.defer('username','id') 或 models.UserInfo.objects.filter(...).defer('username','id') #映射中排除某列数据 def only(self, *fields): #仅取某个表中的数据 models.UserInfo.objects.only('username','id') 或 models.UserInfo.objects.filter(...).only('username','id') def using(self, alias): 指定使用的数据库,参数为别名(setting中的设置)################################################### PUBLIC METHODS THAT RETURN A QUERYSET SUBCLASS ###################################################def raw(self, raw_query, params=None, translations=None, using=None): # 执行原生SQL models.UserInfo.objects.raw('select * from userinfo') # 如果SQL是其他表时,必须将名字设置为当前UserInfo对象的主键列名 models.UserInfo.objects.raw('select id as nid from 其他表') # 为原生SQL设置参数 models.UserInfo.objects.raw('select id as nid from userinfo where nid>%s', params=[12,]) # 将获取的到列名转换为指定列名 name_map = {
    'first': 'first_name', 'last': 'last_name', 'bd': 'birth_date', 'pk': 'id'} Person.objects.raw('SELECT * FROM some_other_table', translations=name_map) # 指定数据库 models.UserInfo.objects.raw('select * from userinfo', using="default") ################### 原生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() # fetchall()/fetchmany(..)def values(self, *fields): # 获取每行数据为字典格式def values_list(self, *fields, **kwargs): # 获取每行数据为元祖def dates(self, field_name, kind, order='ASC'): # 根据时间进行某一部分进行去重查找并截取指定内容 # kind只能是:"year"(年), "month"(年-月), "day"(年-月-日) # order只能是:"ASC" "DESC" # 并获取转换后的时间 - year : 年-01-01 - month: 年-月-01 - day : 年-月-日 models.DatePlus.objects.dates('ctime','day','DESC')def datetimes(self, field_name, kind, order='ASC', tzinfo=None): # 根据时间进行某一部分进行去重查找并截取指定内容,将时间转换为指定时区时间 # kind只能是 "year", "month", "day", "hour", "minute", "second" # order只能是:"ASC" "DESC" # tzinfo时区对象 models.DDD.objects.datetimes('ctime','hour',tzinfo=pytz.UTC) models.DDD.objects.datetimes('ctime','hour',tzinfo=pytz.timezone('Asia/Shanghai')) """ pip3 install pytz import pytz pytz.all_timezones pytz.timezone(‘Asia/Shanghai’) """def none(self): # 空QuerySet对象##################################### METHODS THAT DO DATABASE QUERIES #####################################def aggregate(self, *args, **kwargs): # 聚合函数,获取字典类型聚合结果 from django.db.models import Count, Avg, Max, Min, Sum result = models.UserInfo.objects.aggregate(k=Count('u_id', distinct=True), n=Count('nid')) ===> {
    'k': 3, 'n': 4}def count(self): # 获取个数def get(self, *args, **kwargs): # 获取单个对象def create(self, **kwargs): # 创建对象def bulk_create(self, objs, batch_size=None): # 批量插入 # batch_size表示一次插入的个数 objs = [ models.DDD(name='r11'), models.DDD(name='r22') ] models.DDD.objects.bulk_create(objs, 10)def get_or_create(self, defaults=None, **kwargs): # 如果存在,则获取,否则,创建 # defaults 指定创建时,其他字段的值 obj, created = models.UserInfo.objects.get_or_create(username='root1', defaults={
    'email': '1111111','u_id': 2, 't_id': 2})def update_or_create(self, defaults=None, **kwargs): # 如果存在,则更新,否则,创建 # defaults 指定创建时或更新时的其他字段 obj, created = models.UserInfo.objects.update_or_create(username='root1', defaults={
    'email': '1111111','u_id': 2, 't_id': 1})def first(self): # 获取第一个def last(self): # 获取最后一个def in_bulk(self, id_list=None): # 根据主键ID进行查找 id_list = [11,21,31] models.DDD.objects.in_bulk(id_list)def delete(self): # 删除def update(self, **kwargs): # 更新def exists(self): # 是否有结果
    View Code

    (10)常用双下划线

    models.Tb1.objects.filter(id__lt=10, id__gt=1)   # 获取id大于1 且 小于10的值 models.Tb1.objects.filter(id__in=[11, 22, 33])   # 获取id等于11、22、33的数据models.Tb1.objects.exclude(id__in=[11, 22, 33])  # not in models.Tb1.objects.filter(name__contains="ven")models.Tb1.objects.filter(name__icontains="ven") # icontains大小写不敏感 models.Tb1.objects.filter(id__range=[1, 2])      # 范围bettwen and startswith,istartswith, endswith, iendswith 
    View Code

     (11)表的正反向查询

    1.一对多跨表查询:    (1)正向跨表查询    例1:查询书名为《巴黎圣母院》的出版社名    
    <法1:>
    通过对象进行正向跨表查询(obj.FK.跨表要查询的字段),注意book_obj.publish是指书籍对象对应的关联表中的publish对象,是Publish表中的一条记录 book_obj= book.objects.filter(title="巴黎圣母院").first() ret=book_obj.publish.name 注意.filter输出为[obj,obj...],即一个个对象组成的列表,后面不加.first(),直接取值会出错,可以遍历里面的对象取值 book_obj = book.objects.filter(title="巴黎圣母院") for item in book_obj: print(item.publish.name,item.publish.city)
    <法2:>
    通过PK加双下滑线进行正向跨表查询 ret=book.objects.filter(title="巴黎圣母院").values('publish__name','publish__city')#values里面用双下划线 补充ret=Publish.objects.filter(book__title='巴黎圣母院').values('name','city')#filter里面用双下滑线,这个是反向查询,及类名加双下滑线实现例子中的需求 print(ret) print(ret) (2)反向跨表查询 例1:查询北京出版社出版的所有书籍书名和价格
    <法1:>
    通过对象进行反向跨表查询 publish_obj=Publish.objects.filter(name='北京出版社')[0]#先拿到一个publish对象 ret=book.objects.filter(publish=publish_obj).values('title','price')#通过FK=publish对象进行筛选 print(ret)
    <法2:>
    :通过 小写表名_set进行反向查询 publish_obj = Publish.objects.filter(name='北京出版社')[0]#先拿到一个publish对象 print(publish_obj.book_set.all().values('title','price'))#通过book_set反向关联要查询的表
    <法3:>
    通过类名加双下滑线进行反向查询 ret=Publish.objects.filter(name='北京出版社').values('book__title','book__price') ret=book.objects.filter(publish__name='北京出版社').values('title','price')#补充,这个是通过正向查询,及PK加双下划线实现的例子中的需求 print(ret) 2.一对多查询练习 例1:查询在北京的所有出版社出过的书籍名称和价格 ret=Publish.objects.filter(city='北京').values('book__title','book__price') print(ret)
    View Code
    3.多对多跨表查询    类型1,通过many_to_many字段自动创建第3张表    (1)正向多对多跨表查询    例1:查询书籍《python程序设计教程》的所有作者姓名和年龄    
    <法1:>
    通过对象进行正向跨表查询 book_obj = book.objects.filter(title='python程序设计教程')[0] print(book_obj.author.all())#通过book_obj.MTM字段.all()拿到的是book对应的author对象组成的QuerySet集合
    author_set=book_obj.author.all() for item in author_set: print(item.name,item.age)
    <法2:>
    通过MTM字段加双下滑线进行正向跨表查询 author_ret_set=book.objects.filter(title='python程序设计教程').values('author__name','author__age') print(author_ret_set) (2)反向多对多跨表查询 例1:查询高尔基出过的所有书籍名称和价格
    <法1:>
    通过对象进行反向跨表查询 author_obj=Author.objects.filter(name='高尔基')[0] book_ret_set=book.objects.filter(author=author_obj).values('title','price') print(book_ret_set)
    <法2:>
    通过小写表名_set进行反向查询 author_obj = Author.objects.filter(name='高尔基')[0] book_set=author_obj.book_set.all() for item in book_set: print(item.title,item.price)
    <法3:>
    通过类名加双下滑线进行反向查询 book_ret_set=Author.objects.filter(name='高尔基').values('book__price','book__title') print(book_ret_set) 类型2,自己手动创建第3张表
    View Code

     

    >>>>>>>待续

    转载于:https://www.cnblogs.com/wuxunyan/p/9108587.html

    你可能感兴趣的文章
    Linux下Eclipse+CDT的搭建
    查看>>
    python的tab键补全
    查看>>
    DevOps系列——公司Docker测试,打版,发布实战
    查看>>
    SQLITE3 使用总结
    查看>>
    python3学习之md5加密
    查看>>
    spring中MessageSource的配置使用方法3--ResourceBundleMessa
    查看>>
    Python在同一位置刷新显示进度信息
    查看>>
    解决获取微信用户信息 48001错误
    查看>>
    js操作单选框
    查看>>
    说说内存可见性
    查看>>
    oracle的内存spa与pga
    查看>>
    百度发力智能终端 百加异军突起
    查看>>
    《TableStore最佳实践:轻松实现轨迹管理与地理围栏》
    查看>>
    网络基本功(四):细说路由(上)
    查看>>
    我的友情链接
    查看>>
    解决大数据难题 阿里云MaxCompute获科技大奖
    查看>>
    修复Mysql数据库
    查看>>
    Java基础学习第八天
    查看>>
    MySQL备份导致的waiting for global read lock
    查看>>
    javascriptEvent对象
    查看>>