django模型


用django時,只要用到數據庫就得用到模型。

一、數據庫的MTV開發模式

從MVC到MTV

所謂軟件架構的MVC模式將數據的存取邏輯(Module),表現邏輯(View)和業務邏輯(Controller)分開,降低耦合。

Module代表數據庫的存取,View代表系統中選擇顯示什么和怎樣顯示,Controller指系統根據用戶輸入訪問模型以決定使用哪個視圖。

django設計同樣鼓勵松耦合。

django中的MTV模式也是一種MVC框架。

M:django中模型,負責數據存取。

V:由django視圖模板控制那些數據要顯示已經怎樣顯示。

C:由django框架根據URLconf控制URL調用python函數,由框架自行處理

所以對開發人員來說更關注模型,模板和視圖,就演變成了M(Model)T(Template) V(Views)。

二、數據庫連接

首先在settings.py文件進行數據庫的配置。

DATABASES = {
    'default': {
        'ENGINE': 'mysql', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.                                                     
        'NAME': 'dbname',                      # Or path to database file if using sqlite3.
        'USER': 'stack',                      # Not used with sqlite3.
        'PASSWORD': 'password',                  # Not used with sqlite3.
        'HOST': 'x.x.x.x',                      # Set to empty string for localhost. Not used with sqlite3.
        'PORT': '3306',                      # Set to empty string for default. Not used with sqlite3.
        'OPTIONS': {
                    'charset': 'utf8',
                    'use_unicode': True, },
    }
}

 配置好數據庫,可以使用python manage.py shell進行測試,不報錯說明配置可用。

>>> from django.db import connection
>>> cursor=connection.cursor()
>>> 

三、創建數據庫模型APP

django中一個項目可以包含多個app,項目中對這些app進行配置,配置數據庫連接,app列表,模板路徑等。

一個app包括獨立的功能,可復用,它包括獨立的模型,視圖。

現在在mysite這個項目里創建一個books模型。

liuxiaoyan@development:~/mysite$ python manage.py startapp books
liuxiaoyan@development:~/mysite$ ls
books  __init__.py  __init__.pyc  manage.py  settings.py  settings.pyc  urls.py  urls.pyc  views.py  views.pyc

Django有專用的字段類型來描述Email地址、URL。好處就是高級的數據類型帶來更高的效率和更好的代碼復用。

Django有工具從現有數據庫表自動生成模型。

先提醒一點,要非常注意模型和數據庫的同步問題。修改了一個Django模型,要手動修改數據庫來保證和模型同步。

四、從模型生成數據庫

接下來使用django的模型。從一個例子開始,例子如下:

  • 一個作者有姓、名和Email地址。
  • 出版商有名稱、地址,所在城市、省,國家,網站
  • 書籍有書名和出版日期。書和作者是多對多的關聯關系[many-to-many],出版商和書是一對多的關聯關系[one-to-many],也被稱作外鍵[foreign key]

1、建好模型

liuxiaoyan@development:~/mysite/books$ cat models.py   
from django.db import models

# Create your models here.
class Publisher(models.Model):
    name = models.CharField(max_length=30)
    address = models.CharField(max_length=50)
    city = models.CharField(max_length=60)
    state_province = models.CharField(max_length=30)
    country = models.CharField(max_length=50)
    website = models.URLField()

class Author(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=40)
    email = models.EmailField()

class Book(models.Model):
    title = models.CharField(max_length=100)
    authors = models.ManyToManyField(Author)
    publisher = models.ForeignKey(Publisher)
    publication_date = models.DateField()
View Code

解釋:每個數據模型都是django.db.models.Model的子類。它的父類Model包含了所有必要的和數據庫交互的方法,並提供了一個簡潔的定義數據庫字段的語法。

*python在類名后用一對圓括號表示繼承關系, 括號中的類表示父類 

模型和表一一對應,屬性和表的字段一一對應。屬性名就是字段名,類型是數據庫的字段類型。

2、模型安裝

第一步,在settings.py文件的INSTALLED_APPS加入該APP。

MIDDLEWARE_CLASSES中的中間件依賴於INSTALLED_APPS的條目。

在INSTALLED_APPS中增加'mysite.books'元組。

INSTALLED_APPS = (
    # 'django.contrib.auth',
    # 'django.contrib.contenttypes',
    # 'django.contrib.sessions',
    # 'django.contrib.sites',
    'books', #注意加上引號和這個逗號
)
View Code

第二步,創建數據庫表

首先檢測模型有效性

liuxiaoyan@development:~/mysite$ python manage.py validate
0 errors found

打印創建數據庫表的語句

liuxiaoyan@development:~/mysite$ python manage.py sqlall books
BEGIN;
CREATE TABLE `books_publisher` (
    `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,
    `name` varchar(30) NOT NULL,
    `address` varchar(50) NOT NULL,
    `city` varchar(60) NOT NULL,
    `state_province` varchar(30) NOT NULL,
    `country` varchar(50) NOT NULL,
    `website` varchar(200) NOT NULL
)
;
CREATE TABLE `books_author` (
    `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,
    `first_name` varchar(30) NOT NULL,
    `last_name` varchar(40) NOT NULL,
    `email` varchar(75) NOT NULL
)
;
CREATE TABLE `books_book_authors` (
    `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,
    `book_id` integer NOT NULL,
    `author_id` integer NOT NULL,
    UNIQUE (`book_id`, `author_id`)
)
;
ALTER TABLE `books_book_authors` ADD CONSTRAINT `author_id_refs_id_9e7e386` FOREIGN KEY (`author_id`) REFERENCES `books_author` (`id`);
CREATE TABLE `books_book` (
    `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,
    `title` varchar(100) NOT NULL,
    `publisher_id` integer NOT NULL,
    `publication_date` date NOT NULL
)
;
ALTER TABLE `books_book` ADD CONSTRAINT `publisher_id_refs_id_c5b274bb` FOREIGN KEY (`publisher_id`) REFERENCES `books_publisher` (`id`);
ALTER TABLE `books_book_authors` ADD CONSTRAINT `book_id_refs_id_cfbcf262` FOREIGN KEY (`book_id`) REFERENCES `books_book` (`id`);
CREATE INDEX `books_book_22dd9c39` ON `books_book` (`publisher_id`);
COMMIT;
View Code

sqlall只是打印出SQL語句,沒有在數據庫創建表。

創建表

liuxiaoyan@development:~/mysite$ python manage.py syncdb
Creating tables ...
Creating table books_publisher
Creating table books_author
Creating table books_book_authors
Creating table books_book
Installing custom SQL ...
Installing indexes ...
No fixtures found.
View Code

syncdb同步INSTALLED_APPS的模型到數據庫,這個同步是指檢查表是否存在,不存在就創建,但是不能將模型的修改或刪除同步到數據庫。

所以再次提醒修改了一個Django模型,要手動修改數據庫來保證和模型同步。

五、基本數據訪問

1、增

liuxiaoyan@development:~/mysite$ python manage.py shell
Python 2.7.3 (default, Feb 27 2014, 19:58:35) 
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from books.models import Publisher
>>> p1 = Publisher(name='Apress', address='2855 Telegraph Avenue',city='Berkeley', state_province='CA', country='U.S.A.',website='http://www.apress.com/')
>>> p1.save() >>> 

調用django model API創建的對象必須通過save()插入數據庫。

如果要一步完成對象的創建和存儲到數據庫,就使用管理器的creae方法,即“object.creae()”。

>>> from books.models import Publisher
>>> p1 = Publisher.objects.create(name='Apress',address='2855 Telegraph Avenue',city='Berkeley', state_province='CA', country='U.S.A.',website='http://www.apress.com/')
>>> p2 = Publisher.objects.create(name="O'Reilly",address='10 Fawcett St.', city='Cambridge',state_province='MA', country='U.S.A.',website='http://www.oreilly.com/')
>>> publisher_list = Publisher.objects.all()
>>> publisher_list
[<Publisher: Publisher object>, <Publisher: Publisher object>]
>>> 

2、刪

在對象上調用delete()方法

刪除一條數據

>>> p = Publisher.objects.get(name="O'Reilly")
>>> p.delete()

刪除一部分數據

找到某幾個要刪除的結果集,然后delete

>>> Publisher.objects.filter(country='USA').delete()

全部刪除

為預防錯誤,全部刪除需要顯示調用all()然后調用delete()

>>> Publisher.objects.all().delete()

3、改

賦新值然后調用save()就是更新了,而且是全部字段都更新。

liuxiaoyan@development:~/mysite$ python manage.py shell
Python 2.7.3 (default, Feb 27 2014, 19:58:35) 
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from books.models import Publisher
>>> p = Publisher(name='Apress',address='2855 Telegraph Ave.', city='Berkeley',state_province='CA',country='U.S.A.',website='http://www.starof.com/')
>>> p.save()
>>> p.id
5L
>>> p.name = 'lxy'
>>> p.save()
>>> p.id
5L

過程如下:

第一次調用save()方法插入一條記錄對應一個主鍵,把該主鍵值賦給對象實例p,再次調用save()方法不會創建新記錄,而是去更新全部列。這會導致一個問題,比如我要修改name列, 其他進程同時要修改name之外的列,可能會有沖突。所以局部更新比較明智。

局部更新

調用管理器的update方法。相當於updte SQL,即update table set propertie='xxx' where name='xxx'。

>>> Publisher.objects.filter(name='lxy').update(city='wuxi')
1L
>>> 

update()可以同時更新多條記錄

比如把所有的城市都換成shanghai

>>> Publisher.objects.all().update(city='shanghai')         
3L
>>> 

4、查

數據庫的查詢操作都是通過綁定在該模型上的管理器(objects)的相應方法(如all)。

全部查詢,返回結果集

用Publisher.objects.all()來取出所有記錄,但是並不是select * from table,而是顯示列出所有字段。

liuxiaoyan@development:~/mysite$ python manage.py shell
Python 2.7.3 (default, Feb 27 2014, 19:58:35) 
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from books.models import Publisher
>>> p1 = Publisher(name='Apress', address='2855 Telegraph Avenue',city='Berkeley', state_province='CA', country='U.S.A.',website='http://www.apress.com/')
>>> p1.save()
>>> p2 = Publisher(name="O'Reilly", address='10 Fawcett St.',city='Cambridge', state_province='MA', country='U.S.A.',website='http://www.oreilly.com/')
>>> p2.save()
>>> publisher_list = Publisher.objects.all() >>> publisher_list
[<Publisher: Publisher object>, <Publisher: Publisher object>]
>>> 

Note:

模型,這里就是Publisher,通過模型來獲得數據。

objects:屬性,被稱為管理器,所有模型自動擁有管理器屬性,管理數據。

部分查詢,返回結果集

使用管理器的filter()方法。

>>> Publisher.objects.filter(name="Apress")
[<Publisher: Apress>]

相當where SQL ,即於select * from table where propertie=“xxx”。

給定多個參數相當於and SQL,即select * from table where propertie1="xxx" and propertie2="xxx"

>>> Publisher.objects.filter(country="U.S.A.", state_province="CA")
[<Publisher: Apress>, <Publisher: lxy>]

filter方法還可以使用其他類型查詢,用__contains相當於like SQL,即select * from table where name like '%xxx%'

>>> Publisher.objects.filter(name__contains='lx')
[<Publisher: lxy>]

返回單個對象,而非結果集

使用管理器的get()方法。

>>> Publisher.objects.get(name='lxy')
<Publisher: lxy>

要注意的是返回結果集和和沒有查詢結果都會拋異常。

返回結果集

>>> Publisher.objects.get(city="Berkeley")
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/usr/lib/python2.7/dist-packages/django/db/models/manager.py", line 132, in get
    return self.get_query_set().get(*args, **kwargs)
  File "/usr/lib/python2.7/dist-packages/django/db/models/query.py", line 367, in get
    % (self.model._meta.object_name, num, kwargs))
MultipleObjectsReturned: get() returned more than one Publisher -- it returned 2! Lookup parameters were {'city': 'Berkeley'}

查詢沒有結果

>>> Publisher.objects.get(name='lxx')
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/usr/lib/python2.7/dist-packages/django/db/models/manager.py", line 132, in get
    return self.get_query_set().get(*args, **kwargs)
  File "/usr/lib/python2.7/dist-packages/django/db/models/query.py", line 365, in get
    % self.model._meta.object_name)
DoesNotExist: Publisher matching query does not exist.

查詢結果排序

使用管理器的order_by()方法。相當於order by SQL,即selsect * from table order by properties。

>>> Publisher.objects.all()               
[<Publisher: Apress>, <Publisher: O'Reilly>, <Publisher: lxy>]
>>> Publisher.objects.all().order_by("name")
[<Publisher: Apress>, <Publisher: lxy>, <Publisher: O'Reilly>]
>>> Publisher.objects.order_by("name") 

如果是根據名字逆向排序就加個減號前綴。

>>> Publisher.objects.order_by("-name")
[<Publisher: O'Reilly>, <Publisher: lxy>, <Publisher: Apress>]

如果不想每次都寫order_by,可以在模型里添加Meta類的ordering選項。

    class Meta:
        ordering=['name']

連接查詢

 過濾和排序查詢,用“鏈式”操作。類似where和order by的組合,即select * from table where properite='xxx' order by xxx。

>>> Publisher.objects.filter(country="U.S.A.").order_by("-name")
[<Publisher: O'Reilly>, <Publisher: lxy>, <Publisher: Apress>]
>>> 

限制查詢結果數量

以下[0]取得第一個結果,相當於limit 1,即selsect * from table order by xxx limit 1。

>>> Publisher.objects.filter(country="U.S.A.").order_by("-name")[0]
<Publisher: O'Reilly>

以下返回兩個對象,相當於offset 0 limit 2,即沒隔0個的取,總共取2個。

>>> Publisher.objects.filter(country="U.S.A.").order_by("-name")[0:2]
[<Publisher: O'Reilly>, <Publisher: lxy>]

不管是使用get(),filter(),還是all(),不管得到的是單個記錄,還是記錄集,得到后,就是類似在之前的模型中定義的類的實例對象,此時,就可以進行取出實例的其他字段的數據,或者進行在模型類中定義的其他邏輯函數的操作了。

5、按我們的需要顯示查詢信息

普通情況下list結果都是類似:

>>> publisher_list
[<Publisher: Publisher object>, <Publisher: Publisher object>]
>>> 

我們想看點詳細的信息,或者特定的信息,就給模型對象添加一個方法__unicode__(),類似java中的toString()方法。

liuxiaoyan@development:~/mysite/books$ cat models.py
from django.db import models

class Publisher(models.Model):
    name = models.CharField(max_length=30)
    address = models.CharField(max_length=50)
    city = models.CharField(max_length=60)
    state_province = models.CharField(max_length=30)
    country = models.CharField(max_length=50)
    website = models.URLField()
    
    def __unicode__(self): return self.name class Author(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=40)
    email = models.EmailField()

    def __unicode__(self): return u'%s %s' % (self.first_name, self.last_name) class Book(models.Model):
    title = models.CharField(max_length=100)
    authors = models.ManyToManyField(Author)
    publisher = models.ForeignKey(Publisher)
    publication_date = models.DateField()

    def __unicode__(self): return self.title

要使__unicode__()方法生效,退出python shell,然后再次運行python manage.py shell進入即可,不需要同步數據庫,現在就可以看到想看的內容了。

liuxiaoyan@development:~/mysite$ python manage.py shell
Python 2.7.3 (default, Feb 27 2014, 19:58:35) 
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from books.models import Publisher
>>> publisher_list = Publisher.objects.all()
>>> publisher_list
[<Publisher: Apress>, <Publisher: O'Reilly>]
>>> 
View Code

6、添加行為到模型

和添加__unicode__()一樣。

Django模型不只為對象定義了數據庫表的結果,還定義了對象的行為。新添加的__unicode__()方法就是告訴模型怎樣顯示自己。

六、訪問外鍵值

前面提到出版商和書是一對多的關系,即一本書只有一個出版商。在Book模型定義中可以看出

publisher = models.ForeignKey(Publisher)

出版社是以書的外鍵存在的。

1、通過多端訪問一端

可以通過書來訪問出版社,間接訪問出版社的名字,地址,網站等各種屬性。

liuxiaoyan@development:~/mysite$ python manage.py shell
Python 2.7.3 (default, Feb 27 2014, 19:58:35) 
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from books.models import Book
>>> b=Book.objects.get(id=1)
>>> b.publisher
<Publisher: Apress>
>>> b.publisher.website
u'http://www.apress.com/'
>>> b.publisher.address
u'2855 Telegraph Avenue'
>>> 

2、通過一端訪問多端

通過一個出版社可以獲取該出版社出版的所有書,或者可以通過關鍵字查詢該出版社出版的符合某條件的書。

>>> from books.models import Publisher
>>> p=Publisher.objects.get(name="Apress")
>>> p.book_set.all()
[<Book: 《平凡的世界》>, <Book: 《說話之道》>]
>>> p.book_set.filter(title__icontains='平凡')
[<Book: 《平凡的世界》>]
>>> 

這里用到一個book_set,通過一個“publisher”對象,直接獲取books,用publisher.book_set.all()。這里的book_set是一個QuerySet,所以可以進行數據過濾。而book_set這個屬性則是由模型名稱的小寫加_set組成的。

七、訪問多對多值

多對多和外鍵的工作方式相同,但是處理的都是QuerySet而不是模型實例。

1、通過Book訪問作者

查看一本書的所有作者,

liuxiaoyan@development:~/mysite$ python manage.py shell
Python 2.7.3 (default, Feb 27 2014, 19:58:35) 
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from books.models import Book
>>> b=Book.objects.get(id='5')
>>> b.authors.all()
[<Author: xiaoyan liu>, <Author: yao lu>]
>>> b.authors.filter(first_name="yao")
[<Author: yao lu>]
>>> 

2、通過Author訪問Book

查看一個作者的所有書,使用author.book_set

>>> from books.models import Author
>>> a=Author.objects.get(first_name='yao',last_name='lu')
>>> a.book_set.all()
[<Book: 童年>, <Book: 《平凡的世界》>]
>>> 

和外鍵一樣,這里屬性名book_set,是在數據模型后面追加_set。

資源鏈接:

http://djangobook.py3k.cn/2.0/chapter05/ 

http://djangobook.py3k.cn/2.0/chapter10/

django的教程

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM