Django之模型系統

Django模型簡介

Django 模型是與數據庫相關的,與數據庫相關的代碼通常寫在 models.py 中python

Django 支持 sqlite3, MySQL, oracle,PostgreSQL等數據庫,只須要在settings.py中配置便可,不用更改models.py中的代碼,豐富的API極大的方便了使用。mysql

數據庫的設置

在Django中,django默認使用sqlite的數據庫,django默認自帶sqlite的數據庫驅動git

引擎名稱:django.db.backends.sqlite3正則表達式

settings.py默認支持的數據庫sql

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

  

若是要改成mysql數據庫,則修改成以下設置:數據庫

DATABASES = {

    'default': {

        'ENGINE': 'django.db.backends.mysql', 

        'NAME': 'books',    #你須要連接數據庫的名稱

        'USER': 'root',   #數據庫主機受權的用戶名

        'PASSWORD': '', #數據庫受權的用戶密碼

        'HOST': '', #你的數據庫主機,留空默認爲localhost

        'PORT': '3306', #你的數據庫端口

    }

}

  

提示:django

 

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


前提是安裝了pymysql模塊

  

ORM介紹

什麼是ORM?

對象關係映射(Object Relational Mapping,簡稱ORM),是爲了解決面向對象與關係數據庫存在的互不匹配的現象的技術。數組

簡單來講,就是用面向對象的方式去操做數據庫的建立表以及增刪改查等操做。oracle

 

ORM來源

當咱們與一個面向對象的系統工做,還有的對象模型和關係數據庫之間的不匹配。 app

ORM主要是解決面向對象的設計方式和關係型數據庫之間的關聯,O/R  的o(object)主要面向對象設計,然而數據庫是relational的

所以在分析業務的時候會以對象的角度來看待問題。所以纔有ORM.開發人員在整個代碼設計都將遵循對象的思惟模式.

面向對象是從軟件工程基本原則(如耦合、聚合、封裝)的基礎上發展起來的,而關係數據庫則是從數學理論發展而來的,兩套理論存在顯著的區別。爲了解決這個不匹配的現象,對象關係映射技術應運而生。

 

什麼是耦合,聚合,封裝

耦合:耦合指各個模塊以前的關聯程度

聚合:是指一個模塊內部各個部分之間的關聯程度

封裝原則:隱藏對象的屬性和實現細節,僅對外公開藉口,而且控制訪問級別

在面向對象方法中,用類來實現上面的要求。用類實現封裝,用封裝來實現高內聚,低耦合。

 

用ORM的好處

讓業務代碼訪問對象,而不是數據庫表。

隱藏了面向對象的邏輯SQL查詢詳情。

基於業務概念,而不是數據庫結構的實體。

應用程序的快速開發。

防止了sql注入

Django的ORM相關操做

類映射模型

每一個類對應一個表。類的屬性就是數據庫的表和類型

在(models.py文件中寫)

簡單示例一段代碼

from django.db import models
class Publisher(models.Model):
    name = models.CharField(max_length=30, verbose_name="名稱")
    address = models.CharField("地址", max_length=50)
    def __str__(self):        
        return self.name
# verbose_name表示顯示的別名,相似數據的select as 操做 
# verbose也能夠不寫跟address同樣直接起別名,可是必須放在一個位置

 

__str__表示:用一個字段替代類自己做爲返回值

類模型的字段類型

1. models.AtuoField() 自增列,若不寫Django自動添加,若要自定義自增列,必須設置爲主鍵primary_key=True
2. 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)

3. models.CharField() 字符串字段,必填參數max_length,在數據層和表單驗證中均起做用,用來限定字段的長度
4. models.IntegerField() 整型
5. models.BigIntegerField() 長整型
    對應的變化範圍:
    integer_field_ranges = {
    'SmallIntegerField': (-32768, 32767),
    'IntegerField': (-2147483648, 2147483647),
    'BigIntegerField': (-9223372036854775808, 9223372036854775807),
    'PositiveSmallIntegerField': (0, 32767),
    'PositiveIntegerField': (0, 2147483647),
  }

#自定義無符號整數字段

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

6. models.FloatField() 浮點型
7. models.BooleanField() 布爾型=tinyint(1),不能爲空 Blank=True
8. NullBooleanField(Field):
        - 能夠爲空的布爾值
9. TextField(Field)
        - 文本類型

10. EmailField(CharField):
        - 字符串類型,Django Admin以及ModelForm中提供驗證機制

11. IPAddressField(Field)
        - 字符串類型,Django Admin以及ModelForm中提供驗證 IPV4 機制

12. 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"

13. URLField(CharField)
        - 字符串類型,Django Admin以及ModelForm中提供驗證 URL

14. SlugField(CharField)
        - 字符串類型,Django Admin以及ModelForm中提供驗證支持 字母、數字、下劃線、鏈接符(減號)

15. CommaSeparatedIntegerField(CharField)
        - 字符串類型,格式必須爲逗號分割的數字

16. UUIDField(Field)
        - 字符串類型,Django Admin以及ModelForm中提供對UUID格式的驗證

17. FilePathField(Field)
        - 字符串,Django Admin以及ModelForm中提供讀取文件夾下文件的功能
        - 參數:
                path,                      文件夾路徑
                match=None,                正則匹配
                recursive=False,           遞歸下面的文件夾
                allow_files=True,          容許文件
                allow_folders=False,       容許文件夾

18. FileField(Field)
        - 字符串,路徑保存在數據庫,文件上傳到指定目錄
        - 參數:
            upload_to = ""      上傳文件的保存路徑
            storage = None      存儲組件,默認django.core.files.storage.FileSystemStorage

19. ImageField(FileField)
        - 字符串,路徑保存在數據庫,文件上傳到指定目錄
        - 參數:
            upload_to = ""      上傳文件的保存路徑
            storage = None      存儲組件,默認django.core.files.storage.FileSystemStorage
            width_field=None,   上傳圖片的高度保存的數據庫字段名(字符串)
            height_field=None   上傳圖片的寬度保存的數據庫字段名(字符串)

20. DateTimeField(DateField)
        - 日期+時間格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]

21. DateField(DateTimeCheckMixin, Field)
        - 日期格式      YYYY-MM-DD

22. TimeField(DateTimeCheckMixin, Field)
        - 時間格式      HH:MM[:ss[.uuuuuu]]

23. DurationField(Field)
        - 長整數,時間間隔,數據庫中按照bigint存儲,ORM中獲取的值爲datetime.timedelta類型

24. FloatField(Field)
        - 浮點型 通常不經常使用,由於要精確

25. DecimalField(Field)
        - 10進制小數
        - 參數:
            max_digits,小數總長度
            decimal_places,小數位長度

26. BinaryField(Field)
        - 二進制類型

  

字段類型的參數

一、null=True
  數據庫中字段是否能夠爲空
二、primary_key = False
  主鍵,對AutoField設置主鍵後,就會代替原來的自增 id 列
三、auto_now 和 auto_now_add
  auto_now   自動建立---不管添加或修改,都是當前操做的時間
  auto_now_add  自動建立---永遠是建立時的時間
四、choices  性別選擇經常使用
GENDER_CHOICE = (
        (u'M', u'Male'),
        (u'F', u'Female'),
    )
gender = models.CharField(max_length=2,choices = GENDER_CHOICE)
五、max_length
六、default  默認值
七、name|db_column  數據庫中字段的列名
八、unique=True  不容許重複,自建索引
九、db_index = True  數據庫索引
十、editable=True  在Admin裏是否可編輯
十一、error_messages=None  錯誤提示
十二、auto_created=False  自動建立
1三、upload-to   上傳到哪一個位置,更多與image,filepath配合使用

#Admin相關
一、blank=True
  django的 Admin 中添加數據時是否可容許空值
二、help_text  在Admin中提示幫助信息
三、blank    Admin中是否容許用戶輸入爲空
四、editable  Admin中是否能夠編輯
五、verbose_name  Admin中字段的顯示名稱
六、 error_messages  自定義錯誤信息(字典類型),從而定製想要顯示的錯誤信息;
    字典健:null, blank, invalid, invalid_choice, unique, and unique_for_date
    如:{'null': "不能爲空.", 'invalid': '格式錯誤'}
七、validators=[]
自定義錯誤驗證(列表類型),從而定製想要的驗證規則
from django.core.validators import RegexValidator
from django.core.validators import EmailValidator,URLValidator,DecimalValidator,\
 MaxLengthValidator,MinLengthValidator,MaxValueValidator,MinValueValidator
 如:
     test = models.CharField(
         max_length=32,
         error_messages={
             'c1': '優先錯信息1',
             'c2': '優先錯信息2',
             'c3': '優先錯信息3',
         },
         validators=[
             RegexValidator(regex='root_\d+', message='錯誤了', code='c1'),
             RegexValidator(regex='root_112233\d+', message='又錯誤了', code='c2'),
             EmailValidator(message='又錯誤了', code='c3'), ]
     )

  

 元信息

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   相似as別名

        # verbose_name加s
        verbose_name_plural

    更多:https://docs.djangoproject.com/en/1.10/ref/models/options/
注:
1.觸發Model中的驗證和錯誤提示有兩種方式:
    a. Django Admin中的錯誤信息會優先根據Admiin內部的ModelForm錯誤信息提示,若是都成功,纔來檢查Model的字段並顯示指定錯誤信息
    b. 調用Model對象的 clean_fields 方法,如:
        # models.py
        class UserInfo(models.Model):
            nid = models.AutoField(primary_key=True)
            username = models.CharField(max_length=32)

            email = models.EmailField(error_messages={'invalid': '格式錯了.'})

        # views.py
        def index(request):
            obj = models.UserInfo(username='11234', email='uu')
            try:
                print(obj.clean_fields())
            except Exception as e:
                print(e)
            return HttpResponse('ok')

       # Model的clean方法是一個鉤子,可用於定製操做,如:上述的異常處理。

2.Admin中修改錯誤提示
    # admin.py
    from django.contrib import admin
    from model_club import models
    from django import forms


    class UserInfoForm(forms.ModelForm):
        username = forms.CharField(error_messages={'required': '用戶名不能爲空.'})
        email = forms.EmailField(error_messages={'invalid': '郵箱格式錯誤.'})
        age = forms.IntegerField(initial=1, error_messages={'required': '請輸入數值.', 'invalid': '年齡必須爲數值.'})

        class Meta:
            model = models.UserInfo
            # fields = ('username',)
            fields = "__all__"


    class UserInfoAdmin(admin.ModelAdmin):
        form = UserInfoForm

    admin.site.register(models.UserInfo, UserInfoAdmin)

  

關係映射(表關係)模式

經常使用的有三種:

  • 一對多(one-to-many)
  • 多對多(many-to-many)
  • 一對一(one-to-one)

一對一的關係(one-to-one):相似於每一個人和他的身份證之間的關係

用簡單實際環境介紹其餘模型,以下:

出版商模型:出版商有名稱,地址,所在城市,省,國家和網站。

書籍模型:書籍有書名和出版日期,一本書可能會有多個做者,一個做者也能夠寫多本書,因此做者和書籍的關係就是多對多的關聯關係(many-to-many),一本書只應該由一個出版商出版,因此出版商和書籍是一對多關聯關係(one-to-many),也被稱做外鍵。

先介紹一張表,對錶記錄的增刪改查

 

ORM之單表操做

表記錄的添加 

在models.py 建一個類,叫Author

from django.db import models
class Author(models.Model):
    name = models.CharField(max_length=33)
    age = models.IntegerField()

  

其次

生成數據庫腳本
python manage.py makemigrations


遷移數據庫
python manage.py migrate

  

添加表記錄的兩種方式

在視圖函數裏寫

第一種create方式:

from django.shortcuts import render,HttpResponse
from app01.models import *
# Create your views here.

def author(request):

    Author.objects.create(name="xixi",age=20)
    Author.objects.create(**{"name": "xiaoxi","age":19})

    return HttpResponse("表記錄添加成功")


跟python函數的參數組kwargs用法相似

name表示表的字段,等號後面表示記錄

  

第二種方式save:

def author(request):

    # Author.objects.create(name="xixi",age=20)
    # Author.objects.create(**{"name": "xiaoxi","age":19})

    # save方式一
    au = Author(name="yj",age=20)
    au.save()

    #save方式二
    thor = Author()
    thor.name="lq"
    thor.age=21
    thor.save()

    return HttpResponse("表記錄添加成功")


save方式相似 ——類實例化

  

表記錄刪除delete()

from django.shortcuts import render,HttpResponse
from app01.models import *
# Create your views here.

def author(request):

    Author.objects.filter(id=1).delete()
    return HttpResponse("刪除成功,id=1的記錄")

#django爲默認有一個id主鍵的字段


filter過濾出id=1的那個對象,相似sql 的where

  

一會介紹filter

 

 

表記錄的修改

第一種方式get()    save()方式

from django.shortcuts import render,HttpResponse
from app01.models import *
# Create your views here.

def author(request):

    thor = Author.objects.get(id=2)
    thor.name = "無語"
    thor.save()

    return HttpResponse("修改id=2 的name的記錄")

  

第二種方式update()方式

 

from django.shortcuts import render,HttpResponse
from app01.models import *
# Create your views here.

def author(request):

    thor = Author.objects.get(id=2)
    thor.name = "無語"
    thor.save()

    return HttpResponse("修改id=2 的name的記錄")

  

一會介紹get()操做 ,和 filter()操做,以及區別

 

表記錄查詢

查詢的方法以下

類名.objects.查詢的API

  

例如:

from django.shortcuts import render,HttpResponse
from app01.models import *
# Create your views here.

def author(request):


   
    ret1 = Author.objects.filter(id=2)
    print(ret1)
    #自已在項目運行的查看結果
    return HttpResponse("查詢")

  

 

查詢的API

 

1.filter(**kwargs):      它包含了與所給篩選條件相匹配的QuerySet對象
ret1 = Author.objects.filter(id=2)
    print(ret1)


2.all():                 查詢全部結果,至關於查詢表全部的表記錄,只不過查詢的是QuerySet對象
ret = Author.objects.all()
    print(ret)
    for i in ret:
        print(i.id,i.name,i.age)


3.get(**kwargs):         返回與所給篩選條件相匹配的類對象,返回結果有且只有一個,若是符合篩選條件的對象超過一個或者沒有都會拋出錯誤。
    ret2 = Author.objects.get(id=2)
    print(ret2)  #Author object
    print(ret2.name)  #對象屬性
    # 查詢id=2的這條記錄對象

  

 

立刻寫QuerySet對象,先寫對查詢結果的處理

 

對查詢結果的處理API

注:get沒有如下方法

語法以下

類名.objects.查詢的API.相應處理的API

  

1.values(*field):        返回一個ValueQuerySet——一個特殊的QuerySet,運行後獲得的並非一系列 model的實例化對象,而是一個可迭代的字典序列
例如:
result = Author.objects.filter(id=2).values()
    print(result)

2.exclude(**kwargs):     它包含了與所給篩選條件不匹配的Queryset對象
例如:
result = Author.objects.filter(id=2).exclude()
    print(result)
除了id=2,其餘全部Queryset對象


3.order_by(*field):      對查詢結果排序

4.reverse():             對查詢結果反向排序

5.distinct():            從返回結果中剔除重複紀錄

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

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

8.first():               返回第一條記錄

9.last():                返回最後一條記錄

10.exists():             若是QuerySet包含數據,就返回True,不然返回False。

  

 

get和filter的區別

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

filter 它包含了與所給篩選條件相匹配的QuerySet對象  

get不能對查詢結果作處理

 

聚合查詢和分組查詢

1.聚合查詢aggregate(*args,**kwargs)

聚合查詢至關於sql的聚合函數

經過對QuerySet進行計算,返回一個聚合值的字典。aggregate()中每個參數都指定一個包含在字典中的返回值。即在查詢集上生成聚合

使用查詢首先要在視圖函數裏面導入相關聚合接口的API

例如:

from django.db.models import Avg,Min,Sum,Max

  

簡單示例:

 

from django.shortcuts import render,HttpResponse
from django.db.models import Avg,Min,Sum,Max
from app01.models import *
# Create your views here.

def author(request):

    #查詢做者的總年齡
    TOTAL = Author.objects.all().aggregate(Sum("age"))
    print(TOTAL) #結果是這樣{'age__sum': 101}


    return HttpResponse("聚合查詢")

aggregate()是QuerySet 的一個終止子句,意思是說,它返回一個包含一些鍵值對的字典。鍵的名稱是聚合值的
標識符,值是計算出來的聚合值。鍵的名稱是按照字段和聚合函數的名稱自動生成出來的。
若是你想要爲聚合值指定一個名稱,能夠向聚合子句提供它,則使用:
TOTAL = Author.objects.all().aggregate(SUM=Sum("age"))
    print(TOTAL) #結果是這樣{'SUM': 101}

  

其餘的聚合查詢,跟上面差很少

 

2.分組查詢annotate(*args,**kwargs):

能夠經過計算查詢結果中每個對象所關聯的對象集合,從而得出總計值(也能夠是平均值或總和),即爲查詢集的每一項生成聚合。

就是sql語句的group by,在sql語句中的group by:

GROUP BY是SELECT語句的從句,用來指定查詢分組條件,主要用來對查詢的結果進行分組,相同組合的分組條件在結果集中只顯示一行記錄。使用GROUP BY從句時候,經過添加聚合函數(主要有COUNT()、SUM、MAX()、MIN()等)可使數據聚合。

 

我建立的這個單表很差舉例,就簡單看用annotate用法:

from django.shortcuts import render,HttpResponse
from django.db.models import Avg,Min,Sum,Max
from app01.models import *
# Create your views here.

def author(request):

    TOTAL = Author.objects.values("age").annotate(Sum("age"))
    print(TOTAL) 

  

 QuerySet

Author.objects.all()或者.filter()等都只是返回了一個QuerySet(查詢結果集對象),它並不會立刻執行sql,而是當調用QuerySet的時候才執行。所以Queryset是惰性

 

QuerySet特色

對於QuerySet對象最直接的兩個特色:

  1. 可迭代的
  2. 可切片

 

objs=models.Book.objects.all()#[obj1,obj2,ob3...]

#迭代
for obj in objs:#每一obj就是一個行對象
     print("obj:",obj)

#切片
 print(objs[1])
print(objs[1:4])
print(objs[::-1])

  

QuerySet的高效使用


當一個表裏面有上億條記錄的時候,用 models.xxx.objects.all() 所有讀取到內存時候,這會對內存特別浪費,更糟糕的是,巨大的queryset可能會鎖住系統進程,

使程序崩潰,要避免在遍歷數據的同時產生queryset cache,可使用iterator()方法來獲取數據,處理完數據就將其丟棄。

objs = models.xxx.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,可能
會形成額外的數據庫查詢。

 

ORM之一對多關係

Django 使用 django.db.models.ForeignKey 定義多對一關係。和使用其它字段類型同樣:在模型當中把它作爲一個類屬性包含進來。

ForeignKey 須要一個位置參數:與該模型關聯的類。

好比,一輛汽車(Car)有一個製造商(Manufacturer) —— 可是一個製造商(Manufacturer) 生產不少汽車(Car),每一輛汽車(Car) 只能有一個製造商(Manufacturer)

from django.db import models

class Manufacturer(models.Model):
    # ...
    pass

class Car(models.Model):
    manufacturer = models.ForeignKey(Manufacturer)

 

ORM之多對多關係 

ManyToManyField 用來定義多對多關係,用法和其餘Field 字段類型同樣:在模型中作爲一個類屬性包含進來。

ManyToManyField 須要一個位置參數:和該模型關聯的類。

例如,一個披薩能夠有多種餡料 ,一種餡料 也能夠位於多個披薩上。 以下展現:

from django.db import models

class Topping(models.Model):
    # ...
    pass

class Pizza(models.Model):
    # ...
    toppings = models.ManyToManyField(Topping)

  

在哪一個模型中設置 ManyToManyField 並不重要,在兩個模型中任選一個便可 —— 不要兩個模型都設置。

一般,ManyToManyField 實例應該位於能夠編輯的表單中。要結合實際

 

多對多關係中的其餘字段

處理相似搭配 pizza 和 topping 這樣簡單的多對多關係時,使用標準的ManyToManyField  就能夠了。可是,有時你可能須要關聯數據到兩個模型之間的關係上。

例如,有這樣一個應用,它記錄音樂家所屬的音樂小組。咱們能夠用一個ManyToManyField 表示小組和成員之間的多對多關係。可是,有時你可能想知道更多成員關係的細節,好比成員是什麼時候加入小組的。

對於這些狀況,Django 容許你指定一箇中介模型來定義多對多關係。 你能夠將其餘字段放在中介模型裏面。源模型的ManyToManyField 字段將使用through 參數指向中介模型

from django.db import models

class Person(models.Model):
    name = models.CharField(max_length=128)

    def __str__(self):          
        return self.name

class Group(models.Model):
    name = models.CharField(max_length=128)
    members = models.ManyToManyField(Person, through='Membership')

    def __str__(self):             
        return self.name

class Membership(models.Model):
    person = models.ForeignKey(Person)
    group = models.ForeignKey(Group)
    date_joined = models.DateField()
    invite_reason = models.CharField(max_length=64)

  

中介模型的限制:

  • 中介模型必須有且只有一個外鍵到源模型(上面例子中的Group),或者你必須使用ManyToManyField.through_fields 顯式指定Django 應該在關係中使用的外鍵。若是你的模型中存在不止一個外鍵,而且through_fields沒有指定,將會觸發一個無效的錯誤。 對目標模型的外鍵有相同的限制(上面例子中的 Person)。
  • 對於經過中介模型與本身進行多對多關聯的模型,容許存在到同一個模型的兩個外鍵,但它們將被當作多對多關聯中一個關係的兩邊。若是有超過兩個外鍵,一樣你必須像上面同樣指定through_fields,不然將引起一個驗證錯誤。
  • 使用中介模型定義與自身的多對多關係時,你必須設置 symmetrical=False

 

 

ORM之多表操做

 

 多表基本操做

 

 

增長

跟單表操做同樣

第一種:create方式

第二種:
        1.類實例化
        2.save()    

  

 

刪除

1.clear

2.remove

 

修改

update

set,重置某一列的

查詢

select

 

總結:多表的增刪改查,基本同樣,應用(__雙下線)進行多表操做,

關聯條件查詢(__雙下劃線)

經常使用條件查詢

字段__條件=相應查詢格式或則內容

  

__exact    #j精確匹配

__gt=    #大於(經常使用數字)
__gte=  #大於等於
__in=[,,,]   #in查詢  子查詢   就是sql語句的in查詢
_isnull=True/False   值爲 True 或 False, 至關於 SQL語句IS NULL和IS NOT NULL.
__lt   #小於
__lte   #小於等於
__range=(start,end)   #範圍測試(包含於之中)。  至關於BETWEEN  AND

__startswith=    #以什麼開頭
__istartswith=    #不區分大小寫的開頭
__endswith=    #以什麼結尾
__contains=     #模糊查詢   相似sql語句的LIKE
__regex=r'^(An?|The) +'    #自定義正則表達式查詢
__search=    一個Boolean類型的全文搜索,以全文搜索的優點。這個很像 contains ,可是因爲全文索引的優點,以使它更顯著的快。  相似sql語句的match

  

關聯查詢

關聯字段__另外一張的表的關聯字段__相應條件=相應查詢的格式或則內容

  

 F查詢和Q查詢

若是咱們想將模型的一個字段與同一個模型的另一個字段進行比較該怎麼辦

用上面的關聯條件查詢,這時候確定是辦不到的,這是後就不要用到F查詢了

在這裏引用官方實例

from django.db import models

class Blog(models.Model):
    name = models.CharField(max_length=100)
    tagline = models.TextField()

    def __str__(self):              # __unicode__ on Python 2
        return self.name

class Author(models.Model):
    name = models.CharField(max_length=50)
    email = models.EmailField()

    def __str__(self):              # __unicode__ on Python 2
        return self.name

class Entry(models.Model):
    blog = models.ForeignKey(Blog)
    headline = models.CharField(max_length=255)
    body_text = models.TextField()
    pub_date = models.DateField()
    mod_date = models.DateField()
    authors = models.ManyToManyField(Author)
    n_comments = models.IntegerField()
    n_pingbacks = models.IntegerField()
    rating = models.IntegerField()

    def __str__(self):              # __unicode__ on Python 2
        return self.headline

  

提示自已插入測試數據

F查詢

提示:F查詢——專門取對象中某列值(字段)的操做

 

示例:

 from django.db.models import F  #必須導入

#爲了查找comments 數目多於pingbacks 的Entry,咱們將構造一個F() 對象來引用pingback 數目,並在查詢中使用該F() 對象:
Entry.objects.filter(n_comments__gt=F('n_pingbacks'))

  

Django 支持對F() 對象使用加法、減法、乘法、除法、取模以及冪計算等算術操做,兩個操做數能夠都是常數和其它F() 對象。

#爲了查找comments 數目比pingbacks 兩倍還要多的Entry,咱們將查詢修改成:

 Entry.objects.filter(n_comments__gt=F('n_pingbacks') * 2)

  

注:F查詢一樣也能夠跨表關聯查詢

Q查詢

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

這時候就須要用到Q對象查詢

 

class Poll(models.Model):
    question = models.CharField(max_length=100)
    put_date = models.DateField()

  

Q查詢——對對象的複雜查詢

示例:

 

from django.db.models import Q  #必須導入

#下面的Q 對象封裝一個LIKE 查詢:
Q(question__startswith='What')

  

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

#下面的語句產生一個Q 對象,表示兩個"question__startswith" 查詢的「OR」 

Q(question__startswith='Who') | Q(question__startswith='What')

它等同於下面的SQL WHERE 子句:
WHERE question LIKE 'Who%' OR question LIKE 'What%'

  

能夠組合& 和|  操做符以及使用括號進行分組來編寫任意複雜的Q 對象。同時,Q 對象可使用~ 操做符取反

Q(question__startswith='Who') | ~Q(pub_date__year=2005)

  

 

 

每一個接受關鍵字參數的查詢函數(例如filter()、exclude()、get())均可以傳遞一個或多個Q 對象做爲位置(不帶名的)參數。若是一個查詢函數有多個Q 對象參數,這些參數的邏輯關係爲「AND"。例如:

Poll.objects.get(
    Q(question__startswith='Who'),
    Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6))
)

以翻譯成這個SQL:
SELECT * from Poll WHERE question LIKE 'Who%'
    AND (pub_date = '2005-05-02' OR pub_date = '2005-05-06')

  

提示:

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

#合法
Poll.objects.get(
    Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)),
    question__startswith='Who')

Q對象在前面



#不合法
Poll.objects.get(
    question__startswith='Who',
    Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)))
相關文章
相關標籤/搜索