一、ORM(Object Relational Mapping)
1、ORM概念
對象關系映射(Object Relational Mapping,簡稱ORM)模式是一種為了解決面向對象與關系數據庫存在的互不匹配的現象的技術。
簡單的說,ORM是通過使用描述對象和數據庫之間映射的元數據,將程序中的對象自動持久化到關系數據庫中。
ORM在業務邏輯層和數據庫層之間充當了橋梁的作用。
2、ORM由來
讓我們從O/R開始。字母O起源於"對象"(Object),而R則來自於"關系"(Relational)。
幾乎所有的軟件開發過程中都會涉及到對象和關系數據庫。在用戶層面和業務邏輯層面,我們是面向對象的。當對象的信息發生變化的時候,我們就需要把對象的信息保存在關系數據庫中。
按照之前的方式來進行開發就會出現程序員會在自己的業務邏輯代碼中夾雜很多SQL語句用來增加、讀取、修改、刪除相關數據,而這些代碼通常都是重復的。
3、ORM的優勢
ORM解決的主要問題是對象和關系的映射。它通常把一個類和一個表一一對應,類的每個實例對應表中的一條記錄,類的每個屬性對應表中的每個字段。
ORM提供了對數據庫的映射,不用直接編寫SQL代碼,只需像操作對象一樣從數據庫操作數據。
讓軟件開發人員專注於業務邏輯的處理,提高了開發效率。
4、ORM的劣勢
ORM的缺點是會在一定程度上犧牲程序的執行效率。
但我們不能指望某個工具能一勞永逸地解決所有問題,一些特殊問題還是需要特殊處理的。
但是在整個軟件開發過程中需要特殊處理的情況應該都是很少的,否則所謂的工具也就失去了它存在的意義。
二、Django中的ORM
1、Django項目中使用MySQL數據庫
1.1、在Django項目的settings.py文件中,配置數據庫連接信息
DATABASES = { "default": { "ENGINE": "django.db.backends.mysql", "NAME": "你的數據庫名稱", # 需要自己手動創建數據庫 "USER": "數據庫用戶名", "PASSWORD": "數據庫密碼", "HOST": "數據庫IP", "POST": 3306 } }
1.2、在Django項目的__init__.py文件中寫如下代碼,告訴Django使用pymysql模塊連接MySQL數據庫
import pymysql pymysql.install_as_MySQLdb()
2、Django中的Model
在Django中model是你數據的單一、明確的信息來源。它包含了你存儲的數據的重要字段和行為。通常,一個模型(model)映射到一個數據庫表,
基本情況:
- 每個模型都是一個Python類,它是django.db.models.Model的子類。
- 模型的每個屬性都代表一個數據庫字段。
- 綜上所述,Django為您提供了一個自動生成的數據庫訪問API,詳詢官方文檔鏈接。

3、Django ORM中常用字段和參數
3.1、常用字段
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) - 二進制類型 字段
附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.2、字段的參數
null 數據庫中字段是否可以為空 db_column 數據庫中字段的列名 db_index 如果db_index=True則代表着為此字段設置索引 db_tablespace 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'), ] ) 參數
3.2.1、DateField和DateTimeField才有的參數
auto_now_add=True --> 創建數據的時候自動把當前時間賦值
auto_add=True --> 每次更新數據的時候更新當前時間
上述兩個不能同時設置!!!
3.3、元信息
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 更多:https://docs.djangoproject.com/en/1.10/ref/models/options/ 元信息
3.4、自定義字段
自定義IntegerField字段:
class UnsignedIntegerField(models.IntegerField): def db_type(self, connection): return 'integer UNSIGNED'
自定義char類型字段:
class FixedCharField(models.Field): """ 自定義的char類型的字段類 """ def __init__(self, max_length, *args, **kwargs): self.max_length = max_length super(FixedCharField, self).__init__(max_length=max_length, *args, **kwargs) def db_type(self, connection): """ 限定生成數據庫表的字段類型為char,長度為max_length指定的值 """ return 'char(%s)' % self.max_length class Class(models.Model): id = models.AutoField(primary_key=True) title = models.CharField(max_length=25) # 使用自定義的char類型的字段 cname = FixedCharField(max_length=25)
4、連接結構
- 一對多:models.ForeignKey(其他表)
- 多對多:models.ManyToManyField(其他表)
- 一對一:models.OneToOneField(其他表)
應用場景:
| 表結構 | 應用場景 | 舉例 |
| 一對多 | 當一張表中創建一行數據時,有一個單選的下拉框(可以被重復選擇) | 例如:創建用戶信息時候,需要選擇一個用戶類型【普通用戶】【金牌用戶】【鉑金用戶】等。 |
| 多對多 | 在某表中創建一行數據是,有一個可以多選的下拉框 | 例如:創建用戶信息,需要為用戶指定多個愛好 |
| 一對一 | 在某表中創建一行數據時,有一個單選的下拉框(下拉框中的內容被用過一次就消失了 | 例如:原有含10列數據的一張表保存相關信息,經過一段時間之后,10列無法滿足需求,需要為原來的表再添加5列數據 |
4.1、ForeignKey
外鍵類型在ORM中用來表示外鍵關聯關系,一般把ForeignKey字段設置在 '一對多'中'多'的一方。ForeignKey可以和其他表做關聯關系同時也可以和自身做關聯關系。
4.2、MangToMangField
創建方式:
| 創建方式 | 優點 | 缺點 | 使用場景 |
| ORM自動創建第三張表 | 查詢方便 | 如果第三張表沒有額外的字段,使用這種方法 | |
| 利用外鍵自己創建第三張表 | 關聯查詢比較麻煩,因為沒辦法使用ORM提供的便利方法 | 第三張表有額外的字段 | |
| 自己創建第三張表,使用ORM 的ManyToManyFiled() | 使用此種方式創建多對多表的時候,沒有 add() remove() 等方法 | 第三張表有額外的字段 |
4.3、OneToOneField
當 一張表的某一些字段查詢的比較頻繁,另外一些字段查詢的不是特別頻繁把不怎么常用的字段 單獨拿出來做成一張表 然后用過一對一關聯起來
優勢:既保證數據都完整的保存下來,又能保證大部分的檢索更快
5、使用ORM操作表
5.1、增
- 方式一
models.User.objects.create(name='qianxiaohu',age=18) dic = {'name': 'xx', 'age': 19} models.User.objects.create(**dic)
- 方式二
obj = models.User(name='qianxiaohu',age=18) obj.save()
5.2、刪
models.User.objects.filter(id=1).delete()
5.3、改
models.User.objects.filter(id__gt=1).update(name='alex',age=84) dic = {'name': 'xx', 'age': 19} models.User.objects.filter(id__gt=1).update(**dic)
5.4、查
models.User.objects.filter(id=1,name='root') models.User.objects.filter(id__gt=1,name='root') models.User.objects.filter(id__lt=1) models.User.objects.filter(id__gte=1) models.User.objects.filter(id__lte=1) models.User.objects.filter(id=1,name='root') dic = {'name': 'xx', 'age__gt': 19} models.User.objects.filter(**dic) v1 = models.Business.objects.all() # QuerySet ,內部元素都是對象 # QuerySet ,內部元素都是字典 v2 = models.Business.objects.all().values('id','caption') # QuerySet ,內部元素都是元組 v3 = models.Business.objects.all().values_list('id','caption') # 獲取到的一個對象,如果不存在就報錯 models.Business.objects.get(id=1) 對象或者None = models.Business.objects.filter(id=1).first() 外鍵: v = models.Host.objects.filter(nid__gt=0) v[0].b.caption ----> 通過.進行跨表
5.5、更多操作
""" ORM小練習 如何在一個Python腳本或文件中 加載Django項目的配置和變量信息 """ import os if __name__ == '__main__': # 加載Django項目的配置信息 os.environ.setdefault("DJANGO_SETTINGS_MODULE", "ormday69.settings") # 導入Django,並啟動Django項目 import django django.setup() from app01 import models # # 查詢所有的人 # ret = models.Person.objects.all() # print(ret) # # get查詢 # ret = models.Person.objects.get(name="小黑") # print(ret) # # filter # ret = models.Person.objects.filter(id=100) # 不存在返回一個空的QuerySet,不會報錯 # print(ret) # # 就算查詢的結果只有一個,返回的也是QuerySet,我們要用索引的方式取出第一個元素 # ret = models.Person.objects.filter(id=1)[0] # print(ret) # print("exclude".center(80, "*")) # # exclude # ret = models.Person.objects.exclude(id=1) # print(ret) # print("values".center(80, "*")) # # values 返回一個QuerySet對象,里面都是字典。 不寫字段名,默認查詢所有字段 # ret = models.Person.objects.values("name", "birthday") # print(ret) # print("values_list".center(80, "*")) # # values_list 返回一個QuerySet對象,里面都是元祖。 不寫字段名,默認查詢所有字段 # ret = models.Person.objects.values_list() # print(ret) # print("order_by".center(80, "*")) # # order_by 按照指定的字段排序 # ret = models.Person.objects.all().order_by("birthday") # print(ret) # print("reverse".center(80, "*")) # # reverse 將一個有序的QuerySet 反轉順序 # # 對有序的QuerySet才能調用reverse # ret = models.Person.objects.all().reverse() # print(ret) # print("count".center(80, "*")) # # count 返回QuerySet中對象的數量 # ret = models.Person.objects.all().count() # print(ret) # print("first".center(80, "*")) # # first 返回QuerySet中第一個對象 # ret = models.Person.objects.all().first() # print(ret) # print("last".center(80, "*")) # # last 返回QuerySet中最后一個對象 # ret = models.Person.objects.all().last() # print(ret) # print("exists".center(80, "*")) # # exists 判斷表里有沒有數據 # ret = models.Book.objects.exists() # print(ret) # 單表查詢之神奇的雙下划線 # # 查詢id值大於1小於4的結果 # ret = models.Person.objects.filter(id__gt=1, id__lt=4) # print(ret) # # in # # 查詢 id 在 [1, 3, 5, 7]中的結果 # ret = models.Person.objects.filter(id__in=[1, 3, 5, 7]) # print(ret) # ret = models.Person.objects.exclude(id__in=[1, 3, 5, 7]) # print(ret) # # contains 字段包含指定值的 # # icontains 忽略大小寫包含指定值 # ret = models.Person.objects.filter(name__contains="小") # print(ret) # # range # # 判斷id值在 哪個區間的 SQL語句中的between and 1<= <=3 # ret = models.Person.objects.filter(id__range=[1,3]) # print(ret) # # 日期和時間字段還可以有以下寫法 # ret = models.Person.objects.filter(birthday__year=2000) # print(ret) # ret = models.Person.objects.filter(birthday__year=2000, birthday__month=5) # print(ret) # 外鍵的查詢操作 # 正向查詢 # 基於對象 跨表查詢 # book_obj = models.Book.objects.all().first() # ret = book_obj.publisher # 和我這本書關聯的出版社對象 # print(ret, type(ret)) # ret = book_obj.publisher.name # 和我這本書關聯的出版社對象 # print(ret, type(ret)) # 查詢id是1的書的出版社的名稱 # 利用雙下划線 跨表查詢 # 雙下划線就表示跨了一張表 # ret = models.Book.objects.filter(id=1).values_list("publisher__name") # print(ret) # 反向查詢 # 1. 基於對象查詢 # publisher_obj = models.Publisher.objects.get(id=1) # 得到一個具體的對象 # # ret = publisher_obj.book_set.all() # ret = publisher_obj.books.all() # print(ret) # # # 2. 基於雙下划線 # ret = models.Publisher.objects.filter(id=1).values_list("xxoo__title") # print(ret) # 多對多 # 查詢 # author_obj = models.Author.objects.first() # print(author_obj.name) # 查詢金老板寫過的書 # ret = author_obj.books.all() # print(author_obj.books, type(author_obj.books)) # print(ret) # 1. create # 通過作者創建一本書,會自動保存 # 做了兩件事: # 1. 在book表里面創建一本新書,2. 在作者和書的關系表中添加關聯記錄 # author_obj.books.create(title="金老板自傳", publisher_id=2) # 2. add # 在金老板關聯的書里面,再加一本id是4的書 # book_obj = models.Book.objects.get(id=4) # author_obj.books.add(book_obj) # 添加多個 # book_objs = models.Book.objects.filter(id__gt=5) # author_obj.books.add(*book_objs) # 要把列表打散再傳進去 # 直接添加id # author_obj.books.add(9) # remove # 從金老板關聯的書里面把 開飛船 刪掉 # book_obj = models.Book.objects.get(title="跟金老板學開飛船") # author_obj.books.remove(book_obj) # 從金老板關聯的書里面把 id是8的記錄 刪掉 # author_obj.books.remove(8) # clear # 清空 # 把景女神 關聯的所有書都刪掉 # jing_obj = models.Author.objects.get(id=2) # jing_obj.books.clear() # 額外補充的,外鍵的反向操作 # 找到id是1的出版社 # publisher_obj = models.Publisher.objects.get(id=2) # publisher_obj.books.clear() # 聚合 from django.db.models import Avg, Sum, Max, Min, Count # ret = models.Book.objects.all().aggregate(price_avg=Avg("price")) # print(ret) # # ret = models.Book.objects.all().aggregate(price_avg=Avg("price"), price_max=Max("price"), price_min=Min("price")) # print(ret) # print(ret.get("price_max"), type(ret.get("price_max"))) # 分組查詢 # 查詢每一本書的作者個數 # ret = models.Book.objects.all().annotate(author_num=Count("author")) # # print(ret) # for book in ret: # print("書名:{},作者數量:{}".format(book.title, book.author_num)) # 查詢作者數量大於1的書 # ret = models.Book.objects.all().annotate(author_num=Count("author")).filter(author_num__gt=1) # print(ret) # 查詢各個作者出的書的總價格 # ret = models.Author.objects.all().annotate(price_sum=Sum("books__price")).values_list("name", "price_sum") # ret = models.Author.objects.all().annotate(price_sum=Sum("books__price")) # print(ret) # for i in ret: # print(i, i.name, i.price_sum) # print(ret.values_list("id", "name", "price_sum")) # F和Q # ret = models.Book.objects.filter(price__gt=9.99) # print(ret) # 查詢出 庫存數 大於 賣出數的 所有書(兩個字段做比較) from django.db.models import F # ret = models.Book.objects.filter(kucun__gt=F("maichu")) # print(ret) # 刷單 把每一本書的賣出數都乘以3 # obj = models.Book.objects.first() # obj.maichu = 1000 * 3 # obj.save() # 具體的對象沒有update(),QuerySet對象才有update()方法。 # models.Book.objects.update(maichu=(F("maichu")+1)*3) # 給每一本書的書名后面加上 第一版 # from django.db.models.functions import Concat # from django.db.models import Value # # models.Book.objects.update(title=Concat(F("title"), Value("第一版"))) # Q查詢 from django.db.models import Q # 查詢 賣出數大於1000,並且 價格小於100的所有書 # ret = models.Book.objects.filter(maichu__gt=1000, price__lt=100) # print(ret) # 查詢 賣出數大於1000,或者 價格小於100的所有書 # ret = models.Book.objects.filter(Q(maichu__gt=1000) | Q(price__lt=100)) # print(ret) # Q查詢和字段查詢同時存在時, 字段查詢要放在Q查詢的后面 # ret = models.Book.objects.filter(Q(maichu__gt=1000) | Q(price__lt=100), title__contains="金老板") # print(ret) # Django ORM 事務 # try: # from django.db import transaction # # with transaction.atomic(): # # 先創建一個出版社 # new_publisher = models.Publisher.objects.create(name="火星出版社") # # 創建一本書 # models.Book.objects.create( # title="橘子物語", # price=11.11, # kucun=10, # maichu=10, # publisher_id=1000 # 指定一個不存在的出版社id) # ) # except Exception as e: # print(str(e)) # 沒有指定原子操作 # try: # # # 先創建一個出版社 # new_publisher = models.Publisher.objects.create(name="火星出版社") # # 創建一本書 # models.Book.objects.create( # title="橘子物語", # price=11.11, # kucun=10, # maichu=10, # publisher_id=1000 # 指定一個不存在的出版社id # ) # except Exception as e: # print(str(e)) # 執行原生SQL # 更高靈活度的方式執行原生SQL語句 # from django.db import connection # cursor = connection.cursor() # cursor = connections['default'].cursor() # cursor.execute("SELECT * from app01_book where id = %s", [1]) # ret = cursor.fetchone() # print(ret) # 在QuerSet查詢的基礎上自己指定其他的SQL語句(了解即可) ret = models.Book.objects.extra( # 把出版社計數 賦值給newid select={'newid': 'select count(1) from app01_publisher where id>%s'}, select_params=[1, ], where=["app01_book.id=%s"], params=[1, ], tables=['app01_publisher'] ) print(ret) for i in ret: print(i)
5.6、使用jupyter notebook練習ORM
5.6.1、創建工程
使用PyCharm新建Django工程,配置mysql為數據庫。創建app,在app中添加models中的表,表內容如下:
from django.db import models # Create your models here. class Publisher(models.Model): id = models.AutoField(primary_key=True) name = models.CharField(max_length=64,unique=True) # def __str__(self): # return self.name class Book(models.Model): id = models.AutoField(primary_key=True) isbn = models.BigIntegerField(null=False,unique=True) name = models.CharField(max_length=64) price = models.FloatField(null=False) url = models.CharField(max_length=128) publish = models.ForeignKey( to="Publisher", to_field="id", related_name="books", # related_query_name="book_q", on_delete=models.CASCADE) pub_date = models.DateField(null=True,blank=True) # def __str__(self): # return self.name class Author(models.Model): id = models.AutoField(primary_key=True) name = models.CharField(max_length=64) book = models.ManyToManyField(to="Book") # def __str__(self): # return self.name class Translator(models.Model): id = models.AutoField(primary_key=True) name = models.CharField(max_length=64,null=False) book = models.ManyToManyField(to="Book") # def __str__(self): # return self.name
5.6.2、使用admin向數據庫中添加數據
數據內容如下:
| id | isbn | name | author | translator | publisher | pub_date | price | url |
| 1 | 9787115428028 | Python編程 從入門到實踐 | 埃里克·馬瑟斯 | 袁國忠 | 人民郵電出版社 | 64.10 | https://item.jd.com/11993134.html | |
| 2 | 9787115474889 | Python基礎教程(第3版) | Magnus Lie Hetland | 袁國忠 | 人民郵電出版社 | 2018/2/1 | 71.30 | https://item.jd.com/12279949.html |
| 3 | 9787115404831 | Python算法教程 | Magnus Lie Hetland | 凌傑 | 人民郵電出版社 | 54.40 | https://item.jd.com/11841674.html | |
| 4 | 9787512355309 | Python編程(第4版 套裝上下冊) | Mark Lutz | 鄒曉 | 中國電力出版社 | 2014/12/1 | 151.40 | https://item.jd.com/11598704.html |
| 5 | 9787111603702 | 利用Python進行數據分析(原書第2版) | 韋斯·麥金尼 | 徐敬一 | 機械工業出版社 | 2018/8/1 | 92.70 | https://item.jd.com/12398725.html |
| 6 | 9787115480347 | Python 3網絡爬蟲開發實戰 | 崔慶才 | 人民郵電出版社 | 2018/4/1 | 78.20 | https://item.jd.com/12333540.html | |
| 7 | 9787564175191 | Python數據分析 第2版(影印版) | Wes McKinney | 東南大學出版社 | 76.10 | https://item.jd.com/12310353.html |
5.6.3、啟動jupyter notebook,並創建Jupyter notebook文件
在項目根目錄中使用Termial啟動Jupyter notebook,創建Jupyter notebook文件。
5.6.4、在Jupyter notebook文件中操作ORM
加載Django項目的配置信息,導入Django,並啟動Django項目。
import os if __name__ == '__main__': # 加載Django項目的配置信息 os.environ.setdefault("DJANGO_SETTINGS_MODULE", "book_info.settings") # 導入Django,並啟動Django項目 import django django.setup() from app01 import models
操作orm:
ret = models.Author.objects.all() print(type(ret)) print(ret)
Jupyter notebook文件見:https://files.cnblogs.com/files/bad-robot/jupyter-notebook%E4%B8%AD%E6%93%8D%E4%BD%9Corm%E5%8F%82%E8%80%83.zip
