Django學習筆記6

模型層:Object Relational Mapping(ORM)

ORM

  • 定義

ORM是Object Relational Mapping的簡稱,中文翻譯爲對象關係模型,是一種爲了解決面向對象與關係數據庫存在的互不匹配的現象的技術,ORM在業務邏輯層和數據庫層之間充當了橋樑的做用。html

  • 由來

讓咱們從O/R開始。字母O起源於"對象"(Object),而R則來自於"關係"(Relational)。python

幾乎全部的軟件開發過程當中都會涉及到對象和關係數據庫。在用戶層面和業務邏輯層面,咱們是面向對象的。當對象的信息發生變化的時候,咱們就須要把對象的信息保存在關係數據庫中。mysql

按照以前的方式來進行開發就會出現程序員會在本身的業務邏輯代碼中夾雜不少SQL語句用來增長、讀取、修改、刪除相關數據,而這些代碼一般都是重複的git

  • 本質

每一個模型都是一個Python類,它是django.db.models.Model的子類。程序員

  • 優點

ORM解決的主要問題是對象和關係的映射,按照規定的語法寫,自動翻譯成對應的SQL語句.sql

1.不用本身寫SQL語句
2. 開發效率高數據庫

  • 劣勢

ORM的缺點是會在必定程度上犧牲程序的執行效率。django

ORM用多了SQL語句就不會寫了,關係數據庫相關技能退化...後端

  • ORM能作的事兒:

1. 操做數據表 ===> 建立表/刪除表/修改表
操做models.py裏面的類
2. 操做數據行 ===> 數據的增刪改查
不能建立數據庫,本身動手建立數據庫數組

Django中的ORM

Django項目如何使用ORM鏈接MySQL

1. 手動建立數據庫
2. 在settings.py裏面,配置數據庫的鏈接信息

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'booksystem',
        'HOST': '127.0.0.1',
        'PORT': 3306,
        'USER': 'root',
        'PASSWORD': 'root',
    }
}

3. 在項目/__init__.py告訴Django用pymysql模塊代替MySQLdb來鏈接MySQL數據庫

import pymysql
pymysql.install_as_MySQLdb()

4. 在app/models.py裏面定義類

# 做者類
class Author(models.Model):
    id = models.AutoField(primary_key=True)  # 自增的ID主鍵
    name = models.CharField(max_length=16, null=False, unique=True)
    book = models.ManyToManyField(to="Book")  # 建立做者表和書籍表多對多的關係
    # 多對多的關係會在數據庫中另建立一個新的對應關係表,只存放id的對應關係

    def __str__(self):
        return "<Author object>: {}".format(self.name)

5. 執行兩個命令

在哪兒執行?
在項目的根目錄(有manage.py文件的那個目錄)

  • python3 manage.py makemigrations --> 把models.py裏面的更改記錄到小本本上
  • python3 manage.py migrate --> 把更改翻譯成SQL語句,去數據庫執行

簡單使用

下面這個例子定義了一個 Person 模型,包含 first_name 和 last_name

from django.db import models

class Person(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)

first_name 和 last_name 是模型的字段。每一個字段被指定爲一個類屬性,每一個屬性映射到一個數據庫列。

上面的 Person 模型將會像這樣建立一個數據庫表:

CREATE TABLE myapp_person (
    "id" serial NOT NULL PRIMARY KEY,
    "first_name" varchar(30) NOT NULL,
    "last_name" varchar(30) NOT NULL
);

一些說明:

  • 表myapp_person的名稱是自動生成的,若是你要自定義表名,須要在model的Meta類中指定 db_table 參數,強烈建議使用小寫表名,特別是使用MySQL做爲後端數據庫時。
  • id字段是自動添加的,若是你想要指定自定義主鍵,只需在其中一個字段中指定 primary_key=True 便可。若是Django發現你已經明確地設置了Field.primary_key,它將不會添加自動ID列
  • 本示例中的CREATE TABLE SQL使用PostgreSQL語法進行格式化,但值得注意的是,Django會根據配置文件中指定的數據庫後端類型來生成相應的SQL語句。
  • Django支持MySQL5.5及更高版本。

字段類型

單表字段類型

  • 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

  • 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

參數(上面兩個都能用):

auto_now_add = True 建立數據行時(對象)就會把當前時間添加到數據庫
auto_now = True 每次修改數據行(對象)時會把當前時間添加到數據庫中
  • TimeField(DateTimeCheckMixin, Field)

- 時間格式 HH:MM[:ss[.uuuuuu]]

  • DurationField(Field)

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

  • FloatField(Field)

- 浮點型

  • DecimalField(Field)

- 10進制小數
- 參數:

max_digits,小數總長度
decimal_places,小數位長度
  • BinaryField(Field)

- 二進制類型

抽象基類

當你想將一些共有信息放進其它一些model的時候,抽象化類是十分有用的。 你編寫完基類以後,在 Meta類中設置 abstract=True , 這個模型就不會被用來建立任何數據表。 取而代之的是,當它被用來做爲一個其餘model的基類時,它的字段將被加入那些子類中。 若是抽象基類和它的子類有相同的字段名,那麼將會出現error(而且Django將拋出一個exception)。

一個例子

from django.db import models

class CommonInfo(models.Model):
    name = models.CharField(max_length=100)
    age = models.PositiveIntegerField()

    class Meta:
        abstract = True

class Student(CommonInfo):
    home_group = models.CharField(max_length=5)

  Student 模型將有三個字段:nameage和 home_group。 CommonInfo 模型沒法像通常的Django模型同樣使用,由於它是一個抽象基類。 它沒法生成一張數據表或者擁有一個管理器,而且不能實例化或者直接儲存。

許多應用場景下, 這種類型的模型繼承剛好是你想要的。 它提供了一種在Python層面排除常見信息的方法,同時仍然只在數據庫層面爲每一個子模型建立一個數據庫表。

meta繼承:

當一個抽象基類被建立的時候, Django把你在基類內部定義的 Meta 類做爲一個屬性使其可用。 若是子類沒有聲明本身的Meta類, 它將會繼承父類的Meta若是子類想要擴展父類的Meta類,它能夠子類化它。 例如:

from django.db import models

class CommonInfo(models.Model):
    # ...
    class Meta:
        abstract = True
        ordering = ['name']

class Student(CommonInfo):
    # ...
    class Meta(CommonInfo.Meta):
        db_table = 'student_info'

Django確實會對抽象基類的Meta類作一個調整:在設置Meta屬性以前,Django會設置abstract=False。 這意味着抽象基類的子類自己不會自動變成抽象類。固然,你可讓一個抽象基類繼承自另外一個抽象基類, 你只要記得每次都要顯式地設置 abstract=True

 

關聯關係字段

Django還定義一系列字段來描述數據庫之間的關聯。

ForeignKey(多對一

class  ForeignKey(toon_delete**options)

多對一關係。要求兩個位置參數:模型相關的類和on_delete選項。 on_delete實際上並非必需的,但不提供它會給出已廢棄的警告。 在Django 2.0中將須要它。)

若要建立遞歸關聯關係 ——————— 一個對象與本身具備多對一關聯關係 — 請使用models.ForeignKey('self', on_delete=models.CASCADE)

  • 引用關係(三種狀況)

若是你須要關聯到一個還沒有定義的模型,你可使用模型的名字而不用模型對象自己:

from django.db import models

class Car(models.Model):
    manufacturer = models.ForeignKey(
        'Manufacturer',  # 同一個應用下的表直接使用名字便可,不一樣應用的要'app_name'.'table_name'(即便用app名加表名)
        on_delete=models.CASCADE,
    )
    # ...

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

抽象模型上定義的這種關聯關係在模型子類化爲具體模型時解析,而且不相對於抽象模型的app_label

products/models.py
from django.db import models

class AbstractCar(models.Model):
    manufacturer = models.ForeignKey('Manufacturer', on_delete=models.CASCADE)

    class Meta:
        abstract = True
production/models.py
from django.db import models
from products.models import AbstractCar

class Manufacturer(models.Model):
    pass

class Car(AbstractCar):
    pass

# Car.manufacturer將指向這裏的`production.Manufacturer`。

若要引用在其它應用中定義的模型,你能夠用帶有完整標籤名的模型來顯式指定。 例如,若是上面的Manufacturer模型是在一個名爲production的應用中定義的,你應該這樣使用它:

class Car(models.Model):
    manufacturer = models.ForeignKey(
        'production.Manufacturer',
        on_delete=models.CASCADE,
    )

這種稱爲懶惰關係的引用在解析兩個應用程序之間的循環導入依賴關係時可能頗有用。

  • 數據庫表示

在幕後,Django 會在字段名上添加"_id" 來建立數據庫中的列名。 在上面的例子中,Car 模型的數據庫表將會擁有一個manufacturer_id 列。 (你能夠經過指定db_column來顯式更改)可是,除非你編寫自定義SQL,不然代碼不該該處理數據庫列名。 你應該永遠只處理你的模型對象中的字段名稱。

ForeignKey 會自動建立數據庫索引。 你能夠經過設置db_index 爲False 來取消。 若是你建立外鍵是爲了一致性而不是用來Join,或者若是你將建立其它索引例如部分或多列索引,你也許想要避免索引的開銷。

  • 參數

ForeignKey.to
  要進行關聯的表名,to=「User」和to=User,to本質是和類作關聯,當User類在當前模塊被導入時,才能夠不加雙引號,不然要加雙引號
ForeignKey.on_delete
   當刪除由ForeignKey引用的對象時,Django將模擬由on_delete參數指定的SQL約束的行爲。  自1.9版以來已棄用 on_delete將成爲Django 2.0中必需的參數。 在舊版本中,默認爲CASCADE。
  • CASCADE
    級聯刪除,刪除關聯數據,與之關聯也刪除,Django模擬SQL約束ON DELETE CASCADE的行爲,並刪除包含ForeignKey的對象。
  • PROTECT
    拋出 ProtectedError 以阻止被引用對象的刪除,它是 django.db.IntegrityError 的一個子類。
  • SET_NULL

    刪除關聯數據,與之關聯的值設置爲null(前提FK字段須要設置爲可空)

  • SET_DEFAULT
    刪除關聯數據,與之關聯的值設置爲默認值(前提FK字段須要設置默認值)
  • SET()
    設置 ForeignKey 爲傳遞給 SET() 的值,若是傳遞的是一個可調用對象,則爲調用後的結果。  在大部分情形下,傳遞一個可調用對象用於避免models.py 在導入時執行查詢:
    a. 與之關聯的值設置爲指定值,設置:
    models.SET(值)
    b. 與之關聯的值設置爲可執行對象的返回值,設置:
    class MyModel(models.Model):
        user = models.ForeignKey(
            to="User",
            to_field="id",
            on_delete=models.SET(func), 
        )
  • DO_NOTHING

    不採起任何動做。 若是您的數據庫後端強制引用完整性,除非手動添加SQL ON DELETE約束,不然將致使IntegrityError到數據庫字段。

ForeignKey.limit_choices_to

當這個字段使用ModelForm或者Admin 渲染時(默認狀況下,查詢集中的全部對象均可以使用),爲這個字段設置一個可用的選項。 它能夠是一個字典、一個Q 對象或者一個返回字典或Q對象的可調用對象。

# 在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) | 
ForeignKey.related_name

反向操做時,使用的字段名,用於代替 【表名_set】 如: obj.表名_set.all()。它仍是related_query_name 的默認值。

若是你不想讓Django 建立一個反向關聯,請設置related_name 爲 '+' 或者以'+' 結尾。 例如,下面這行將肯定User 模型將不會有到這個模型的返回關聯:

user = models.ForeignKey(
    User,
    on_delete=models.CASCADE,
    related_name='+',
)
ForeignKey.related_query_name

反向操做時,使用的鏈接前綴,用於替換【表名】 如:

models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名')

  用於過濾器或者value,不直接用於.後面

ForeignKey.to_field

關聯到的關聯對象的字段名稱。 默認地,Django 使用關聯對象的主鍵。 若是引用其餘字段,該字段必須具備unique=True

ForeignKey. db_constraint

控制是否在數據庫中爲這個外鍵建立約束。 默認值爲True,這幾乎是你想要的;將此設置爲False可能對數據完整性很是不利。 即使如此,有一些場景你也許想要這麼設置:

  • 你有遺留的無效數據。
  • 你正在對數據庫縮容。

若是被設置成False,訪問一個不存在的關聯對象將拋出 DoesNotExist 異常。

ManyToManyField(多對多)

class  ManyToManyField(to**options)[source]

一個多對多關聯。關聯的對象能夠經過字段的RelatedManager 添加、刪除和建立。

數據庫表示

在幕後,Django 建立一箇中間表來表示多對多關係。 默認狀況下,這張中間表的名稱使用多對多字段的名稱和包含這張表的模型的名稱生成。 由於某些數據庫支持的表的名字的長度有限制,這些表的名稱將自動截短到64 個字符並加上一個惟一性的哈希值。 這意味着你可能會看到像author_books_9cdf4這樣的表名;這是徹底正常的。 你可使用db_table選項手工提供中間表的名稱。

參數

  • ManyToManyField.to
  • ManyToManyField.to_filed
  • ManyToManyField.on_delete
  • ManyToManyField.related_name
  • ManyToManyField.related_query_name

上面幾個屬性參考foreignerkey的參數便可相同。

  • ManyToManyField.limit_choices_to

ForeignKey.limit_choices_to 相同。

ManyToManyField 對於使用through 參數自定義中間表的limit_choices_to 不生效。

  • ManyToManyField.symmetrical

只用於與自身進行關聯的ManyToManyField。 例以下面的模型:

from django.db import models

class Person(models.Model):
    friends = models.ManyToManyField("self")

當Django 處理這個模型的時候,它定義該模型具備一個與自身具備多對多關聯的ManyToManyField,所以它不會向person_set 類添加Person 屬性。 Django 將假定這個ManyToManyField 字段是對稱的 —— 若是我是你的朋友,那麼你也是個人朋友。

若是你但願與self 進行多對多關聯的關係不具備對稱性,能夠設置symmetrical 爲False。 這會強制讓Django 添加一個描述器給反向的關聯關係,以使得ManyToManyField 的關聯關係不是對稱的。

  • ManyToManyField.through    (使用本身指定的第三方表)

Django 會自動建立一個表來管理多對多關係。 不過,若是你但願手動指定中介表,可使用through 選項來指定Django 模型來表示你想要使用的中介表。

這個選項最多見的使用場景是當你想要關聯更多的數據到關聯關係的時候。

若是你沒有顯式指定through 的模型,仍然會有一個隱式的through 模型類,你能夠用它來直接訪問對應的表示關聯關係的數據庫表。 它由三個字段來連接模型。

若是源模型和目標不一樣,則生成如下字段:

  • id:關係的主鍵。
  • <containing_model>_id:聲明瞭ManyToManyField的模型的id
  • <other_model>_id: 被ManyToManyField所指向的模型的id

若是ManyToManyField 的源模型和目標模型相同,則生成如下字段:

  • id:關係的主鍵。
  • from_<model>_id:源模型實例的id
  • to_<model>_id:目標模型實例的id

這個類可讓一個給定的模型像普通的模型那樣查詢與之相關聯的記錄。

  • ManyToManyField.through_fields

只能在指定了自定義中間模型的時候使用。 Django 通常狀況會自動決定使用中間模型的哪些字段來創建多對多關聯。 可是,考慮以下模型:

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)

Membership兩個 foreign keys指向 Person (person and inviter), 這樣會致使關係不清晰,Django不知道使用哪個外鍵。 在這種狀況下,你必須使用through_fields 明確指定Django 應該使用哪些外鍵,就像上面例子同樣。

through_fields 接受一個2元數組 ('field1', 'field2'), 其中 field1是指向定義了ManyToManyField的那個model的 foreign key的名字(在本例中就是group,它本身定義了M2M字段,同時也在中間模型中被ForeignKey所指向 ), and field2就是目標模型的foreign key 的名字 (person in this case).

當中間模型具備多個外鍵指向多對多關聯關係模型中的任何一個(或兩個),你必須 指定through_fields。 這通用適用於recursive relationships,當用到中間模型而有多個外鍵指向該模型時,或當你想顯式指定Django 應該用到的兩個字段時。

遞歸的關聯關係使用的中間模型始終定義爲非對稱的,也就是symmetrical=False —— 因此具備源和目標的概念。 這種狀況下,'field1' 將做爲管理關係的源,而'field2' 做爲目標。

  • ManyToManyField.db_table

爲存儲多對多數據而建立的表的名稱。 若是沒有提供,Django 將基於定義關聯關係的模型和字段假設一個默認的名稱。

  • ManyToManyField.db_constraint

控制中間表中的外鍵是否建立約束。 默認值爲True,這幾乎是你想要的;將此設置爲False可能對數據完整性很是不利。 即使如此,有一些場景你也許想要這麼設置:

  • 你有遺留的無效數據。
  • 你正在對數據庫縮容。

不能夠同時傳遞db_constraint 和 through

OneToOneField(一對一)

class  OneToOneField(toon_deleteparent_link=False**options)[source]

一對一關聯關係。 概念上講,這個字段相似ForeignKey設置了unique=True,不一樣的是關聯關係的另外一邊會直接返回單個對象。選定了之後別的不能選了,不像多對一,別的還能選

何時用一對一?
當 一張表的某一些字段查詢的比較頻繁,另一些字段查詢的不是特別頻繁,把不怎麼經常使用的字段,單獨拿出來作成一張表,而後用過一對一關聯起來。

一對一關係使用案例

# 做者
class Author(models.Model):
    name = models.CharField(max_length=32)
    age = models.IntegerField()
    phone = models.IntegerField()
    books = models.ManyToManyField(to="Book", related_name="authors")
    detail = models.OneToOneField(to="AuthorDetail")

    def __str__(self):
        return self.name


# 做者詳情
class AuthorDetail(models.Model):
    # 愛好
    hobby = models.CharField(max_length=32)
    # 地址
    addr = models.CharField(max_length=128)

  注意:一對一關係時,默認值會很差使,覺得這列不能有相同的,全爲none也不行

若是你沒有指定OneToOneField 的related_name 參數,Django 將使用當前模型的小寫的名稱做爲默認值。

例以下面的例子:

from django.conf import settings
from django.db import models

class MySpecialUser(models.Model):
    user = models.OneToOneField(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
    )
    supervisor = models.OneToOneField(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name='supervisor_of',
    )

你將使得User 模型具備如下屬性:

>>> user = User.objects.get(pk=1)
>>> hasattr(user, 'myspecialuser')
True
>>> hasattr(user, 'supervisor_of')
True

自定義字段

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

  自定義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)

  建立的表結構:

字段通用參數

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': '格式錯誤'}

從數據庫中逆向生成ORM

正常狀況在models.py中寫下ORM語句,而後使用makemigrations和migrate便可將models中表結構映射到數據庫中,當有了數據庫的表結構卻沒有ORM又該如何呢?下面是從數據庫中逆向生成ORM的方法:

首先呢:咱們就須要根據數據庫去自動生成新的models文件

python manage.py inspectdb    #簡單能夠看一下自動映射成的models中的內容

  這個語句只會將ORM語句輸出到控制檯中,並無將其保存到文件裏,能夠手動將這些代碼保存到文件裏,也可使用下面的語句。

導出而且去代替models.py

python manage.py inspectdb > models.py

  這樣你就會發如今manage.py的同級目錄下生成了一個models.py文件,使用這個models.py文件覆蓋app中的models文件,或者將文件裏的語句複製到你本身的models.py文件中。

文件的頭部提示信息以下:

# This is an auto-generated Django model module.
# You'll have to do the following manually to clean this up:
#   * Rearrange models' order
#   * Make sure each model has one field with primary_key=True
#   * Make sure each ForeignKey has `on_delete` set to the desired behavior.
#   * Remove `managed = False` lines if you wish to allow Django to create, modify, and delete the table
# Feel free to rename the models, but don't rename db_table values or field names.

  若是完成了以上的操做,生成的是一個不可修改/刪除的models(managed=False),修改meta class中的managed = True則能夠去告訴django能夠對數據庫進行操做,下面解釋managed屬性的意義

managed:

Options. managed
默認爲True,表示Django會經過migrate建立合適的數據表,而且可經過flush管理命令移除這些數據庫表。 換句話說,Django會管理這些數據表的生命週期。 若是是False,Django 就不會爲當前模型建立和刪除數據表。 若是當前模型表示一個已經存在的且是經過其它方法建立的者數據表或數據庫視圖,這會至關有用。 這是設置爲managed=False惟一的不一樣之處。 模型處理的其它任何方面都和日常同樣。 這包括:
  1. 若是你不聲明它的話,會向你的模型中添加一個自增主鍵。 爲了不給後面的代碼讀者帶來混亂,當你在使用未被管理的模型時,強烈推薦你指定(specify)數據表中全部的列。
  2. 若是一個模型設置了managed=False且含有ManyToManyField,且這個多對多字段指向其餘一樣也是未被管理模型的,那麼這兩個未被管理的模型的多對多中介表也不會被建立。 可是,一個被管理模型和一個未被管理模型之間的中介表就會被建立。若是你須要修改這一默認行爲,建立中介表做爲顯式的模型(也要設置managed),而且使用ManyToManyField.through爲你的自定義模型建立關聯。
若是你進行測試,測試中涉及非託管 model ( managed=False),那麼在測試以前,你應該要確保在 測試啓動時 已經建立了正確的數據表。 若是你對在Python層面修改模型類的行爲感興趣,你能夠設置 managed=False ,而且爲一個已經存在的模型建立一個副本。 不過在面對這種狀況時還有個更好的辦法就是使 用Proxy models.

補充:

自定義表名,列名

在咱們建立一個模型時,Django的ORM會根據應用名(app name), 模型名(model name)和字段名(field name)自動在數據庫中建立數據表。好比咱們有一個Blog的應用,裏面有Article模型, 其中Article模型有title這個字段,那麼Django默認會建立一個名爲blog_article的數據表,其中有title這個字段。假如咱們但願把表名改成article,標題改成article_title,以便與已經存在的數據表或字段創建映射關係,咱們能夠按以下代碼操做。

class Article(models.Model):
   """文章模型"""
  
   # 經過db_column自定義數據表中字段名
  title = models.CharField('標題', max_length=200, db_column='article_title')
   slug = models.SlugField('slug', max_length=60, blank=True)
   
   def __str__(self):
       return self.title
       
   class Meta:
       db_table = 'article' # 經過db_table自定義數據表名

  經過db_table指定數據表名,還能夠經過db_column指定但願訪問的字段名。參考:https://blog.csdn.net/weixin_42134789/article/details/84567297

 自定義模型管理器對象(替換object)

假如models裏面有這樣一個表數據:

class User(models.Model):
    name = models.CharField(max_length=32)
    pwd = models.CharField(max_length=32)
    roles = models.ManyToManyField(to="Role")

    def __str__(self): return self.name

  查詢的時候使用下面的語句查詢

models.User.objects.filter(name=username, pwd=password).first()

  寫過orm查詢的都知道這句話的用法,那麼User.objects到底是什麼呢?

objects是Django幫咱們自動生成的管理器對象,經過這個管理器能夠爲數據的查詢添加點共性的東西。好比添加額外的方法和修改查詢結果

objects是models.Manager類的一個對象。

class Manager(BaseManager.from_queryset(QuerySet)):
    pass

  可是若是在裏本身生成管理器對象,那麼原來的objects將再也不好使,改爲你定義的那種,好比:

class User(models.Model):
    name = models.CharField(max_length=32)
    pwd = models.CharField(max_length=32)
    roles = models.ManyToManyField(to="Role")
    
    user = models.Manager()  # 自定義了一個Manager類對象

    def __str__(self): return self.name

  這時,User.objects將很差使,而User.user將徹底代替User.objects,下面的圖說明這些關係

例以下面,這樣修改管理器類的all方法,object.all()方法的內容就會更着改變,這樣就能夠添加方法和修改原方法

相關文章
相關標籤/搜索