国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發(fā)設計 > 正文

跟我一起Django-04定義和使用模型

2019-11-14 17:34:21
字體:
來源:轉載
供稿:網友

4.1 定義模型

數據模型通常是Web應用程序的基礎,從這里開始探索Django開發(fā)的細節(jié)。

Django的數據庫模型層使用了大量的 ORM(對象關系映射),這一節(jié)

先解釋下 Django的ORM,
然后深入講解模型變量 model field
模型類model class之間可能的關系,
以及通過模型類元數據model class metadata來定義特定行為或者是激活和自定義 Django的 admin應用。

4.1.1 為什么使用ORM

Django和其他大多數現(xiàn)代Web框架一樣,依賴一個強大的DAO,數據訪問層,試圖將底層的關系數據庫和Python的面向對象的特質聯(lián)系起來

使用ORM有4個充分的理由:

  • 封裝有用的方法
  • 可移植性
  • 安全性
  • 表現(xiàn)力

4.1.1.1 封裝有用的方法

Django模型對象是定義變量的首選方式,而變量通常對應的是數據庫的列。

你可以請求一個 id 為 5 的Author對象并檢查其 author.name, 而不必去寫SELECT name from authors WHERE id=5這樣的SQL語句, 這樣要 Pythonic的多。

而且,模型對象能給那個簡陋的例子增加許多額外的價值,Django的ORM可以讓你定義任何實例方法:

  • 定義只讀的變量或者屬性集合,也稱為 數據集合data aggregation或者計算屬性calculated attribute
  • Django的ORM允許重寫內置的數據庫修改方法,例如保存和刪除對象
  • 和編程語言集成(python)通常比較簡單,可以讓你的數據庫對象和特定的接口或API更加一致

4.1.1.2 可移植性

ORM作為應用程序和數據庫之間的代碼層,通常具有很好的可移植性

4.1.1.3 安全性

使用ORM之后很少有機會需要自己執(zhí)行SQL查詢,所以不必擔心保護性很差的查詢字符串導致的問題,如SQL注入攻擊等

而且ORM還提供一個智能化的引用和轉義輸入變量的核心機制,讓你不在花很多時間來處理這種細枝末節(jié)

4.1.1.4 表現(xiàn)力

跟直接編寫SQL相比,ORM最大的好處就是從數據庫中獲取記錄時使用的查詢語法。高級一點的語法不僅更容易編寫,而且這種帶入到Python領域的查詢機制更帶來了一系列有用的技巧和方法。比如,直接循環(huán)一個數據結構,原本在SQL中是相當笨拙的,現(xiàn)在卻簡潔的多,還可以回避本來是無可避免的討厭的字符串操作。

4.1.2 Django豐富的變量類型

Django的模型擁有多種不同變量類型,一些跟它們在數據庫里的實現(xiàn)比較接近,一些則是為Web表單界面而考慮設計

首先來看一個Django模型定義

from django.db import modelsclass Book(models.Model):   title = models.CharField(max_length=100)   author = models.ForeignKey(Author)   length = models.IntergerField()

看來, Django用Python的類來表示對象,而對象則通常映射到SQL中的表,屬性對應列;
這些屬性本身也是對象, 是 Field 類的子類; 如上提到過的,
這些子類有的跟SQL列類型很相似, 其他的則都提供了某種程度的抽象。比如:

  • CharField/TextField -- 都是用于保存文本,區(qū)別在于一個定長,一個無限長
  • EmailField/URLField/ipAddressField -- 就是CharField加上驗證功能
  • BooleanField/NullBooleanField
  • FileField/FilePathField -- FileField只在數據庫中保存了一個文件的路徑,和它接近的FileFieldPath

主鍵和唯一性
如果你沒有明確指定,Django會自動生成主鍵 id(AutoField,自增整數)
如果你希望有更多的控制主鍵,只需要在某個變量上指定 PRimary_key = True,
這個變量會取代 id 成為這個表的主鍵
類似于SQL中的UNIQUE索引,Django也提供了 unique=True的參數

4.1.3 模型之間的關系

定義模型對象之間關系的能力通常是關系數據庫最大的賣點之一, 同時也是ORM之間相互競爭的區(qū)域。Django目前的實現(xiàn)還是圍繞著數據庫展開,確保關系在數據庫層而不是在應用層上定義;然而,由于SQL提供了一種顯式組織關系的方法(外鍵),我們有必要再加入一些抽象來表示更復雜的關系。

4.1.3.1 外鍵(多對一)

class Author(models.Model):    name = models.CharField(max_length=100)class Book(models.Model):    title = models.CharField(max_length=100)	author = models.ForeignKey(Author)

Django的外鍵表現(xiàn)很直觀,其主要參數就是它要引用的模型類;但是注意要把被引用的類放在前面。不過,如果不想留意順序,也可以用字符串代替。

class Book(models.Model):    title = models.CharField(max_length=100)	author = models.ForeignKey("Author")	#if Author class is defined in another file myapp/models.py	author = models.ForeignKey("myapp.Author")class Author(models.Model):   name = models.CharField(max_length=100)

如果要引用自己為外鍵,可以設置 models.ForeignKey("self"),
這在定義層次結構等類似場景很常用,比如Employee類可以具有類似supervisor或是hired_by這樣的屬性

外鍵ForeignKey只定義了關系的一端,但是另一端可以根據關系追溯回來,因為這是一種多對一的關系,多個子對象可以引用同一個父對象,而父對象可以訪問到一組子對象。看下面的例子:

#取一本書“Moby Dick”book = Book.objects.get(title="Moby Dick")#取作者名字author = Book.author#獲取這個作者所有的書books = author.book_set.all()

這里從Author到Book的反向關系式通過Author.book_set屬性來表示的(這是一個manager對象),是由ORM自動添加的,
可以通過在 ForeignKey里指定 related_name參數來改變它的名字。比如:

class Book(models.Model):    ... ...	... ...	author = models.ForeignKey("Author", related_name = "books")... ...... ...#獲取這個作者所有的書books = author.books.all()

對簡單的對象層次來說,related_name不是必需的,但是更復雜的關系里,比如當有多個ForeignKey的時候就一定要指定了。

4.1.3.2 多對多

上面的例子假設的是一本書只有一個作者,一個作者有多本書,所以是多對一的關系;但是如果一本書也有多個作者呢?

這就是多對多的關系;由于SQL沒有定義這種關系,必須通過外鍵用它能理解的方式實現(xiàn)多對多

這里Django提供了第二種關系對象映射變量ManyToManyField

語法上來講, 這和 ForeignKey是一模一樣的,你在關系的一端定義,把要關聯(lián)的類傳遞進來,ORM會自動為另一端生成使用這個關系必要的方法和屬性

不過由于 ManyToManyField的特性,在哪一端定義它通常都沒有關系,因為這個關系是對稱的

class Author(models.Model):    name = models.CharField(max_length=100)class Book(models.Model):    title = models.CharField(max_length=100)	authors = models.ManyToManyField(Author)#獲取一本書book = Book.objects.get(title="Python Web Dev Django")#獲取該書所有的作者authors = Book.author_set.all()#獲取第三個作者出版過的所有的書books = authors[2].book_set.all()

ManyToManyField的秘密在于它在背后創(chuàng)建了一張新的表來滿足這類關系的查詢的需要,而這張表用的則是SQL外鍵,其中每一行都代表了兩個對象的一個關系,同時包含了兩端的外鍵
這張查詢表在Django
ORM中一般是隱藏的,不可以單獨查詢,只能通過關系的某一端查詢;不過可以在
MTMField上指定一個特殊的選項through來指向一個顯式的中間模型類,更方便你的手動管理關系的兩端

class Author(models.Model):    name = models.CharField(max_length=100)class Book(models.Model):    title = models.CharField(max_length=100)	authors = models.ManyToManyField(Author, through = "Authoring")class Authoring(models.Model):    collaboration_type = models.CharField(max_length=100)	book = model.ForeignKey(Book)	author = model.ForeignKey(Author)

查詢Author和Book的方法和之前完全一樣,另外還能構造對authoring的查詢

chan_essay_compilations = Book.objects.filter(    author__name__endswith = 'Chun'	authoring__collaboration_type = 'essays')

如此,Django在創(chuàng)建關系的能力上就顯得更靈活了

4.1.3.3 用一對一關系進行組合

類似的,Django提供了OneToOneField屬性,幾乎和ForeignKey一樣,接受一個參數(要關聯(lián)的類或者"self"),同樣也接受一個可選參數related_name,這樣就可以在兩個相同的類里區(qū)分出多個這樣的關系來。
不同的是,OTOField沒有在反向關系中添加reverse manager,而只是增加了一個普通屬性而已,因為關系的另一端一定只有一個對象。

這種關系最常用的是用來支持對象組合或者是擁有關系,所以相比現(xiàn)實世界,它更加面向對象一點。

在Django直接支持模型繼承(model inheritance)之前,OTOField主要是用來實現(xiàn)模型繼承, 而現(xiàn)在,則是轉向對這個特性的幕后支持了。

限制關系
關于定義關系的最后一點, ForeignKey 和 MTMField 都可以指定一個> limit_choices_to參數,這個參數接受一個字典,鍵值對是查詢的關鍵字和值

class Author(models.Model):    name = models.CharField(max_length=100)class SmithBook(models.Model):    title = models.CharField(max_length=100)	authors = models.ManyToManyField(Author, limit_choices_to={	    'name__endswith' : 'Smith'	})

這個例子中,Book模型就只能和姓Smith的Authors類一起工作。當然這個問題最好用另一種解決方案--ModelChoiceField,ModelMultipleChoiceField

4.1.3.4 模型繼承

Django 的ORM中一個相對新的特性就是 模型繼承 model inheritance;
兩個模型之間除了外鍵以及其他關系之外,還可以和普通的、非ORM的Python類一樣,通過從另一個模型繼承來定義模型。

模型繼承,子類通過添加或者是重寫變量來和父類區(qū)分開來,而不需要重寫整個類的定義。

Django目前支持2種不同的繼承方式,每種都有自身的優(yōu)缺點:

  • abstract base class 抽象基礎類 -- 純Python的繼承
  • multi-table inheritance 多表繼承
class Author(models.Model):    name = models.CharField(max_length=100)class Book(models.Model):    title = models.CharField(max_length=100)	genre = models.CharField(max_length=100)	num_pages = models.IntergerField()	authors = models.ManyToManyField(Author)	def __unicode__(self):	    return self.title    class Meta:	    abstract = Trueclass SmithBook(Book):    authors = models.ManyToManyField(Author, limit_choices_to = {	    'name_endswith': 'Smith'	})

這個例子,抽象基礎類方式繼承,純Python的繼承, 允許重構Python模型的定義,這樣變量和方法都可以從基類中繼承下來。然而在數據庫和查詢層上并沒有基類的概念,子類在數據庫的表其實還是復制了基類的一個變量,而不是為基類創(chuàng)建一張額外的數據表

另外,這里代碼的關鍵是 abstract = True設置, 指明了Book是一個抽象基礎類,只是用來為它實際的模型子類提供屬性而存在的。

再說說多表繼承, 同樣,還是會用到Python的 類繼承, 但是不再需要 abstract = True這個 Meta類選項了。

在檢查模型實例或是查詢的時候,多表繼承和前面看到的一樣,子類會從父類中繼承所有的屬性和方法

主要的區(qū)別在于,底層的機制。在這兒,父類是擁有自己數據表的完整的Django模型,可以正常的實例化,同時還能把自己的屬性借給子類,其實,這是通過自動在子類和父類之間設置了一個OneToOneField,以及幕后一些小手段把兩個對象連在一起實現(xiàn)的,所以,子類才能繼承父類的屬性。

因此,多表繼承其實就是對普通的has-a關系(或者說對象組合)的一個方便的包裝

class Author(models.Model):    name = models.CharField(max_length=100)class Book(models.Model):    title = models.CharField(max_length=100)	genre = models.CharField(max_length=100)	num_pages = models.IntegerField()	authors = models.ManyToManyField(Author)	def __unicode__(Book):	    return self.titleclass SmithBook(Book):    authors = models.ManyToManyField(Author, limit_choices_to={	    'name_endswith':'Smith'	})

這里唯一的不同是,沒有了Meta abstract 選項。那結果是什么呢?

在一個空數據庫和這個models.py文件上運行 manage.py syncdb會創(chuàng)建三張表 Author, Book, SmithBook

而抽象基礎類的情況下,只創(chuàng)建了 Author, SmithBook 兩張表。

注意 SmithBook 實例得到的 book_ptr屬性會指向和他們組合的Book實例,而屬于SmithBook的Book實例會得到一個 smithbook屬性。

之所以說多表繼承更適合我們這個Smithbook的例子,因為我們可以同時實例化普通的Book對象以及SmithBook對象。而實際應用過程中,也是多表繼承要比抽象基礎類好用的多。

4.1.3.5 Meta嵌套類

模型里定義的變量fields和關系relationships提供了數據庫的布局以及稍后查詢模型時要用的變量名--經常你還需要添加__unicode__ 和 get_absolute_url 方法或是重寫 內置的 save 和 delete方法。

然而,模型的定義還有第三個方面--告知Django關于這個模型的各種元數據信息的嵌套類Meta

Meta類處理的是模型的各種元數據的使用和顯示:

  • 比如在一個對象對多個對象是,它的名字應該怎么顯示;
  • 查詢數據表示默認的排序順序是什么?
  • 數據表的名字是什么
  • 多變量唯一性 (這種限制沒有辦法在每個單獨的變量聲明上定義)
class Person(models.Model):    first = models.CharField(max_length=100)	last = models.CharField(max_length=100)	middle = models.CharField(max_length=100, blank=True)	class Meta:	    ordering = ['last', 'first', 'middle']	    unique_together = ['first', 'last', 'middle']	    #Django默認的復數形式是加 s,這里不適用	    verbose_name_plural = "people"

4.1.3.6 Admin注冊和選項

2 使用模型

2.1 用manage.py創(chuàng)建和更新數據庫

2.1.1 syncdb

創(chuàng)建所有的應用程序所需要的數據表
并不是對整個DB進行一次完整的同步,只是保證所有的模型類都有對應的數據表,在必要的時候創(chuàng)建為模型創(chuàng)建新的表,但是不會修改已經存在的表
因此,如果你創(chuàng)建模型,運行syncdb將它載入DB,然而改變這個模型時,syncdb不會試圖去和DB協(xié)調這些改動,需要程序員自己去

  • 手動修改
  • 通過腳本修改
  • 直接刪掉數據表或者整個數據庫然后哦重新執(zhí)行syncdb

原創(chuàng)文章:http://m.survivalescaperooms.com/ganiks

2.1.2 sql*

  • sql
    顯示 CREATETABLE調用
  • sqlall
    跟sql一樣從.sql文件中初始化數據載入語句
  • sqlindexes
    顯示對主鍵創(chuàng)建索引的調用
  • sqlclear
    顯示Drop Table調用
  • sqlreset
    sqlclear和sql的組合
    顯示DROP+CREATE
  • sqlcustom
    執(zhí)行應用程序自定義initial SQL

2.1.3 loaddata

載入初始數據, 和sqlcustom類似,但是沒有原始SQL

2.1.4 dumpdata

把現(xiàn)有數據庫里的數據輸出為JSON、xml格式

2.2 查詢

2.2.1 Manager類

總是附在模型類里,除非有特別指定,每個模型類都會展示一個objects屬性,它構成了這個模型在數據庫所有的基本查詢
Manager是從數據庫獲取信息的門戶

  • all
    返回一個包含模式里所有數據庫記錄的QuerySet
  • filter
    返回一個包含符合指定條件的模型記錄的QuerySet
  • exclude
    和filter相反--查找不符合條件的那些記錄
  • get
    獲取單個符合條件的記錄(沒找到或者是>1個記錄都將拋出異常)

2.2.2 QuerySet類

模型類實例的列表,或者說是數據庫行記錄的列表

2.2.3 查詢語法

將QuerySet作為數據庫查詢

books_about_trees = Book.objects.filter(title__contain="Trees")SELECT * FROM myapp_book WHERE title LIKE "%Tree%" john_does = Person.objects.filter(last="Doe", first="John")everyone = Person.objects.all()

之前提到的Meta嵌套類里定義的哪些各種和查詢相關的選項都會影響所生成的SQL
ordering->ORDER BY
QuerySet被當做一個數據庫查詢的始發(fā)端,接受動態(tài)的關鍵字參數然后轉化成合適的SQL

  • contain
  • gt
  • get
  • in
  • ... ...

將QuerySet作為容器

QuerySet像一個列表,實現(xiàn)了一部分列表的接口

  • 迭代 for record in queryset:
  • 索引 queryset[0]自動轉換成SQL的 OFFSET
  • 切片 queryset[:5] 自動轉換成SQL 的LIMIT
  • 獲取長度 len(queryset)
  • ... ...

最好不要把QuerySet通過list函數轉換成一個真正的列表,因為如果QuerySet很大的話,會導致內存或者數據庫很大的負擔

QuerySet是懶惰的,只有在必要時才會去執(zhí)行數據庫查詢

  • 當被轉換成list迭代、索引、切片、獲取長度操作時
  • 組合QuerySet查詢

    Person.objects.filter(last="Doe").filter(first="John").filter(middle="Quincy")
    overdue_books = book_queryset.filter(due_data_lt=datetime.now())
    nonfiction
    smithBook.objects.fitler(author__last="Smith").exclude(genre="Fiction")

查詢結果排序

all_sorted_first = Person.objects.all().order_by('first')all_sorted_first_five = Person.objects.all().order_by('first')[:5]sorted_by_state = Person.objects.all().order_by('address__state', 'last')

Person有一個FK包含了一個Address, Address中包含一個state變量,這里希望按照state,再按照姓氏排序

其他改變查詢的方法

  • order_by
  • reverse
  • distinct
  • values
    Person.objects.values('first')
    [{'first': u'John'}, {'first': u'Jane'}]
  • values_list
    Person.objects.values_list('last')
    [(u'Doe',),(u'Doe',)]
  • select_related
    Person.objects.all().select_related('address', depth=1)
  • 用Q和~Q組合查詢關鍵字
    specific_does = Person.objects.filter(last="Doe").exclude(Q(first="John")|Q(middle="Quincy"))
    specific_does = Person.objects.filter(Q() | (Q() & Q() &~Q()))
  • 用Extra調整SQL

    • select 修改SELECT語句
    • where 提供額外的WHERE子句
    • tables 提供額外的表
    • params 安全的替換動態(tài)參數

2.3 利用Django沒有提供的SQL特性

2.3.1 定義模式schema和定制initial SQL

通過initial SQL,將模式定義命令存放在Django項目中,當Django的工具來創(chuàng)建或者重新創(chuàng)建DB時,*.sql會被包含近來

myproject/myapp/sql/triggers.sql
  • 視圖
  • 觸發(fā)器和聯(lián)級
  • 自定義函數和數據類型

2.3.2 Fixtures: 載入和導出數據

類似initial SQL,每個Django項目有一個fixtures目錄,里面存放XML YAML 或者JSON數據文件,在運行數據庫創(chuàng)建或者重設命令的時候會運行
這個特性的主要作用在于比如要將數據從PostgreSQL導出數據和導入數據

myproject/myapp/fixtures/initial_data.json

2.3.3 自定義SQL查詢

導入django.db中定義的connection對象,獲取數據庫游標進行查詢

cursor = connection.cursor()cursor.execute("SELECT first, last FROM myapp_person WHERE last='Doe'")doe_rows = cursor.fetchall()

本文結束。

附件:

思維導圖全圖:http://images.VEVb.com/VEVb_com/ganiks/618830/o_%E6%A8%A1%E5%9E%8B.JPG


發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 扎赉特旗| 桐梓县| 搜索| 石狮市| 龙山县| 绥滨县| 江孜县| 阿荣旗| 长寿区| 诸暨市| 楚雄市| 仪征市| 乌鲁木齐市| 灌阳县| 梁山县| 马关县| 东港市| 房产| 长沙市| 察雅县| 大荔县| 密云县| 花垣县| 三原县| 岚皋县| 阿勒泰市| 曲松县| 碌曲县| 瑞昌市| 西充县| 普兰店市| 伊川县| 永吉县| 嘉义县| 玛曲县| 台前县| 友谊县| 思茅市| 大港区| 贞丰县| 孝昌县|