ORM

一  概述

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

每一個模型都是一個Python類,它是django.db.models.Model的子類。模型的每一個屬性都表明一個數據庫字段。mysql

1. Django使用MySQL配置

1. 在Django項目的settings.py文件中,配置數據庫鏈接信息:git

DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.mysql",
        "NAME": "你的數據庫名稱",  # 須要本身手動建立數據庫
        "USER": "數據庫用戶名",
        "PASSWORD": "數據庫密碼",
        "HOST": "數據庫IP",
        "POST": 3306
    }
}

2. 在Django項目的__init__.py文件中寫以下代碼,告訴Django使用pymysql模塊鏈接MySQL數據庫:sql

import pymysql
pymysql.install_as_MySQLdb()

二  ORM 經常使用字段和參數

1. 字段

  AutoField(Field)
        - int自增列,必須填入參數 primary_key=True。id字段是自動添加的,若是Django發現你已經明確地設置了Field.primary_key,它將不會添加自動ID列。
  BigAutoField(AutoField)
        - bigint自增列,必須填入參數 primary_key=True

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

多選的話須要導入:數據庫

from multiselectfield import MultiSelectField

2. ORM字段與數據庫的對應關係

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

3. 自定義字段

class FixedCharField(models.Field):
    """
    自定義的char類型的字段類
    """
    def __init__(self, max_length, *args, **kwargs):
        super().__init__(max_length=max_length, *args, **kwargs)
        self.length = max_length
    def db_type(self, connection):
        """
        限定生成數據庫表的字段類型爲char,長度爲length指定的值
        """
        return 'char(%s)' % self.length  #數據庫的語法char() class Class(models.Model):
    id = models.AutoField(primary_key=True)
    title = models.CharField(max_length=25)
    # 使用上面自定義的char類型的字段
    cname = FixedCharField(max_length=25)

4. 字段參數

   null                數據庫中字段是否能夠爲空
    db_column           數據庫中字段的列名
    default 數據庫中字段的默認值 primary_key 數據庫中字段是否爲主鍵 db_index 數據庫中字段是否能夠創建索引 unique           數據庫中字段是否能夠創建惟一索引
    unique_for_date     數據庫中字段【日期】部分是否能夠創建惟一索引
    unique_for_month    數據庫中字段【月】部分是否能夠創建惟一索引
    unique_for_year     數據庫中字段【年】部分是否能夠創建惟一索引
 
    verbose_name        Admin中顯示的字段名稱
    blank             Admin中是否容許用戶輸入爲空
    editable            Admin中是否能夠編輯
    help_text           Admin中該字段的提示信息
    choices             Admin中顯示選擇框的內容,用不變更的數據放在內存中從而避免跨表操做
                        如:gf = models.IntegerField(choices=[(0, '何穗'),(1, '大表姐'),],default=1)
 
    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'), ] )

5. Model Meta參數

class UserInfo(models.Model):
    nid = models.AutoField(primary_key=True)
    username = models.CharField(max_length=32)
    class Meta:
        # 數據庫中生成的表名稱 默認 app名稱 + 下劃線 + 類名
        db_table = "table_name"
 
        # admin中顯示的表名稱
        verbose_name = '我的信息'
 
        # verbose_name加s,admin中顯示改變
        verbose_name_plural = '全部用戶信息'
 
        # 聯合索引 
        index_together = [
            ("pub_date", "deadline"),   # 應爲兩個存在的字段
        ]
 
        # 聯合惟一索引
        unique_together = (("driver", "restaurant"),)   # 應爲兩個存在的字段
     
    ordering=(‘id’)  #默認查詢對象的排序

6. 時間字段

DatetimeField、DateField、TimeField這個三個時間字段,均可以設置以下屬性。django

  • auto_now_add:配置auto_now_add=True,建立數據記錄的時候會把當前時間添加到數據庫。
  • auto_now:配置auto_now=True,每次更新數據記錄的時候會更新該字段。

三  單表操做

1. 基本查詢

<1> all():                 查詢全部結果,返回queryset對象 <2> filter(**kwargs):      它包含了與所給篩選條件相匹配的對象,返回queryset對象 <3> get(**kwargs):         返回與所給篩選條件相匹配的對象,返回結果有且只有一個,若是符合篩選條件的對象超過一個(默認返回最後一個元素)或者沒有都會拋出錯誤。返回queryset元素 <4> exclude(**kwargs):     它包含了與所給篩選條件不匹配的對象,返回queryset對象
 
<5> values(*field):        返回一個可迭代的字典序列 <6> values_list(*field):   它與values()很是類似,它返回的是一個元組序列,只有值,沒有字段的名稱

<7> order_by(*field): 對查詢結果排序,返回queryset對象;例如orser_by(-id),降序 <8> reverse(): 對查詢結果反向排序,請注意reverse()一般只能在具備已定義順序的QuerySet上調用(在model類的Meta中指定ordering或調用order_by()方法)。 <9> distinct(): 從返回結果中剔除重複紀錄(若是你查詢跨越多個表,可能在計算QuerySet時獲得重複的結果。此時可使用distinct(),注意只有在PostgreSQL中支持按字段去重。) <10> count(): 返回數據庫中匹配查詢(QuerySet)的對象數量。 <11> first(): 返回第一條記錄,返回queryset元素,爲空返回None,[0]爲空報錯 <12> last(): 返回最後一條記錄,返回queryset元素,爲空返回None <13> exists(): 若是QuerySet包含數據,就返回True,不然返回False

2. 雙下劃線查詢

models.Tb1.objects.filter(id__lt=10, id__gt=1)   # 獲取id大於1 且 小於10的值
(id__gte=1),(id__lte=1)               #大於等於,小於等於
models.Tb1.objects.filter(id__in=[11, 22, 33]) # 獲取id等於十一、2二、33的數據 models.Tb1.objects.exclude(id__in=[11, 22, 33]) # not in models.Tb1.objects.filter(name__contains="ven") # 獲取name字段包含"ven"的 models.Tb1.objects.filter(name__icontains="ven") # icontains大小寫不敏感 models.Tb1.objects.filter(id__range=[1, 3]) # id範圍是1到3的,等價於SQL的bettwen and 相似的還有:startswith,istartswith, endswith, iendswith  date字段還能夠: models.Class.objects.filter(first_day__year=2017)

3. 增刪改查

#
1.  object.creat() models.Tb1.objects.create(c1='xx', c2='oo') # 增長一條數據,能夠接受字典類型數據 **kwargs, 2.  實例化
obj = models.Tb1(c1='xx', c2='oo') obj.save() # models.Tb1.objects.get(id=123) # 獲取單條數據,不存在則報錯(不建議) models.Tb1.objects.all() # 獲取所有 models.Tb1.objects.filter(name='seven') # 獲取指定條件的數據 # models.Tb1.objects.filter(name='seven').delete() # 刪除指定條件的數據 # models.Tb1.objects.filter(name='seven').update(gender='0') # 將指定條件的數據更新,均支持 **kwargs
obj = models.Tb1.objects.get(id=1) obj.c1 = '111' obj.save() # 修改整條數據

四  OneToOneField

用途很少,一對一的關聯關係多用在當一張表的不一樣字段查詢頻次差距過大的狀況下,將本能夠存儲在一張表的字段拆開放置在兩張表中,而後將兩張表創建一對一的關聯關係。app

class Author(models.Model):
    name = models.CharField(max_length=32)
    info = models.OneToOneField(to='AuthorInfo')

class AuthorInfo(models.Model):
    phone = models.CharField(max_length=11)
    email = models.EmailField()

五  ForeignKey

一對多的連表就是使用的foreignkey關鍵字,必定標明外鍵關係名稱的起始終止方向,設置的時候保持關係名稱與被指向數據庫同名。函數

通常是在「多」中創建外鍵,生成管理對象。ui

class Publisher(models.Model):
    name = models.CharField(max_length=32)  # 出版社名稱
class Book(models.Model):
    title = models.CharField(max_length=30)  # 書名
    price = models.IntegerField()  # 價格
    publisher = models.ForeignKey(to='Publisher', related_name='books')

QL語句中可使用連表查詢,外鍵的用途不是特別廣,主要起到約束的做用;但在ORM中,只能經過外鍵進行連表,做用明顯spa

create table userinfo(
          uid int auto_increment primary key,
          name varchar(32), department_id int, constraint fk_user_depar foreign key (department_id) references department(id)  )engine=innodb default charset=utf8;

1. 字段參數

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, # 默認建立第三張表時,數據庫中表的名稱

2.  正向查詢

2.1 對象查詢

book_obj = models.Book.objects.first()  # 第一本書對象
print(book_obj.publisher)  # 獲得這本書關聯的出版社對象
print(book_obj.publisher.name)  # 獲得出版社對象的名稱

結果爲:屢次查詢

SELECT `mainApp_book`.`id`, `mainApp_book`.`title`, `mainApp_book`.`price`, `mainApp_book`.`publisher_id` FROM `mainApp_book` ORDER BY `mainApp_book`.`id` ASC  LIMIT 1; args=()
中國地理出版社
SELECT `mainApp_publisher`.`id`, `mainApp_publisher`.`name` FROM `mainApp_publisher` WHERE `mainApp_publisher`.`id` = 1; args=(1,)

2.2 字段查詢

print(models.Book.objects.values_list("publisher__name"))    #雙下滑線標明是連表查詢

結果爲:連表查詢

(0.000) SELECT `mainApp_publisher`.`name` FROM `mainApp_book` INNER JOIN `mainApp_publisher` ON (`mainApp_book`.`publisher_id` = `mainApp_publisher`.`id`)  LIMIT 21; args=()
<QuerySet [('中國地理出版社',)]>

3.  反向查詢

反向關係名稱:

  • tablename_set
  • tablename·_字段
  • relate_name設置

3.1 對象查詢

publisher_obj = models.Publisher.objects.first()  # 找到第一個出版社對象
books = publisher_obj.book_set.all()  # 找到第一個出版社出版的全部書
print(books.values_list("title") )  # 找到第一個出版社出版的全部書的書名
# 或者
publisher_obj = models.Publisher.objects.first()  # 找到第一個出版社對象
book = publisher_obj.books.all()  # 找到第一個出版社出版的全部書
print(book.values_list("title") )  # 找到第一個出版社出版的全部書的書

3.2 字段查詢

titles = models.Publisher.objects.values_list("book__title")
#或者
titles = models.Publisher.objects.values_list("books__title")

4 方法

create():與單表操做一致

# object.create()方法
models.Book.objects.create(title='書摩納哥', price=12.36, publisher_id=1)
# 實例化
obj = models.Book(title='肖申克的救贖', price=15, publisher_id=1)
obj.save()

add()、set()、remove()、clear()都是針對管理對象進行的操做,都是對「一」進行的添加「多」。

add():必要時,參數須要加*打散

    obj = models.Publisher.objects.last()
    obj.books.add(models.Book.objects.filter(id=2).first())

set():參數爲可迭代對象

    obj = models.Publisher.objects.last()
    obj.books.set([models.Book.objects.filter(id=1).first()])

remove():ForeignKey字段沒設置null=True時才生效

    obj = models.Publisher.objects.last()
    obj.books.remove(models.Book.objects.filter(id=1).first())

clear():ForeignKey字段沒設置null=True時才生效

    obj = models.Publisher.objects.last()
    obj.books.clear()

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

六  ManyToManyField

class Book(models.Model):
    title = models.CharField(max_length=30)  # 書名
    price = models.IntegerField()  # 價格
    publisher = models.ForeignKey(to='Publisher', null=True,
                                  related_name='books', on_delete=models.CASCADE)
    def __str__(self):
        return '<Book %s-%s>' % (self.id, self.title)

class Author(models.Model):
    name = models.CharField(max_length=32)  # 做者名字
    book2author = models.ManyToManyField(to='Book', related_name='author2book')

1. 多對多關聯關係的三種方式 

1.1 自行建立第三張表

class Book(models.Model):
    title = models.CharField(max_length=32, verbose_name="書名")

class Author(models.Model):
    name = models.CharField(max_length=32, verbose_name="做者姓名")

# 本身建立第三張表,分別經過外鍵關聯書和做者
class Author2Book(models.Model):
    author = models.ForeignKey(to="Author")
    book = models.ForeignKey(to="Book")

    class Meta:
        unique_together = ("author", "book")

1.2 經過ManyToManyField自動建立第三張表

class Book(models.Model):
    title = models.CharField(max_length=32, verbose_name="書名")


# 經過ORM自帶的ManyToManyField自動建立第三張表
class Author(models.Model):
    name = models.CharField(max_length=32, verbose_name="做者姓名")
    books = models.ManyToManyField(to="Book", related_name="authors")

1.3 設置ManyTomanyField並指定自行建立的第三張表

class Book(models.Model):
    title = models.CharField(max_length=32, verbose_name="書名")


# 本身建立第三張表,並經過ManyToManyField指定關聯
class Author(models.Model):
    name = models.CharField(max_length=32, verbose_name="做者姓名")
    books = models.ManyToManyField(to="Book", through="Author2Book", through_fields=("author", "book"))
    # through_fields接受一個2元組('field1','field2'):
    # 其中field1是定義ManyToManyField的模型外鍵的名(author),field2是關聯目標模型(book)的外鍵名。

class Author2Book(models.Model):
    author = models.ForeignKey(to="Author")
    book = models.ForeignKey(to="Book")

    class Meta:
        unique_together = ("author", "book")

注意:

當咱們須要在第三張關係表中存儲額外的字段時,就要使用第三種方式。可是當咱們使用第三種方式系時,就沒法使用set、add、remove、clear方法,須要經過第三張表的model來管理多對多關係。

2. 參數字段

symmetrical  僅用於多對多自關聯時,指定內部是否建立反向操做的字段。默認爲True。

舉個例子:

class Person(models.Model):
    name = models.CharField(max_length=16)
    friends = models.ManyToManyField("self")

此時,person對象就沒有person_set屬性。

class Person(models.Model):
    name = models.CharField(max_length=16)
    friends = models.ManyToManyField("self", symmetrical=False)

此時,person對象如今就可使用person_set屬性進行反向查詢。

through

在使用ManyToManyField字段時,Django將自動生成一張表來管理多對多的關聯關係。

但咱們也能夠手動建立第三張表來管理多對多關係,此時就須要經過through來指定第三張表的表名。

through_fields

設置關聯的字段。

db_table

默認建立第三張表時,數據庫中表的名稱。

3. 方法

create()

在原表基礎上建立

models.Author.objects.create(name='tony')

在管理對象表建立:建立一個新的對象,並將它添加到關聯對象集之中。foreignkey沒有此方法。

 models.Book.objects.first().book2author.create(name='lucy')

add()

把指定的model對象添加到關聯對象集中。在原來的關係基礎上添加

    # 添加id
    models.Book.objects.first().book2author.add(1, 3)
    # 添加對象
    obj = models.Author.objects.filter(id__in=[1, 2, 3, 4])
    models.Book.objects.first().book2author.add(*obj)

set()

更新model對象的關聯對象。先清除關係,再添加

    # 設置id
    models.Book.objects.first().book2author.set([1, 3])
    # 設置對象
    obj = models.Author.objects.filter(id__in=[1, 2, 3, 4])
    models.Book.objects.first().book2author.set(obj)

由於原數據表中的每一條數據不必定存在關係,不必定存在於第三張表中,即null默認爲True,因此remove和clear可以使用

remove()

從關聯對象集中移除執行的model對象

    # 清除id
    models.Book.objects.first().book2author.remove(1, 3)
    # 清除對象
    obj = models.Author.objects.filter(id__in=[1, 2, 3, 4])
    models.Book.objects.first().book2author.remove(*obj)

clear()

從關聯對象集中移除一切對象。

models.Book.objects.first().book2author.clear()

七 聚合

aggregate()是QuerySet 的一個終止子句,意思是說,它返回一個包含一些鍵值對的字典。
用到的內置函數:from django.db.models import Avg, Sum, Max, Min, Count

from django.db.models import Avg, Sum, Max, Min, Count
book_obj
=models.Book.objects.all() print(book_obj.aggregate(Max("price"))) #{'price__max': Decimal('9999.99')}
#指定一個名稱 print(book_obj.aggregate(max_price=Max("price"))) #{'max_price': Decimal('9999.99')}
#生成多個聚合 print(book_obj.aggregate(Max("price"),Min("price"),Avg("price"))) #{'price__max': Decimal('9999.99'), 'price__min': Decimal('10.00'), 'price__avg': 1507.141429}

八 分組

#單表查詢
select dept,AVG(salary) from employee group by dept; from django.db.models import Avg model.Employee.objects.values("dept").annotate(avg=Avg("salary").values(dept, "avg")

和sql對比:

  • annotate前面的values值至關於group by的字段,默認爲一組
  • values('dept')、(a=Avg("salary"))內部如是跨表查詢就須要使用雙下劃線
  • annotate後面的values 是select的字段
  • annotate前面是queryset對象;annotate()返回值依然是queryset對象

# 多表查詢
select dept.name,AVG(salary) from employee inner join dept on (employee.dept_id=dept.id) group by dept_id; from django.db.models import Avg models.Dept.objects.annotate(avg=Avg("employee__salary")).values("name", "avg")

 更多實例:

1.ORM中values或者values_list中的字段,至關於select字段
 ORM分組查詢 每一個部門名稱及部門的平均年齡
ret = models.Employee.objects.all().values("dept", "age")
SQL語句
"""
SELECT `employee`.`dept`, `employee`.`age` FROM `employee` LIMIT 21; args=()
"""
2.ORM中 annotate 前面values()是group_by()字段 from django.db.models import Avg ret = models.Employee.objects.values("province").annotate(a=Avg("salary")).values("province", "a") 至關於: SELECT `employee`.`province`, AVG(`employee`.`salary`) AS `a` FROM `employee` GROUP BY `employee`.`province` ORDER BY NULL LIMIT 21; args=()
3. ORM跨表分組查詢,queryset對象跨表查詢時使用雙下劃線 ret = models.Person.objects.values("dept_id").annotate(a=Avg("salary")).values("dept__name", "a") """ SELECT `dept`.`name`, AVG(`person`.`salary`) AS `a` FROM `person` INNER JOIN `dept` ON (`person`.`dept_id` = `dept`.`id`) GROUP BY `person`.`dept_id`, `dept`.`name` ORDER BY NULL LIMIT 21; args=() """
4.查詢每個部門的名稱和人數 #正向查詢: models.emp.objects.values("dept_id").annotate(c=Count("name")).values("dept__name","c") #反向查詢 models.dep.objects.values("name").annotate(c=Count("emp__name")).values("name","c") SQL: select dep_name Count(emp.name) from emp inner join dep on .... group by dep_id 5.查詢每個做者的名字及出版過的書籍的最高價 models.Author.objects.values('id').annotate(c=Max('book__price')).values("name","c")
6.查詢每一本書做者的個數 models.Book.objects.values("id").annotate(c=Count("authors__name")).values("title","c") ret=models.Book.objects.annotate(author_num=Count("author")) for book in ret: print("書名:{},做者數量:{}".format(book.title, book.author_num))
7.統計不止一個做者的圖書(過濾完後顯示)
models.Book.objects.values("title").annotate(c=Count("authors__name")).filter(c__gt=1).values('name',"c") 8.查詢各個做者出的書的總價格
ret = models.Author.objects.annotate(price_sum=Sum("books__price"))
for i in ret:
   print(i, i.name, i.price_sum)

九  F查詢

F查詢就是取表中的動態變量

查詢評論數大於收藏數的書籍

from django.db.models import F
models.Book.objects.filter(commnet_num__gt=F('keep_num'))

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

models.Book.objects.filter(commnet_num__lt=F('keep_num')*2)

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

models.Book.objects.all().update(price=F("price")+30)

引伸:

若是要修改char字段咋辦?

如:把全部書名後面加上(初版)

>>> from django.db.models.functions import Concat
>>> from django.db.models import Value
>>> models.Book.objects.all().update(title=Concat(F("title"), Value("("), Value("初版"), Value(")")))

十 Q查詢

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

示例1:

查詢做者名是小仙女或小魔女的

models.Book.objects.filter(Q(authors__name="小仙女")|Q(authors__name="小魔女"))

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

示例:查詢做者名字是小仙女而且不是2018年出版的書的書名。

>>> models.Book.objects.filter(Q(author__name="小仙女") & ~Q(publish_date__year=2018)).values_list("title")
<QuerySet [('番茄物語',)]>

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

例如:查詢出版年份是2017或2018,書名中帶物語的全部書。

>>> models.Book.objects.filter(Q(publish_date__year=2018) | Q(publish_date__year=2017), title__icontains="物語")
<QuerySet [<Book: 番茄物語>, <Book: 香蕉物語>, <Book: 橘子物語>]>

十一 Django終端打印SQL語句

在Django項目的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',
        },
    }
}

十二 在Python腳本中調用Django環境

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

    from app01 import models

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

 參考:

ORM大彙總:https://www.cnblogs.com/sss4/p/7070942.html

分組查詢詳解:https://www.cnblogs.com/zgf-666/p/9119126.html

相關文章
相關標籤/搜索