Django學習筆記之——Models

Django裏的模型是對數據庫對錶的一次封裝,是應用業務與數據之間的橋樑。
python


1. 模型的Fields

在上一節,咱們在mysite/blog/models.py中建立了BlogPost這個Model。sql

from django.db import models
class BlogPost(models.Model):
    title = models.CharField(max_length=150)
    body = models.TextField()
    timestamp = models.DateTimeField()

BlogPost裏用了CharField,TextField, TextField域。難道就只有這三種,不可能!shell

以下,我列出了其它的Field,並代表了它們的繼承關係:數據庫

Field
|--AutoField
|--BooleanField
|--CharField
|  |--EmailField
|  |--SlugField
|  `--URLField
|--DateField
|  `--DateTimeField
|--DecimalField
|--FilePathField
|--FloatField
|--IntegerField
|  |--BigIntegerField
|  |--PositiveIntegerField
|  `--PositiveSmallIntegerField
|--IPAddressField
|--GenericIPAddressField
|--NullBooleanField
|--TextField
|--TimeField
`--BinaryField

別問我是怎麼知道的。看源碼呀~在 django/db/models/fields/__init__.py 中定義。
django

若是你是去看了這個文件,那麼不難知道 Field類的__init__(self)函數帶了不少參數吧。json

Field類在構造的時候能夠指定如下參數:
verbose_name=None   #顯示名
name=None           #域名
primary_key=False   #是否爲主鍵
max_length=None     #在CharFiled中用到
unique=False        #是否惟一
blank=False
null=False          #是否容許爲空
db_index=False
rel=None
default=NOT_PROVIDED
editable=True       #是否可編輯
serialize=True
unique_for_date=None
unique_for_month=None
unique_for_year=None
choices=None
help_text=''
db_column=None
db_tablespace=None
auto_created=False
validators=[]
error_messages=None

models.ForeignKey
~~~~~~~~~~~~~~~~~
能夠用models.ForeignKey()指定外鍵,如在models.py中:
_______________________________________________
class Author(models.Model):
    name = models.CharField(max_length=100)

class Book(models.Model):
    title = models.CharField(max_length=100)
    author = models.ForeignKey(Author) #定義外鍵
-----------------------------------------------
注:Author必須在Book以前定義。若是不想有這樣的限制,那麼在ForeignKey()中以
"Author"字符串對象做爲參數傳入。
_______________________________________________
class Book(models.Model):
    title = models.CharField(max_length=100)
    author = models.ForeignKey('Author') # 注意,這裏用的是類名稱,而不是類
                                         # 自己
class Author(models.Model):
    name = models.CharField(max_length=100)
-----------------------------------------------

在外鍵的支持下,能夠實現數據庫中多表查詢的功能。好比查到與該書做者的全部書:
________________________________________________
book_title = "C++程序設計"
this_book = Book.objects.get(title=book_title)  # 找到title爲"C++程序設計"
                                                # 的book對象this_book
author = this_book.author   # 由this_book得到做者對象author
books = author.book_set.all()   # 根據author得到全部的書,獲得books數組
               ^^^^^^^^
for book in books: # 打印每一本書
    print(book.title)
------------------------------------------------
在Book中加入了ForeignKey('Author')以後,Django會在Author對象中添加一個屬性
叫:book_set。
可是,若是用的是ForeignKey('Author', related_name="books"),也就是告訴django
在Author端對應的屬性名叫"books",而再也不是django默認的"book_set"了。

models.ManyToManyField
~~~~~~~~~~~~~~~~~~~~~~
顧名思意,就是多對多域。當兩個表存在多對多的關係時,這就頗有用。
好比:一名做者可能寫了多本書,一本書也可能由多名做者共同編寫。
_______________________________________________
class Author(models.Model):
    name = models.CharField(max_length=100)

class Book(models.Model):
    title = models.CharField(max_length=100)
    author = models.ManyToManyField(Author)
-----------------------------------------------
其實,Django爲咱們建了另外一個book_book_author的表。

以下爲book_book_author的建立明細:
__________________________________________________________________________
sqlite> .schema book_book_author
CREATE TABLE "book_book_author" (
    "id" integer NOT NULL PRIMARY KEY,
    "book_id" varchar(50) NOT NULL,
    "author_id" integer NOT NULL REFERENCES "book_author" ("id"),
    UNIQUE ("book_id", "author_id")
    );
CREATE INDEX "book_book_author_36c249d7" ON "book_book_author" ("book_id");
CREATE INDEX "book_book_author_e969df21" ON "book_book_author" ("author_id");
--------------------------------------------------------------------------

那麼,這種多對多的關係在view中怎麼使用呢?

models.OneToOneField一對一關係
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


模型繼承關係
~~~~~~~~~~~~
在模型類中定義Meta內部類,並指定Meta.abstract = True時,表示該模型爲抽象模型
,即只用來被子模型類派生而不生成實際的模型。
這時,Django在./manage.py syncdb時就不會爲該模型建立表。好比:Person爲人的模
型,裏面定義了人的基本屬性。Student與Teacher繼承於它。在同步數據庫時,咱們不
能爲Person建立一張表吧。以下:
________________________________________________
class Person(models.Model):
    name = models.CharField(max_length=50)
    gender = models.PositiveSmallIntegerField()
    birthday = models.DateField()

    def __unicode__(self):
        return self.name

    class Meta:
        abstract = True

class Teacher(Person):
    pass

class Student(Person):
    pass
------------------------------------------------
對了,記得給模型定義__unicode__方法。這用利於讓admin知道模型對象該怎麼顯示。

Meta嵌套類
~~~~~~~~~~

在前面有兩處提到了Meta類,一處是在blog排序時,另外一處就是上面的虛繼承。
Meta的用法是嵌套在Model類裏面,用於說明附加的信息。

數據查詢
~~~~~~~~
每一個Model都有一個objects屬性,而這個objects屬性具備如下方法:
Model.objects.all()       # 獲取全部對象的QuerySet
Model.objects.filter()    # 獲取知足條件的對象的QuerySet
Model.objects.exclude()   # 獲取不知足條件的對象的QuerySet
Model.objects.get()       # 獲取單個符合條件的對象的QuerySet

QuerySet會將查詢條件轉換成SQL語句,並得到執行結果。
示例:
____________________________________________________________
# 找出John Doe
Person.objects.filter(last="Doe").filter(first="John")

# 找出逾期不還的書
today = datetime.now()
overdue_books = book_queryset.filter(due_date__lt = today)
                                             ^^^^
                                 意恩是:due_date < today
# 注:除了__lt,還有:__gt

# 查詢結果排序,並提取前5個
all_sorted_first = Person.objects.all().order_by('first')[:5]

# 使用select_related執行簡單的join操做
Person.objects.all().select_related('address', depth=1)
-------------------------------------------------------------

用Q()讓條件靈活組合
~~~~~~~~~~~~~~~~~~~
使用Q()來封裝查詢條件,與 & | ~ 配合,造成組合條件。
_______________________________________________________________________
Person.objects.filter(
    Q(last="Doe") |
    (Q(last="Smith") & Q(first="John") & ~Q(middle__startswith="W"))
)

first_names = ['John', 'Jane', 'Jeremy']
first_name_keywords = Q()
for name in first_names:
    first_name_keywords = first_name_keywords | Q(first=name)
specific_does = Person.objects.filter(last="Doe").filter(first_name_keywords)
----------------------------------------------------------------------

用extra()提供其它的功能
~~~~~~~~~~~~~~~~~~~~~~~

## select提供簡單數據
# SELECT age, (age > 18) as is_adult FROM myapp_person;
Person.objects.all().extra(select={'is_adult': "age > 18"})

## where提供查詢條件
# SELECT * FROM myapp_person WHERE first||last ILIKE 'jeffrey%';
Person.objects.all().extra(where=["first||last ILIKE 'jeffrey%'"])

## table鏈接其它表
# SELECT * FROM myapp_book, myapp_person WHERE last = author_last
Book.objects.all().extra(table=['myapp_person'], where=['last = author_last'])

## params添參數
# !! 錯誤的方式 !!
first_name = 'Joe'  # 若是first_name中有SQL特定字符就會出現漏洞
Person.objects.all().extra(where=["first = '%s'" % first_name])
# 正確方式
Person.objects.all().extra(where=["first = '%s'"], params=[first_name])
#                                                ^^^^^^^^^^^^^^^^^^^^^

數據庫導入導出
~~~~~~~~~~~~~~
# 將book應用的數據導出到book.json文件中去
./manage.py dumpdata --indent=4 book > book.json

自定義SQL查詢
~~~~~~~~~~~~~
若是前面的QuerySet沒法知足特殊的查詢要求,那就讓咱們本身來指定select語句吧。
以下:
_______________________________________________________________________
from django.db import connection
cursor = connection.cursor()
cursor.execute("SELECT first, last FROM myapp_person WHERE last='Doe'")
doe_rows = cursor.fetchall()
for row in doe_rows:
    print("%s %s" % (row[0], row[1]))
-----------------------------------------------------------------------

數組

相關文章
相關標籤/搜索