Django-查到暈

ORM

一 ORM簡介

查詢數據層次圖解:若是操做mysql,ORM是在pymysq之上又進行了一層封裝python

  • MVC或者MTV框架中包括一個重要的部分,就是ORM,它實現了數據模型與數據庫的解耦,即數據模型的設計不須要依賴於特定的數據庫,經過簡單的配置就能夠輕鬆更換數據庫,這極大的減輕了開發人員的工做量,不須要面對因數據庫變動而致使的無效勞動
  • ORM是「對象-關係-映射」的簡稱。

#sql中的表                                                      

 #建立表:
     CREATE TABLE employee(                                     
                id INT PRIMARY KEY auto_increment ,                    
                name VARCHAR (20),                                      
                gender BIT default 1,                                  
                birthday DATA ,                                         
                department VARCHAR (20),                                
                salary DECIMAL (8,2) unsigned,                          
              );


  #sql中的表紀錄                                                  

  #添加一條表紀錄:                                                          
      INSERT employee (name,gender,birthday,salary,department)            
             VALUES   ("alex",1,"1985-12-12",8000,"保潔部");               

  #查詢一條表紀錄:                                                           
      SELECT * FROM employee WHERE age=24;                               

  #更新一條表紀錄:                                                           
      UPDATE employee SET birthday="1989-10-24" WHERE id=1;              

  #刪除一條表紀錄:                                                          
      DELETE FROM employee WHERE name="alex"                             





#python的類
class Employee(models.Model):
     id=models.AutoField(primary_key=True)
     name=models.CharField(max_length=32)
     gender=models.BooleanField()
     birthday=models.DateField()
     department=models.CharField(max_length=32)
     salary=models.DecimalField(max_digits=8,decimal_places=2)


 #python的類對象
      #添加一條表紀錄:
          emp=Employee(name="alex",gender=True,birthday="1985-12-12",epartment="保潔部")
          emp.save()
      #查詢一條表紀錄:
          Employee.objects.filter(age=24)
      #更新一條表紀錄:
          Employee.objects.filter(id=1).update(birthday="1989-10-24")
      #刪除一條表紀錄:
          Employee.objects.filter(name="alex").delete()

示例

二.單表操做

建立名爲book的app,在book下的models.py中建立模型:
mysql

from django.db import models

# Create your models here.
class Book(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=64)
    pub_data = models.DateField()
    price = models.DecimalField(max_digits=5, decimal_places=2)
    publish = models.CharField(max_length=12)
    def __str__(self):
        return self.name

每一個字段有一些特有的參數,例如,CharField須要max_length參數來指定VARCHAR數據庫字段的大小。還有一些適用於全部字段的通用參數。 這些參數在文檔中有詳細定義,這裏咱們只簡單介紹一些最經常使用的:git

經常使用字段ajax

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中提供驗證機制

    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)
        - 二進制類型

字段

經常使用參數:sql

(1)null
 
若是爲True,Django 將用NULL 來在數據庫中存儲空值。 默認值是 False.
 
(1)blank
 
若是爲True,該字段容許不填。默認爲False。
要注意,這與 null 不一樣。null純粹是數據庫範疇的,而 blank 是數據驗證範疇的。
若是一個字段的blank=True,表單的驗證將容許該字段是空值。若是字段的blank=False,該字段就是必填的。
 
(2)default
 
字段的默認值。能夠是一個值或者可調用對象。若是可調用 ,每有新對象被建立它都會被調用。
 
(3)primary_key
 
若是爲True,那麼這個字段就是模型的主鍵。若是你沒有指定任何一個字段的primary_key=True,
Django 就會自動添加一個IntegerField字段作爲主鍵,因此除非你想覆蓋默認的主鍵行爲,
不然不必設置任何一個字段的primary_key=True。
 
(4)unique
 
若是該值設置爲 True, 這個數據字段的值在整張表中必須是惟一的
 
(5)choices
由二元組組成的一個可迭代對象(例如,列表或元組),用來給字段提供選擇項。 若是設置了choices ,默認的表單將是一個選擇框而不是標準的文本框,<br>並且這個選擇框的選項就是choices 中的選項。

參數

元信息:數據庫

class UserInfo(models.Model):
        nid = models.AutoField(primary_key=True)
        username = models.CharField(max_length=32)
        class Meta:
            # 數據庫中生成的表名稱 默認 app名稱 + 下劃線 + 類名
            db_table = "table_name"

            # 聯合索引
            index_together = [
                ("pub_date", "deadline"),
            ]

            # 聯合惟一索引
            unique_together = (("driver", "restaurant"),)

            # admin中顯示的表名稱
            verbose_name

            # verbose_name加s
            verbose_name_plural

元信息

settings配置:django

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'lqz',
        'USER': 'root',
        'PASSWORD': '123456',
        'HOST': '127.0.0.1',
        'PORT': 3306,
        'ATOMIC_REQUEST': True,
        'OPTIONS': {
            "init_command": "SET storage_engine=MyISAM",
        }
    }
}
'''
'NAME':要鏈接的數據庫,鏈接前須要建立好
'USER':鏈接數據庫的用戶名
'PASSWORD':鏈接數據庫的密碼
'HOST':鏈接主機,默認本機
'PORT':端口 默認3306
'ATOMIC_REQUEST': True,
設置爲True統一個http請求對應的全部sql都放在一個事務中執行(要麼全部都成功,要麼全部都失敗)。
是全局性的配置, 若是要對某個http請求放水(而後自定義事務),能夠用non_atomic_requests修飾器 
'OPTIONS': {
             "init_command": "SET storage_engine=MyISAM",
            }
設置建立表的存儲引擎爲MyISAM,INNODB
'''

注意1:NAME即數據庫的名字,在mysql鏈接前該數據庫必須已經建立,而上面的sqlite數據庫下的db.sqlite3則是項目自動建立 USER和PASSWORD分別是數據庫的用戶名和密碼。設置完後,再啓動咱們的Django項目前,咱們須要激活咱們的mysql。而後,啓動項目,會報錯:no module named MySQLdb 。這是由於django默認你導入的驅動是MySQLdb,但是MySQLdb 對於py3有很大問題,因此咱們須要的驅動是PyMySQL 因此,咱們只須要找到項目名文件下的__init__,在裏面寫入:api

import pymysql
pymysql.install_as_MySQLdb()

最後經過兩條數據庫遷移命令便可在指定的數據庫中建立表 :session

python manage.py makemigrations
python manage.py migrate

注意2:確保配置文件中的INSTALLED_APPS中寫入咱們建立的app名稱app

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

注意3:若是報錯以下:

django.core.exceptions.ImproperlyConfigured: mysqlclient 1.3.3 or newer is required; you have 0.7.11.None

MySQLclient目前只支持到python3.4,所以若是使用的更高版本的python,須要修改以下:

經過查找路徑C:\Programs\Python\Python36-32\Lib\site-packages\Django-2.0-py3.6.egg\django\db\backends\mysql
這個路徑裏的文件把

if version < (1, 3, 3):
     raise ImproperlyConfigured("mysqlclient 1.3.3 or newer is required; you have %s" % Database.__version__)

註釋掉就能夠了

注意4: 若是想打印orm轉換過程當中的sql,須要在settings中進行以下配置:

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

增長,刪除字段:

刪除,直接註釋掉字段,執行數據庫遷移命令便可

  新增字段,在類裏直接新增字段,直接執行數據庫遷移命令會提示輸入默認值,此時須要設置

publish = models.CharField(max_length=12,default='人民出版社',null=True)

注意:

  1 數據庫遷移記錄都在 app01下的migrations裏

  2 使用showmigrations命令能夠查看沒有執行migrate的文件

  3 makemigrations是生成一個文件,migrate是將更改提交到數據量

添加表紀錄

方式1

# create方法的返回值book_obj就是插入book表中的python葵花寶典這本書籍紀錄對象
book_obj=Book.objects.create(title="python葵花寶典",state=True,price=100,publish="蘋果出版社",pub_date="2012-12-12")

方式2

book_obj=Book(title="python葵花寶典",state=True,price=100,publish="蘋果出版社",pub_date="2012-12-12")
book_obj.save()

查詢表紀錄

查詢api
<1> all():                  查詢全部結果
  
<2> filter(**kwargs):       它包含了與所給篩選條件相匹配的對象
  
<3> get(**kwargs):          返回與所給篩選條件相匹配的對象,返回結果有且只有一個,若是符合篩選條件的對象超過一個或者沒有都會拋出錯誤。
  
<4> exclude(**kwargs):      它包含了與所給篩選條件不匹配的對象
 
<5> order_by(*field):       對查詢結果排序('-id')
  
<6> reverse():              對查詢結果反向排序
  
<8> count():                返回數據庫中匹配查詢(QuerySet)的對象數量。
  
<9> first():                返回第一條記錄
  
<10> last():                返回最後一條記錄
  
<11> exists():              若是QuerySet包含數據,就返回True,不然返回False
 
<12> values(*field):        返回一個ValueQuerySet——一個特殊的QuerySet,運行後獲得的並非一系列
                            model的實例化對象,而是一個可迭代的字典序列
<13> values_list(*field):   它與values()很是類似,它返回的是一個元組序列,values返回的是一個字典序列
 
<14> distinct():            從返回結果中剔除重複紀錄
def index(request):
    # 添加表記錄++++++++++++++++++++++++++++++++++
    # 方式一
    # book=Book(name='紅樓夢',pub_data='2015-10-12',price=88,publish='老男孩出版社')
    # book.save()
    # 方式二
    # Book.objects.create(name='Python紅寶書',pub_data='2010-10-12',price=100,publish='人民出版社')
    # 查詢表記錄++++++++++++++++++++++++++++++++++
    # QUerySet數據類型(相似於一個列表,裏面放着一些對象)
    # 1 方法的返回值是什麼
    # 2 方法的調用者
    # (1) all方法 返回一個QuerySet對象
    # book_list=Book.objects.all()
    # print(book_list[1].name)
    # print(book_list)
    # for obj in book_list:
    #     print(obj.name)
    # (2)first last:調用者是queryset對象,返回值是對象
    # book=Book.objects.all().first()
    # book2=Book.objects.all().last()
    # print(book)
    # print(book2)
    # (3) filter  返回值是queryset對象(至關於where語句)
    # 能夠加多個過濾條件
    # book=Book.objects.filter(name='紅樓夢').first()
    # print(book)
    # (4)get方法 有且只有一個查詢結果纔有意義 返回值是一個對象
    # book=Book.objects.get(name='紅樓夢')
    # print(book)
    # 直接報錯
    # book = Book.objects.get(name='紅樓夢eee')
    # --------------最經常使用-----------------
    # (5)exclude 除了查詢以外的 返回值也是queryset
    # ret=Book.objects.exclude(name='紅樓夢')
    # print(ret)
    # (6)order_by(默認升序,加個- 就是降序),能夠多個過濾條件調用者是queryset返回值也是queryset
    # book_list=Book.objects.all().order_by('id')
    # book_list=Book.objects.all().order_by('-id','price')
    # print(book_list)
    # (7)count() 調用者是queryset,返回值是int
    # ret=Book.objects.all().count()
    # print(ret)
    # (8)exist()判斷是是否有值,不能傳參數,
    # ret=Book.objects.all().exists()
    # print(ret)
    # (9)values方法
    # 查詢全部書籍的名稱(裏面傳的值,前提是表有這個字段)也是queryset可是裏面放的是字典
    '''
    values原理
    temp=[]
    for obj in Book.objects.all():
        temp.append({'name':obj.name})
    '''
    # ret=Book.objects.all().values('name')
    # print(ret)
    # 不加.all()也能夠,調用是queryset返回值也是queryset
    # ret=Book.objects.values('price')
    # print(ret)
    # (10)value_list
    # ret=Book.objects.all().values_list('price','name')
    # print(ret)
    # (11) distinct  seletc * 的時候沒有意義
    # SELECT DISTINCT name from app01_book;
    # 沒有任何意義,不要這樣麼用
    # Book.objects.all().distinct()
    # ret=Book.objects.all().values('name').distinct()
    # print(ret)

    # 雙下劃線模糊查詢-----------------------
    # 查詢價格大於100的書
    # ret=Book.objects.filter(price__gt=100)
    # print(ret)
    # 查詢大於50小於100的書
    # ret=Book.objects.filter(price__gt=50,price__lt=100)
    # print(ret)
    # 查詢已紅樓開頭的書
    # ret=Book.objects.filter(name__startswith='紅樓')
    # print(ret)
    # 查詢包含‘紅’的書
    # ret= Book.objects.filter(name__contains='紅')
    # print(ret)
    # icontains  不區分大小寫
    # 價格在50,88,100 中的
    # ret=Book.objects.filter(price__in=[50,88,100])
    # print(ret)
    # 出版日期在2018年的
    # ret=Book.objects.filter(pub_data__year=2015,pub_data__month=2)
    # print(ret)
    # 刪除,修改------------------------
    # delete:調用者能夠是queryset也能夠是model對象
    # 刪除價格爲188的書有返回值 (1, {'app01.Book': 1}) 刪除的個數,那張表,記錄數
    # ret=Book.objects.filter(price=188).delete()
    # print(ret)
    # ret=Book.objects.filter(price=100).first().delete()
    # print(ret)

    # 修改 update只能queryset來調用 返回值爲int
    # ret=Book.objects.filter(name='紅樓夢1').update(name='紅樓夢')
    # print(ret)
    # 報錯
    # Book.objects.filter(name='紅樓夢').first().update(name='紅樓夢1')

    # ret=Book.objects.filter(name='紅樓夢1').first()
    # print(ret.delete())
    # aa=Publish.objects.filter(name='人民出版社')
    # print(type(aa))
    # aa.delete()

    return HttpResponse('ok')

測試數據

基於雙下劃線的模糊查詢 

Book.objects.filter(price__in=[100,200,300])
Book.objects.filter(price__gt=100)
Book.objects.filter(price__lt=100)
Book.objects.filter(price__gte=100)
Book.objects.filter(price__lte=100)
Book.objects.filter(price__range=[100,200])
Book.objects.filter(title__contains="python")
Book.objects.filter(title__icontains="python")
Book.objects.filter(title__startswith="py")
Book.objects.filter(pub_date__year=2012)

刪除表紀錄

刪除方法就是 delete()。它運行時當即刪除對象而不返回任何值。例如:

model_obj.delete()

你也能夠一次性刪除多個對象。每一個 QuerySet 都有一個 delete() 方法,它一次性刪除 QuerySet 中全部的對象。

例如,下面的代碼將刪除 pub_date 是2005年的 Entry 對象:

Entry.objects.filter(pub_date__year=2005).delete()

在 Django 刪除對象時,會模仿 SQL 約束 ON DELETE CASCADE 的行爲,換句話說,刪除一個對象時也會刪除與它相關聯的外鍵對象。例如:

b = Blog.objects.get(pk=1)
# This will delete the Blog and all of its Entry objects.
b.delete()

要注意的是: delete() 方法是 QuerySet 上的方法,但並不適用於 Manager 自己。這是一種保護機制,是爲了不意外地調用 Entry.objects.delete() 方法致使 全部的 記錄被誤刪除。若是你確認要刪除全部的對象,那麼你必須顯式地調用:

Entry.objects.all().delete() 

若是不想級聯刪除,能夠設置爲:

pubHouse = models.ForeignKey(to='Publisher', on_delete=models.SET_NULL, blank=True, null=True)

修改表紀錄

Book.objects.filter(title__startswith="py").update(price=120)

此外,update()方法對於任何結果集(QuerySet)均有效,這意味着你能夠同時更新多條記錄update()方法會返回一個整型數值,表示受影響的記錄條數。

三 在Python腳本中調用Django環境

import os
if __name__ == '__main__':
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "untitled15.settings")
    import django
    django.setup()

    from app01 import models

    books = models.Book.objects.all()
    print(books)

四 Django終端打印SQL語句

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

五.Foreignkey,onetoone,manytomany表關係

1..Foreignkey:外鍵類型在ORM中用來表示外鍵關聯關係,通常把ForeignKey字段設置在 '一對多'中'多'的一方。

ForeignKey能夠和其餘表作關聯關係同時也能夠和自身作關聯關係。

字段參數:

to

設置要關聯的表

to_field

設置要關聯的表的字段

on_delete

當刪除關聯表中的數據時,當前表與其關聯的行的行爲。

models.CASCADE

刪除關聯數據,與之關聯也刪除

db_constraint

是否在數據庫中建立外鍵約束,默認爲True。

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)
    )

OneToOneField:一對一字段。

一般一對一字段用來擴展已有字段。(通俗的說就是一我的的全部信息不是放在一張表裏面的,簡單的信息一張表,隱私的信息另外一張表,之間經過一對一外鍵關聯)

to

設置要關聯的表。

to_field

設置要關聯的字段。

on_delete

當刪除關聯表中的數據時,當前表與其關聯的行的行爲。(參考上面的例子)

"關聯管理器"是在一對多或者多對多的關聯上下文中使用的管理器。

它存在於下面兩種狀況:

  1. 外鍵關係的反向查詢
  2. 多對多關聯關係

簡單來講就是在多對多表關係而且這一張多對多的關係表是有Django自動幫你建的狀況下,下面的方法纔可以使用。

方法

create()

建立一個關聯對象,並自動寫入數據庫,且在第三張雙方的關聯表中自動新建上雙方對應關係。

models.Author.objects.first().book_set.create(title="偷塔祕籍")
上面這一句幹了哪些事兒:
1.由做者表中的一個對象跨到書籍比表
2.新增名爲偷塔祕籍的書籍並保存
3.到做者與書籍的第三張表中新增二者之間的多對多關係並保存

add()

把指定的model對象添加到第三張關聯表中。

添加對象

>>> author_objs = models.Author.objects.filter(id__lt=3)
>>> models.Book.objects.first().authors.add(*author_objs)

添加id

>>> models.Book.objects.first().authors.add(*[1, 2])

set()

更新某個對象在第三張表中的關聯對象。不一樣於上面的add是添加,set至關於重置

>>> book_obj = models.Book.objects.first()
>>> book_obj.authors.set([2, 3])

remove()

從關聯對象集中移除執行的model對象(移除對象在第三張表中與某個關聯對象的關係)

>>> book_obj = models.Book.objects.first()
>>> book_obj.authors.remove(3)

clear()

從關聯對象集中移除一切對象。(移除全部與對象相關的關係信息)

>>> book_obj = models.Book.objects.first()
>>> book_obj.authors.clear()

注意:

對於ForeignKey對象,clear()和remove()方法僅在null=True時存在。

舉個例子:

ForeignKey字段沒設置null=True時,

class Book(models.Model):
    title = models.CharField(max_length=32)
    publisher = models.ForeignKey(to=Publisher)

沒有clear()和remove()方法:

>>> models.Publisher.objects.first().book_set.clear()
Traceback (most recent call last):
  File "<input>", line 1, in <module>
AttributeError: 'RelatedManager' object has no attribute 'clear'

當ForeignKey字段設置null=True時,

class Book(models.Model):
    name = models.CharField(max_length=32)
    publisher = models.ForeignKey(to=Class, null=True)

此時就有clear()和remove()方法:

>>> models.Publisher.objects.first().book_set.clear()

再次強調:

  1. 對於全部類型的關聯字段,add()、create()、remove()和clear(),set()都會立刻更新數據庫。換句話說,在關聯的任何一端,都不須要再調用save()方法。

六.QuerySet數據的基本13個方法:

返回QuerySet對象的方法有
all()

filter()

exclude()

order_by()

reverse()

distinct()

特殊的QuerySet
values()       返回一個可迭代的字典序列

values_list() 返回一個可迭代的元祖序列

返回具體對象的
get()

first()

last()

返回布爾值的方法有:
exists()

返回數字的方法有
count()

詳細解釋:

操做下面的操做以前,咱們實現建立好了數據表,這裏主要演示下面的操做,再也不細講建立準備過程

<1> all(): 查詢全部結果

**<2> filter(**kwargs): 它包含了與所給篩選條件相匹配的對象**

**<3> get(**kwargs): 返回與所給篩選條件相匹配的對象,返回結果有且只有一個,若是符合篩選條件的對象超過一個或者沒有都會拋出錯誤。**

**<4> exclude(**kwargs): 它包含了與所給篩選條件不匹配的對象**

<5> values(*field): 返回一個ValueQuerySet——一個特殊的QuerySet,運行後獲得的並非一系列model的實例化對象,而是一個可迭代的字典序列

<6> values_list(*field): 它與values()很是類似,它返回的是一個元組序列,values返回的是一個字典序列

<7> order_by(*field): 對查詢結果排序

<8> reverse(): 對查詢結果反向排序,請注意reverse()一般只能在具備已定義順序的QuerySet上調用(在model類的Meta中指定ordering或調用order_by()方法)。

<9> distinct(): 從返回結果中剔除重複紀錄(若是你查詢跨越多個表,可能在計算QuerySet時獲得重複的結果。此時可使用distinct(),注意只有在PostgreSQL中支持按字段去重。)

<10> count(): 返回數據庫中匹配查詢(QuerySet)的對象數量。

<11> first(): 返回第一條記錄

<12> last(): 返回最後一條記錄

<13> exists(): 若是QuerySet包含數據,就返回True,不然返回False

七.基於對象的跨表查詢:

一對多查詢(publish與book)

正向查詢(按字段:publish)

# 查詢主鍵爲1的書籍的出版社所在的城市
book_obj=Book.objects.filter(pk=1).first()
# book_obj.publish 是主鍵爲1的書籍對象關聯的出版社對象
print(book_obj.publish.city)

反向查詢(按表名:book_set)

publish=Publish.objects.get(name="蘋果出版社")
#publish.book_set.all() : 與蘋果出版社關聯的全部書籍對象集合
book_list=publish.book_set.all()    
for book_obj in book_list:
       print(book_obj.title)
# 一對多正向查詢
    book=Book.objects.filter(name='紅樓夢').first()
    print(book.publish)#與這本書關聯的出版社對象
    print(book.publish.name)
    # 一對多反向查詢
    # 人民出版社出版過的書籍名稱
    pub=Publish.objects.filter(name='人民出版社').first()
    ret=pub.book_set.all()
    print(ret)
一對一查詢(Author 與 AuthorDetail)

正向查詢(按字段:authorDetail):

egon=Author.objects.filter(name="egon").first()
print(egon.authorDetail.telephone)

反向查詢(按表名:author):

# 查詢全部住址在北京的做者的姓名
 
authorDetail_list=AuthorDetail.objects.filter(addr="beijing")
for obj in authorDetail_list:
     print(obj.author.name)
# 一對一正向查詢
    # lqz的手機號
    lqz=Author.objects.filter(name='lqz').first()
    tel=lqz.author_detail.telephone
    print(tel)
    # 一對一反向查詢
    # 地址在北京的做者姓名
    author_detail=AuthorDatail.objects.filter(addr='北京').first()
    name=author_detail.author.name
    print(name)
多對多查詢 (Author 與 Book)

正向查詢(按字段:authors):

# 眉全部做者的名字以及手機號
 
book_obj=Book.objects.filter(title="眉").first()
authors=book_obj.authors.all()
for author_obj in authors:
     print(author_obj.name,author_obj.authorDetail.telephone)

反向查詢(按表名:book_set):

# 查詢egon出過的全部書籍的名字
 
    author_obj=Author.objects.get(name="egon")
    book_list=author_obj.book_set.all()        #與egon做者相關的全部書籍
    for book_obj in book_list:
        print(book_obj.title)
# 正向查詢----查詢紅樓夢全部做者名稱
    book=Book.objects.filter(name='紅樓夢').first()
    ret=book.authors.all()
    print(ret)
    for auth in ret:
        print(auth.name)
    # 反向查詢 查詢lqz這個做者寫的全部書
    author=Author.objects.filter(name='lqz').first()
    ret=author.book_set.all()
    print(ret)

注意:

你能夠經過在 ForeignKey() 和ManyToManyField的定義中設置 related_name 的值來覆寫 FOO_set 的名稱。例如,若是 Article model 中作一下更改:

publish = ForeignKey(Book, related_name='bookList')

那麼接下來就會如咱們看到這般:

# 查詢 人民出版社出版過的全部書籍
 
publish=Publish.objects.get(name="人民出版社")
book_list=publish.bookList.all()  # 與人民出版社關聯的全部書籍對象集合

八.基於雙下劃線的跨表查詢

Django 還提供了一種直觀而高效的方式在查詢(lookups)中表示關聯關係,它能自動確認 SQL JOIN 聯繫。要作跨關係查詢,就使用兩個下劃線來連接模型(model)間關聯字段的名稱,直到最終連接到你想要的model 爲止。

'''
    正向查詢按字段,反向查詢按表名小寫用來告訴ORM引擎join哪張表
'''
一對多查詢
# 練習:  查詢蘋果出版社出版過的全部書籍的名字與價格(一對多)

    # 正向查詢 按字段:publish

    queryResult=Book.objects
            .filter(publish__name="蘋果出版社")
            .values_list("title","price")

    # 反向查詢 按表名:book

    queryResult=Publish.objects
              .filter(name="蘋果出版社")
              .values_list("book__title","book__price")
查詢的本質同樣,就是select from的表不同
# 正向查詢按字段,反向查詢按表名小寫
    # 查詢紅樓夢這本書出版社的名字
    # select * from app01_book inner join app01_publish
    # on app01_book.publish_id=app01_publish.nid
    ret=Book.objects.filter(name='紅樓夢').values('publish__name')
    print(ret)
    ret=Publish.objects.filter(book__name='紅樓夢').values('name')
    print(ret)
多對多查詢
# 練習: 查詢alex出過的全部書籍的名字(多對多)

    # 正向查詢 按字段:authors:
    queryResult=Book.objects
            .filter(authors__name="yuan")
            .values_list("title")

    # 反向查詢 按表名:book
    queryResult=Author.objects
              .filter(name="yuan")
              .values_list("book__title","book__price")
# 正向查詢按字段,反向查詢按表名小寫
    # 查詢紅樓夢這本書出版社的名字
    # select * from app01_book inner join app01_publish
    # on app01_book.publish_id=app01_publish.nid
    ret=Book.objects.filter(name='紅樓夢').values('publish__name')
    print(ret)
    ret=Publish.objects.filter(book__name='紅樓夢').values('name')
    print(ret)
    # sql 語句就是from的表不同
    # -------多對多正向查詢
    # 查詢紅樓夢全部的做者
    ret=Book.objects.filter(name='紅樓夢').values('authors__name')
    print(ret)
    # ---多對多反向查詢
    ret=Author.objects.filter(book__name='紅樓夢').values('name')
    ret=Author.objects.filter(book__name='紅樓夢').values('name','author_detail__addr')
    print(ret)
一對一查詢
# 查詢alex的手機號
    
    # 正向查詢
    ret=Author.objects.filter(name="alex").values("authordetail__telephone")

    # 反向查詢
    ret=AuthorDetail.objects.filter(author__name="alex").values("telephone")
# 查詢lqz的手機號
    # 正向查
    ret=Author.objects.filter(name='lqz').values('author_detail__telephone')
    print(ret)
    # 反向查
    ret= AuthorDatail.objects.filter(author__name='lqz').values('telephone')
    print(ret)
# 練習: 查詢人民出版社出版過的全部書籍的名字以及做者的姓名


    # 正向查詢
    queryResult=Book.objects
            .filter(publish__name="人民出版社")
            .values_list("title","authors__name")
    # 反向查詢
    queryResult=Publish.objects
              .filter(name="人民出版社")
              .values_list("book__title","book__authors__age","book__authors__name")


# 練習: 手機號以151開頭的做者出版過的全部書籍名稱以及出版社名稱


    # 方式1:
    queryResult=Book.objects
            .filter(authors__authorDetail__telephone__regex="151")
            .values_list("title","publish__name")
    # 方式2:    
    ret=Author.objects
              .filter(authordetail__telephone__startswith="151")
              .values("book__title","book__publish__name")
              
  # ----進階練習,連續跨表
    # 查詢手機號以33開頭的做者出版過的書籍名稱以及書籍出版社名稱
    # author_datail author book publish
    # 基於authorDatail表
    ret=AuthorDatail.objects.filter(telephone__startswith='33').values('author__book__name','author__book__publish__name')
    print(ret)
    # 基於Author表
    ret=Author.objects.filter(author_detail__telephone__startswith=33).values('book__name','book__publish__name')
    print(ret)
    # 基於Book表
    ret=Book.objects.filter(authors__author_detail__telephone__startswith='33').values('name','publish__name')
    print(ret)
    # 基於Publish表
    ret=Publish.objects.filter(book__authors__author_detail__telephone__startswith='33').values('book__name','name')
    print(ret)
publish = ForeignKey(Blog, related_name='bookList')
# 練習: 查詢人民出版社出版過的全部書籍的名字與價格(一對多)

# 反向查詢 再也不按表名:book,而是related_name:bookList


    queryResult=Publish.objects
              .filter(name="人民出版社")
              .values_list("bookList__title","bookList__price")

九.聚合查詢與分組查詢

聚合

aggregate(*args, **kwargs)

# 計算全部圖書的平均價格
 from django.db.models import Avg
 Book.objects.all().aggregate(Avg('price'))
#{'price__avg': 34.35}

aggregate()QuerySet` 的一個終止子句,意思是說,它返回一個包含一些鍵值對的字典。鍵的名稱是聚合值的標識符,值是計算出來的聚合值。鍵的名稱是按照字段和聚合函數的名稱自動生成出來的。若是你想要爲聚合值指定一個名稱,能夠向聚合子句提供它。

Book.objects.aggregate(average_price=Avg('price'))
#{'average_price': 34.35}

若是你但願生成不止一個聚合,你能夠向aggregate()子句中添加另外一個參數。因此,若是你也想知道全部圖書價格的最大值和最小值,能夠這樣查詢:

from django.db.models import Avg, Max, Min
Book.objects.aggregate(Avg('price'), Max('price'), Min('price'))
#{'price__avg': 34.35, 'price__max': Decimal('81.20'), 'price__min': Decimal('12.99')}
# 查詢全部書籍的平均價格
    from django.db.models import Avg,Count,Max,Min
    ret=Book.objects.all().aggregate(Avg('price'))
    # {'price__avg': 202.896}
    # 能夠更名字
    ret=Book.objects.all().aggregate(avg_price=Avg('price'))
    # 統計平均價格和最大價格
    ret=Book.objects.all().aggregate(avg_price=Avg('price'),max_price=Max('price'))
    # 統計最小价格
    ret = Book.objects.all().aggregate(avg_price=Avg('price'), min_price=Min('price'))
    # 統計個數和平均價格
    ret = Book.objects.all().aggregate(avg_price=Avg('price'), max_price=Max('price'),count=Count('price'))
    ret = Book.objects.all().aggregate(avg_price=Avg('price'), max_price=Max('price'),count=Count('nid'))
    print(ret)
分組

annotate()爲調用的QuerySet中每個對象都生成一個獨立的統計值(統計方法用聚合函數)。

總結 :跨表分組查詢本質就是將關聯表join成一張表,再按單表的思路進行分組查詢。 

練習:統計每一本書做者個數
from django.db.models import Avg, Max, Sum, Min, Max, Count
book_list = models.Book.objects.all().annotate(author_num=Count("authors"))
for book in book_list:
     print(book.name)
     print(book.author_num)
book_list = models.Book.objects.all().annotate(author_num=Count("authors")).values('name','author_num')
print(book_list)

練習:統計每個出版社的最便宜的書

publishList=Publish.objects.annotate(MinPrice=Min("book__price"))
for publish_obj in publishList:
    print(publish_obj.name,publish_obj.MinPrice)

annotate的返回值是querySet,若是不想遍歷對象,能夠用上valuelist:

queryResult= Publish.objects.annotate(MinPrice=Min("book__price")).values_list("name","MinPrice")
print(queryResult)

練習:統計每一本以py開頭的書籍的做者個數:

queryResult=Book.objects.filter(title__startswith="Py").annotate(num_authors=Count('authors'))

練習:統計不止一個做者的圖書:(做者數量大於一)

ret=models.Book.objects.annotate(author_num=Count("authors")).filter(author_num__gt=1).values('name','author_num')
print(ret)

練習:根據一本圖書做者數量的多少對查詢集 QuerySet進行排序:

Book.objects.annotate(num_authors=Count('authors')).order_by('num_authors')

練習:查詢各個做者出的書的總價格:

ret=models.Author.objects.annotate(sum_price=Sum("book__price")).values("name", "sum_price")
print(ret)

練習:查詢每一個出版社的名稱和書籍個數

ret=models.Publish.objects.all().annotate(c=Count('book__name')).values('name','c')
print(ret)
# ————————————單表下的分組查詢
    '''
    查詢每個部門名稱以及對應的員工數
    emp:
    id  name age   salary    dep
  alex  12   2000     銷售部
  egon  22   3000     人事部
  wen   22   5000     人事部
    '''
    # select count(id) from emp group by dep
    # 示例一:查詢每個部門的名稱,以及平均薪水
    # select dep,Avg(salary) from app01_emp group by dep
    from django.db.models import Avg, Count, Max, Min
    ret=Emp.objects.values('dep').annotate(Avg('salary'))
    # 從新命名
    ret=Emp.objects.values('dep').annotate(avg_salary=Avg('salary'))
    print(ret)
    # ---*******單表分組查詢ORM總結:表名.objects.values('group by 的字段').annotate(聚合函數('統計的字段'))
    # 示例2 查詢每一個省份對應的員工數
    ret=Emp.objects.values('province').annotate(Count('id'))
    ret=Emp.objects.values('province').annotate(c=Count('id'))
    print(ret)
    # 補充知識點:
    ret=Emp.objects.all()
    # select * from emp
    ret=Emp.objects.values('name')
    # select name from emp
    # ****單表下,按照id進行分組是沒有任何意義的
    ret=Emp.objects.all().annotate(Avg('salary'))
    print(ret)
    # ******多表分組查詢
    # 查詢每個出版社出版的書籍個數
    ret=Book.objects.values('publish_id').annotate(Count('nid'))
    print(ret)
    # 查詢每一個出版社的名稱以及出版社書的個數(先join在跨表分組)
    # 正向
    ret=Publish.objects.values('name').annotate(Count('book__name'))
    ret=Publish.objects.values('nid').annotate(c=Count('book__name')).values('name','c')
    print(ret)
    # 反向
    ret=Book.objects.values('publish__name').annotate(Count('name'))
    ret=Book.objects.values('publish__name').annotate(c=Count('name')).values('publish__name','c')
    print(ret)
    # 查詢每一個做者的名字,以及出版過書籍的最高價格
    ret=Author.objects.values('pk').annotate(c=Max('book__price')).values('name','c')
    print(ret)
    # 跨表查詢的模型:每個後表模型.objects.value('pk').annotate(聚合函數('關聯表__統計字段')).values()

    # 查詢每個書籍的名稱,以及對應的做者個數
    ret=Book.objects.values('pk').annotate(c=Count('authors__name')).values('name','c')
    print(ret)
    # 統計不止一個做者的圖書
    ret=Book.objects.values('pk').annotate(c=Count('authors__name')).filter(c__gt=1).values('name','c')
    print(ret)

十. F查詢與Q查詢

F查詢

在上面全部的例子中,咱們構造的過濾器都只是將字段值與某個常量作比較。若是咱們要對兩個字段的值作比較,那該怎麼作呢?

Django 提供 F() 來作這樣的比較。F() 的實例能夠在查詢中引用字段,來比較同一個 model 實例中兩個不一樣字段的值。

# 查詢評論數大於收藏數的書籍
 from django.db.models import F
 Book.objects.filter(commnetNum__lt=F('keepNum'))

Django 支持 F() 對象之間以及 F() 對象和常數之間的加減乘除和取模的操做。

# 查詢評論數大於收藏數2倍的書籍
Book.objects.filter(commnetNum__lt=F('keepNum')*2)

修改操做也可使用F函數,好比將每一本書的價格提升30元:

Book.objects.all().update(price=F("price")+30) 
Q查詢

filter() 等方法中的關鍵字參數查詢都是一塊兒進行「AND」 的。 若是你須要執行更復雜的查詢(例如OR 語句),你可使用Q 對象

from django.db.models import Q
Q(title__startswith='Py')

Q 對象可使用&| 操做符組合起來。當一個操做符在兩個Q 對象上使用時,它產生一個新的Q 對象。

bookList=Book.objects.filter(Q(authors__name="yuan")|Q(authors__name="egon"))

等同於下面的SQL WHERE 子句:

WHERE name ="yuan" OR name ="egon"

你能夠組合&| 操做符以及使用括號進行分組來編寫任意複雜的Q 對象。同時,Q 對象可使用~ 操做符取反,這容許組合正常的查詢和取反(NOT) 查詢:

查詢函數能夠混合使用Q 對象和關鍵字參數。全部提供給查詢函數的參數(關鍵字參數或Q 對象)都將"AND」在一塊兒。可是,若是出現Q 對象,它必須位於全部關鍵字參數的前面。例如:

bookList=Book.objects.filter(Q(publishDate__year=2016) | Q(publishDate__year=2017), title__icontains="python")
# 查詢評論數大於閱讀數的書籍
    from django.db.models import F,Q
    # select * from book where commit_num>read_num;
    # 這樣確定是不行的
    # Book.objects.filter(commit_num__gt=read_num)
    ret=Book.objects.filter(commit_num__gt=F('reat_num'))
    print(ret)
    # 把全部書籍的價格加10
    Book.objects.all().update(price=F('price')+10)
    # ----Q函數,描述一個與,或,非的關係
    # 查詢名字叫紅樓夢或者價格大於100的書
    ret=Book.objects.filter(Q(name='紅樓夢')|Q(price__gt=100))
    print(ret)
    # 查詢名字叫紅樓夢和價格大於100的書
    ret = Book.objects.filter(Q(name='紅樓夢') & Q(price__gt=100))
    print(ret)
    # # 等同於
    ret2=Book.objects.filter(name='紅樓夢',price__gt=100)
    print(ret2)
    # 也能夠Q套Q
    # 查詢名字叫紅樓夢和價格大於100  或者 nid大於2
    ret=Book.objects.filter((Q(name='紅樓夢') & Q(price__gt=100))|Q(nid__gt=2))
    print(ret)
    # ----非
    ret=Book.objects.filter(~Q(name='紅樓夢'))
    print(ret)
    # Q和鍵值對聯合使用,可是鍵值對必須放在Q的後面(描述的是一個且的關係)
    # 查詢名字不是紅樓夢,而且價格大於100的書
    ret=Book.objects.filter(~Q(name='紅樓夢'),price__gt=100)
    print(ret)

十一.事務

事務的定義:將多個sql語句操做變成原子性操做,要麼同時成功,有一個失敗則裏面回滾到原來的狀態,保證數據的完整性和一致性(NoSQL數據庫對於事務則是部分支持)

# 事務
    # 買一本 跟老男孩學Linux 書
    # 在數據庫層面要作的事兒
    # 1. 建立一條訂單數據
    # 2. 去產品表 將賣出數+1, 庫存數-1
    from django.db.models import F
    from django.db import transaction
    # 開啓事務處理
    try:
        with transaction.atomic():
            # 建立一條訂單數據
            models.Order.objects.create(num="110110111", product_id=1, count=1)
            # 能執行成功
            models.Product.objects.filter(id=1).update(kucun=F("kucun")-1, maichu=F("maichu")+1)
    except Exception as e:
        print(e)

十二.QuerySet方法優化比較與優化操做

幾個比較重要的方法:

update()與save()的區別

二者都是對數據的修改保存操做,可是save()函數是將數據列的所有數據項所有從新寫一遍,而update()則是針對修改的項進行鍼對的更新效率高耗時少

因此之後對數據的修改保存用update()

select_related和prefetch_related

def select_related(self, *fields)
    性能相關:表之間進行join連表操做,一次性獲取關聯的數據。

    總結:
    1. select_related主要針一對一和多對一關係進行優化。
    2. select_related使用SQL的JOIN語句進行優化,經過減小SQL查詢的次數來進行優化、提升性能。

def prefetch_related(self, *lookups)
    性能相關:多表連表操做時速度會慢,使用其執行屢次SQL查詢在Python代碼中實現連表操做。

    總結:
    1. 對於多對多字段(ManyToManyField)和一對多字段,可使用prefetch_related()來進行優化。
    2. prefetch_related()的優化方式是分別查詢每一個表,而後用Python處理他們之間的關係。

bulk_create批量插入數據

要求:一次性插入多條數據

data = ["".join([str(random.randint(65, 99)) for i in range(4)]) for j in range(100)]
obj_list = [models.A(name=i) for i in data]
models.A.objects.bulk_create(obj_list)

defer和only

defer('id','name'):取出對象,字段除了id和name都有
only('id','name'):取的對象,只有id和name
若是點,依然能點出其它列,可是不要點了,由於取沒有的列,會再次查詢數據庫

ret=models.Author.objects.only('nid')
    for i in ret:
        # 查詢不在的字段,會再次查詢數據庫,形成數據庫壓力大
        print(i.name)
原生SQL語句

條件假設:就拿博客園舉例,咱們寫的博客並非按照年月日來分檔,而是按照年月來分的,而咱們的DateField時間格式是年月日形式,也就是說咱們須要對從數據庫拿到的時間格式的數據再進行一次處理拿到咱們想要的時間格式,這樣的需求,Django是沒有給咱們提供方法的,須要咱們本身去寫處理語句了

extra
# 在QuerySet的基礎上繼續執行子語句
# extra(self, select=None, where=None, params=None, tables=None, order_by=None, select_params=None)

# select和select_params是一組,where和params是一組,tables用來設置from哪一個表
# 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'])

舉個例子:
models.UserInfo.objects.extra(
                    select={'newid':'select count(1) from app01_usertype where id>%s'},
                    select_params=[1,],
                    where = ['age>%s'],
                    params=[18,],
                    order_by=['-age'],
                    tables=['app01_usertype']
                )
                """
                select 
                    app01_userinfo.id,
                    (select count(1) from app01_usertype where id>1) as newid
                from app01_userinfo,app01_usertype
                where 
                    app01_userinfo.age > 18
                order by 
                    app01_userinfo.age desc
                """


# 執行原生SQL
# 更高靈活度的方式執行原生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()
QuerySet方法大全
##################################################################
# PUBLIC METHODS THAT ALTER ATTRIBUTES AND RETURN A NEW QUERYSET #
##################################################################

def all(self)
    # 獲取全部的數據對象

def filter(self, *args, **kwargs)
    # 條件查詢
    # 條件能夠是:參數,字典,Q

def exclude(self, *args, **kwargs)
    # 條件查詢
    # 條件能夠是:參數,字典,Q

def select_related(self, *fields)
    性能相關:表之間進行join連表操做,一次性獲取關聯的數據。

    總結:
    1. select_related主要針一對一和多對一關係進行優化。
    2. select_related使用SQL的JOIN語句進行優化,經過減小SQL查詢的次數來進行優化、提升性能。

def prefetch_related(self, *lookups)
    性能相關:多表連表操做時速度會慢,使用其執行屢次SQL查詢在Python代碼中實現連表操做。

    總結:
    1. 對於多對多字段(ManyToManyField)和一對多字段,可使用prefetch_related()來進行優化。
    2. prefetch_related()的優化方式是分別查詢每一個表,而後用Python處理他們之間的關係。

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) > 1

def 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):
   # 是否有結果

知識點補充:

Django與Ajax

相關文章
相關標籤/搜索