Django模型層
一 ORM簡介
查詢數據層次圖解:若是操做mysql,ORM是在pymysq之上又進行了一層封裝html
- MVC或者MTV框架中包括一個重要的部分,就是ORM,它實現了數據模型與數據庫的解耦,即數據模型的設計不須要依賴於特定的數據庫,經過簡單的配置就能夠輕鬆更換數據庫,這極大的減輕了開發人員的工做量,不須要面對因數據庫變動而致使的無效勞動
- ORM是「對象-關係-映射」的簡稱。
-
映射關係:python
表名 <-------> 類名 字段 <-------> 屬性 表記錄 <------->類實例對象

#sql中的表 #建立表: CREATE TABLE employee( id INT PRIMARY KEY auto_increment , name VARCHAR (20), gender BIT default 1, birthday DATA , department VARCHAR (20), salary DECIMAL (8,2) unsigned, ); #sql中的表紀錄 #添加一條表紀錄: INSERT employee (name,gender,birthday,salary,department) VALUES ("alex",1,"1985-12-12",8000,"保潔部"); #查詢一條表紀錄: SELECT * FROM employee WHERE age=24; #更新一條表紀錄: UPDATE employee SET birthday="1989-10-24" WHERE id=1; #刪除一條表紀錄: DELETE FROM employee WHERE name="alex" #python的類 class Employee(models.Model): id=models.AutoField(primary_key=True) name=models.CharField(max_length=32) gender=models.BooleanField() birthday=models.DateField() department=models.CharField(max_length=32) salary=models.DecimalField(max_digits=8,decimal_places=2) #python的類對象 #添加一條表紀錄: emp=Employee(name="alex",gender=True,birthday="1985-12-12",epartment="保潔部") emp.save() #查詢一條表紀錄: Employee.objects.filter(age=24) #更新一條表紀錄: Employee.objects.filter(id=1).update(birthday="1989-10-24") #刪除一條表紀錄: Employee.objects.filter(name="alex").delete()
二 單表操做
建立表
1 建立模型
建立名爲book的app,在book下的models.py中建立模型:mysql
from django.db import models # Create your models here. class Book(models.Model): id = models.AutoField(primary_key=True) name = models.CharField(max_length=64) pub_data = models.DateField() price = models.DecimalField(max_digits=5, decimal_places=2) publish = models.CharField(max_length=12) def __str__(self): return self.name
2 更多字段和參數
每一個字段有一些特有的參數,例如,CharField須要max_length參數來指定VARCHAR
數據庫字段的大小。還有一些適用於全部字段的通用參數。 這些參數在文檔中有詳細定義,這裏咱們只簡單介紹一些最經常使用的:git

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) - 二進制類型

(1)null 若是爲True,Django 將用NULL 來在數據庫中存儲空值。 默認值是 False. (1)blank 若是爲True,該字段容許不填。默認爲False。 要注意,這與 null 不一樣。null純粹是數據庫範疇的,而 blank 是數據驗證範疇的。 若是一個字段的blank=True,表單的驗證將容許該字段是空值。若是字段的blank=False,該字段就是必填的。 (2)default 字段的默認值。能夠是一個值或者可調用對象。若是可調用 ,每有新對象被建立它都會被調用。 (3)primary_key 若是爲True,那麼這個字段就是模型的主鍵。若是你沒有指定任何一個字段的primary_key=True, Django 就會自動添加一個IntegerField字段作爲主鍵,因此除非你想覆蓋默認的主鍵行爲, 不然不必設置任何一個字段的primary_key=True。 (4)unique 若是該值設置爲 True, 這個數據字段的值在整張表中必須是惟一的 (5)choices 由二元組組成的一個可迭代對象(例如,列表或元組),用來給字段提供選擇項。 若是設置了choices ,默認的表單將是一個選擇框而不是標準的文本框,<br>並且這個選擇框的選項就是choices 中的選項。 這是一個關於 choices 列表的例子: YEAR_IN_SCHOOL_CHOICES = ( ('FR', 'Freshman'), ('SO', 'Sophomore'), ('JR', 'Junior'), ('SR', 'Senior'), ('GR', 'Graduate'), ) 每一個元組中的第一個元素,是存儲在數據庫中的值;第二個元素是在管理界面或 ModelChoiceField 中用做顯示的內容。 在一個給定的 model 類的實例中,想獲得某個 choices 字段的顯示值,就調用 get_FOO_display 方法(這裏的 FOO 就是 choices 字段的名稱 )。例如: from django.db import models class Person(models.Model): SHIRT_SIZES = ( ('S', 'Small'), ('M', 'Medium'), ('L', 'Large'), ) name = models.CharField(max_length=60) shirt_size = models.CharField(max_length=1, choices=SHIRT_SIZES) >>> p = Person(name="Fred Flintstone", shirt_size="L") >>> p.save() >>> p.shirt_size 'L' >>> p.get_shirt_size_display() 'Large'

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
3 settings配置sql
若想將模型轉爲mysql數據庫中的表,須要在settings中配置:數據庫
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'lqz',
'USER': 'root',
'PASSWORD': '123456',
'HOST': '127.0.0.1',
'PORT': 3306,
'ATOMIC_REQUEST': True,
'OPTIONS': {
"init_command": "SET storage_engine=MyISAM",
}
}
}
'''
'NAME':要鏈接的數據庫,鏈接前須要建立好
'USER':鏈接數據庫的用戶名
'PASSWORD':鏈接數據庫的密碼
'HOST':鏈接主機,默認本機
'PORT':端口 默認3306
'ATOMIC_REQUEST': True,
設置爲True統一個http請求對應的全部sql都放在一個事務中執行(要麼全部都成功,要麼全部都失敗)。
是全局性的配置, 若是要對某個http請求放水(而後自定義事務),能夠用non_atomic_requests修飾器
'OPTIONS': {
"init_command": "SET storage_engine=MyISAM",
}
設置建立表的存儲引擎爲MyISAM,INNODB
'''
注意1:NAME即數據庫的名字,在mysql鏈接前該數據庫必須已經建立,而上面的sqlite數據庫下的db.sqlite3則是項目自動建立 USER和PASSWORD分別是數據庫的用戶名和密碼。設置完後,再啓動咱們的Django項目前,咱們須要激活咱們的mysql。而後,啓動項目,會報錯:no module named MySQLdb 。這是由於django默認你導入的驅動是MySQLdb,但是MySQLdb 對於py3有很大問題,因此咱們須要的驅動是PyMySQL 因此,咱們只須要找到項目名文件下的__init__,在裏面寫入:django
import pymysql pymysql.install_as_MySQLdb()
最後經過兩條數據庫遷移命令便可在指定的數據庫中建立表 :session
python manage.py makemigrations
python manage.py migrate
注意2:確保配置文件中的INSTALLED_APPS中寫入咱們建立的app名稱app
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', "book" ]
注意3:若是報錯以下:框架
django.core.exceptions.ImproperlyConfigured: mysqlclient 1.3.3 or newer is required; you have 0.7.11.None
MySQLclient目前只支持到python3.4,所以若是使用的更高版本的python,須要修改以下:
經過查找路徑C:\Programs\Python\Python36-32\Lib\site-packages\Django-2.0-py3.6.egg\django\db\backends\mysql
這個路徑裏的文件把
if version < (1, 3, 3): raise ImproperlyConfigured("mysqlclient 1.3.3 or newer is required; you have %s" % Database.__version__)
註釋掉就能夠了
注意4: 若是想打印orm轉換過程當中的sql,須要在settings中進行以下配置:
LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'handlers': { 'console':{ 'level':'DEBUG', 'class':'logging.StreamHandler', }, }, 'loggers': { 'django.db.backends': { 'handlers': ['console'], 'propagate': True, 'level':'DEBUG', }, } }
4 增長,刪除字段
刪除,直接註釋掉字段,執行數據庫遷移命令便可
新增字段,在類裏直接新增字段,直接執行數據庫遷移命令會提示輸入默認值,此時須要設置
publish = models.CharField(max_length=12,default='人民出版社',null=True)
注意:
1 數據庫遷移記錄都在 app01下的migrations裏
2 使用showmigrations命令能夠查看沒有執行migrate的文件
3 makemigrations是生成一個文件,migrate是將更改提交到數據量
添加表紀錄
方式1
# create方法的返回值book_obj就是插入book表中的python葵花寶典這本書籍紀錄對象
book_obj
=
Book.objects.create(title
=
"python葵花寶典"
,state
=
True
,price
=
100
,publish
=
"蘋果出版社"
,pub_date
=
"2012-12-12"
)
方式2
book_obj
=
Book(title
=
"python葵花寶典"
,state
=
True
,price
=
100
,publish
=
"蘋果出版社"
,pub_date
=
"2012-12-12"
)
book_obj.save()
補充 ******************
#新增 返回的對象 就是新增的數據 # obj = models.UserType.objects.create(title='xxx') # obj = models.UserType.objects.create(**{'title': 'xxx'}) # print(obj.id) save保存後纔會數據庫建立 # obj = models.UserType(title='xxx') # obj.save() 批量增長 def bulk_create(self, objs, batch_size=None): # 批量插入 # batch_size表示一次插入的個數 objs = [ models.DDD(name='r11'), models.DDD(name='r22') ] models.DDD.objects.bulk_create(objs, 10) def get_or_create(self, defaults=None, **kwargs): # 若是存在,則獲取,不然,建立 # defaults 指定建立時,其餘字段的值 obj, created = models.UserInfo.objects.get_or_create(username='root1', defaults={'email': '1111111','u_id': 2, 't_id': 2}) created 返回的爲 True或者是false def update_or_create(self, defaults=None, **kwargs): # 若是存在,則更新,不然,建立 # defaults 指定建立時或更新時的其餘字段 obj, created = models.UserInfo.objects.update_or_create(username='root1', defaults={'email': '1111111','u_id': 2, 't_id': 1})
查詢表紀錄
查詢API
<
1
>
all
(): 查詢全部結果
<
2
>
filter
(
*
*
kwargs): 它包含了與所給篩選條件相匹配的對象
<
3
> get(
*
*
kwargs): 返回與所給篩選條件相匹配的對象,返回結果有且只有一個,
若是符合篩選條件的對象超過一個或者沒有都會拋出錯誤。
<
4
> exclude(
*
*
kwargs): 它包含了與所給篩選條件不匹配的對象
<
5
> order_by(
*
field): 對查詢結果排序
<
6
> reverse(): 對查詢結果反向排序
<
8
> count(): 返回數據庫中匹配查詢(QuerySet)的對象數量。
<
9
> first(): 返回第一條記錄
<
10
> last(): 返回最後一條記錄
<
11
> exists(): 若是QuerySet包含數據,就返回
True
,不然返回
False
<
12
> values(
*
field): 返回一個ValueQuerySet——一個特殊的QuerySet,運行後獲得的並非一系列
model的實例化對象,而是一個可迭代的字典序列
<
13
> values_list(
*
field): 它與values()很是類似,它返回的是一個元組序列,values返回的是一個字典序列
<
14
> distinct(): 從返回結果中剔除重複紀錄

def index(request): # 添加表記錄++++++++++++++++++++++++++++++++++ # 方式一 # book=Book(name='紅樓夢',pub_data='2015-10-12',price=88,publish='老男孩出版社') # book.save() # 方式二 # Book.objects.create(name='Python紅寶書',pub_data='2010-10-12',price=100,publish='人民出版社') # 查詢表記錄++++++++++++++++++++++++++++++++++ # QUerySet數據類型(相似於一個列表,裏面放着一些對象) # 1 方法的返回值是什麼 # 2 方法的調用者 # (1) all方法 返回一個QuerySet對象 # book_list=Book.objects.all() # print(book_list[1].name) # print(book_list) # for obj in book_list: # print(obj.name) # (2)first last:調用者是queryset對象,返回值是對象 # book=Book.objects.all().first() # book2=Book.objects.all().last() # print(book) # print(book2) # (3) filter 返回值是queryset對象(至關於where語句) # 能夠加多個過濾條件 # book=Book.objects.filter(name='紅樓夢').first() # print(book) # (4)get方法 有且只有一個查詢結果纔有意義 返回值是一個對象 # book=Book.objects.get(name='紅樓夢') # print(book) # 直接報錯 # book = Book.objects.get(name='紅樓夢eee') # --------------最經常使用----------------- # (5)exclude 除了查詢以外的 返回值也是queryset # ret=Book.objects.exclude(name='紅樓夢') # print(ret) # (6)order_by(默認升序,加個- 就是降序),能夠多個過濾條件調用者是queryset返回值也是queryset # book_list=Book.objects.all().order_by('id') # book_list=Book.objects.all().order_by('-id','price') # print(book_list) # (7)count() 調用者是queryset,返回值是int # ret=Book.objects.all().count() # print(ret) # (8)exist()判斷是是否有值,不能傳參數, # ret=Book.objects.all().exists() # print(ret) # (9)values方法 # 查詢全部書籍的名稱(裏面傳的值,前提是表有這個字段)也是queryset可是裏面放的是字典 ''' values原理 temp=[] for obj in Book.objects.all(): temp.append({'name':obj.name}) ''' # ret=Book.objects.all().values('name') # print(ret) # 不加.all()也能夠,調用是queryset返回值也是queryset # ret=Book.objects.values('price') # print(ret) # (10)value_list # ret=Book.objects.all().values_list('price','name') # print(ret) # (11) distinct seletc * 的時候沒有意義 # SELECT DISTINCT name from app01_book; # 沒有任何意義,不要這樣麼用 # Book.objects.all().distinct() # ret=Book.objects.all().values('name').distinct() # print(ret) # 雙下劃線模糊查詢----------------------- # 查詢價格大於100的書 # ret=Book.objects.filter(price__gt=100) # print(ret) # 查詢大於50小於100的書 # ret=Book.objects.filter(price__gt=50,price__lt=100) # print(ret) # 查詢已紅樓開頭的書 # ret=Book.objects.filter(name__startswith='紅樓') # print(ret) # 查詢包含‘紅’的書 # ret= Book.objects.filter(name__contains='紅') # print(ret) # icontains 不區分大小寫 # 價格在50,88,100 中的 # ret=Book.objects.filter(price__in=[50,88,100]) # print(ret) # 出版日期在2018年的 # ret=Book.objects.filter(pub_data__year=2015,pub_data__month=2) # print(ret) # 刪除,修改------------------------ # delete:調用者能夠是queryset也能夠是model對象 # 刪除價格爲188的書有返回值 (1, {'app01.Book': 1}) 刪除的個數,那張表,記錄數 # ret=Book.objects.filter(price=188).delete() # print(ret) # ret=Book.objects.filter(price=100).first().delete() # print(ret) # 修改 update只能queryset來調用 返回值爲int # ret=Book.objects.filter(name='紅樓夢1').update(name='紅樓夢') # print(ret) # 報錯 # Book.objects.filter(name='紅樓夢').first().update(name='紅樓夢1') # ret=Book.objects.filter(name='紅樓夢1').first() # print(ret.delete()) # aa=Publish.objects.filter(name='人民出版社') # print(type(aa)) # aa.delete() return HttpResponse('ok')
基於雙下劃線的模糊查詢
__exact 精確等於 like 'aaa'
__iexact 精確等於 忽略大小寫 ilike 'aaa'
__contains 包含 like '%aaa%'
__icontains 包含 忽略大小寫 ilike '%aaa%',可是對於sqlite來講,contains的做用效果等同於icontains。
__gt 大於
__gte 大於等於
__lt 小於
__lte 小於等於
__ne 不等於
__in 存在於一個list範圍內
__startswith 以...開頭
__istartswith 以...開頭 忽略大小寫
__endswith 以...結尾
__iendswith 以...結尾,忽略大小寫
__range 在...範圍內
__year 日期字段的年份
__month 日期字段的月份
__day 日期字段的日
__isnull=True/False
__isnull=True 與 __exact=None的區別
Book.objects.
filter
(price__in
=
[
100
,
200
,
300
])
Book.objects.
filter
(price__gt
=
100
)
Book.objects.
filter
(price__lt
=
100
)
Book.objects.
filter
(price__range
=
[
100
,
200
])
Book.objects.
filter
(title__contains
=
"python"
)
Book.objects.
filter
(title__icontains
=
"python"
)
Book.objects.
filter
(title__startswith
=
"py"
)
Book.objects.
filter
(pub_date__year
=
2012
)
刪除表紀錄
刪除方法就是 delete()。它運行時當即刪除對象而不返回任何值。例如:
你也能夠一次性刪除多個對象。每一個 QuerySet 都有一個 delete() 方法,它一次性刪除 QuerySet 中全部的對象。
例如,下面的代碼將刪除 pub_date 是2005年的 Entry 對象:
Entry.objects.
filter
(pub_date__year
=
2005
).delete()
在 Django 刪除對象時,會模仿 SQL 約束 ON DELETE CASCADE 的行爲,換句話說,刪除一個對象時也會刪除與它相關聯的外鍵對象。例如:
b
=
Blog.objects.get(pk
=
1
)
# This will delete the Blog and all of its Entry objects.
b.delete()
要注意的是: delete() 方法是 QuerySet 上的方法,但並不適用於 Manager 自己。這是一種保護機制,是爲了不意外地調用 Entry.objects.delete() 方法致使 全部的 記錄被誤刪除。若是你確認要刪除全部的對象,那麼你必須顯式地調用:
Entry.objects.
all
().delete()
若是不想級聯刪除,能夠設置爲:
pubHouse
=
models.ForeignKey(to
=
'Publisher'
, on_delete
=
models.SET_NULL, blank
=
True
, null
=
True
)
修改表紀錄
Book.objects.
filter
(title__startswith
=
"py"
).update(price
=
120
)
此外,update()方法對於任何結果集(QuerySet)均有效,這意味着你能夠同時更新多條記錄update()方法會返回一個整型數值,表示受影響的記錄條數。
三 章節做業
1 圖書管理系統
實現功能:book單表的增刪改查
2 查詢操做練習
1 查詢老男孩出版社出版過的價格大於200的書籍 2 查詢2017年8月出版的全部以py開頭的書籍名稱 3 查詢價格爲50,100或者150的全部書籍名稱及其出版社名稱 4 查詢價格在100到200之間的全部書籍名稱及其價格 5 查詢全部人民出版社出版的書籍的價格(從高到低排序,去重)