D jango 模型是與數據庫相關的,與數據庫相關的代碼一般寫在 models.py 中,Django 支持 sqlite3, MySQL, PostgreSQL等數據庫,只需要在settings.py中配置即可,不用更改models.py中的代碼,豐富的API極大的方便了使用。
1、數據庫的連接方式以及設置:
在Django中默認使用的數據庫類型是sqlite3,如果想要使用其他數據庫就需要在settings中設置數據庫的連接方式:
# Database
# https://docs.djangoproject.com/en/1.10/ref/settings/#databases
# sqlite3數據庫連接方式
# DATABASES = {
# ‘default‘: {
# ‘ENGINE‘: ‘django.db.backends.sqlite3‘,
# ‘NAME‘: os.path.join(BASE_DIR, ‘db.sqlite3‘),
# }
# }
# MySQL數據庫連接方式
DATABASES = {
‘default‘: {
‘ENGINE‘: ‘django.db.backends.mysql‘,
‘NAME‘:‘dbname‘,
‘USER‘: ‘root‘,
‘PASSWORD‘: ‘xxx‘,
‘HOST‘: ‘‘,
‘PORT‘: ‘‘,
}
}
2、開始創建表
數據需要在models.py文件中創建
class UserInfo(models.Model):
# CharField類型不能爲空,最少要指定一個長度
user = models.CharField(max_length=32)
email = models.EmailField(max_length=32)
pwd = models.CharField(max_length=32)
user_type = models.ForeignKey(‘UserType‘)
class UserType(models.Model):
nid = models.AutoField(primary_key=True)
caption = models.CharField(max_length=16)
注:在創建外鍵的時候直接寫上UserType和‘UserType‘的區別就是python程序從上到下解釋的順序問題,如果把UserType這個類寫到下面就會沒事了
運行Djando項目程序,執行命令創建數據:
python3 manage.py makemigrations
python3 manage.py migrate
創建表的的參數:
1、models.AutoField 自增列 = int(11) 如果沒有的話,默認會生成一個名稱爲 id 的列,如果要顯示的自定義一個自增列,必須將給列設置爲主鍵 primary_key=True。 2、models.CharField 字符串字段 必須 max_length 參數 3、models.BooleanField 布爾類型=tinyint(1) 不能爲空,Blank=True 4、models.ComaSeparatedIntegerField 用逗號分割的數字=varchar 繼承CharField,所以必須 max_lenght 參數 5、models.DateField 日期類型 date 對於參數,auto_now = True 則每次更新都會更新這個時間;auto_now_add 則只是第一次創建添加,之後的更新不再改變。 6、models.DateTimeField 日期類型 datetime 同DateField的參數 7、models.Decimal 十進制小數類型 = decimal 必須指定整數位max_digits和小數位decimal_places 8、models.EmailField 字符串類型(正則表達式郵箱) =varchar 對字符串進行正則表達式 9、models.FloatField 浮點類型 = double 10、models.IntegerField 整形 11、models.BigIntegerField 長整形 integer_field_ranges = { ‘SmallIntegerField‘: (-32768, 32767), ‘IntegerField‘: (-2147483648, 2147483647), ‘BigIntegerField‘: (-9223372036854775808, 9223372036854775807), ‘PositiveSmallIntegerField‘: (0, 32767), ‘PositiveIntegerField‘: (0, 2147483647), } 12、models.IPAddressField 字符串類型(ip4正則表達式) 13、models.GenericIPAddressField 字符串類型(ip4和ip6是可選的) 參數protocol可以是:both、ipv4、ipv6 驗證時,會根據設置報錯 14、models.NullBooleanField 允許爲空的布爾類型 15、models.PositiveIntegerFiel 正Integer 16、models.PositiveSmallIntegerField 正smallInteger 17、models.SlugField 減號、下劃線、字母、數字 18、models.SmallIntegerField 數字 數據庫中的字段有:tinyint、smallint、int、bigint 19、models.TextField 字符串=longtext 20、models.TimeField 時間 HH:MM[:ss[.uuuuuu]] 21、models.URLField 字符串,地址正則表達式 22、models.BinaryField 二進制 23、models.ImageField 圖片 24、models.FilePathField 文件
1、null=True 數據庫中字段是否可以爲空 2、blank=True django的 Admin 中添加數據時是否可允許空值 3、primary_key = False 主鍵,對AutoField設置主鍵後,就會代替原來的自增 id 列 4、auto_now 和 auto_now_add auto_now 自動創建---無論添加或修改,都是當前操作的時間 auto_now_add 自動創建---永遠是創建時的時間 5、choices GENDER_CHOICE = ( (u‘M‘, u‘Male‘), (u‘F‘, u‘Female‘), ) gender = models.CharField(max_length=2,choices = GENDER_CHOICE) 6、max_length 7、default 默認值 8、verbose_name Admin中字段的顯示名稱 9、name|db_column 數據庫中的字段名稱 10、unique=True 不允許重複 11、db_index = True 數據庫索引 12、editable=True 在Admin裏是否可編輯 13、error_messages=None 錯誤提示 14、auto_created=False 自動創建 15、help_text 在Admin中提示幫助信息 16、validators=[] 17、upload-to
執行成功狀態:
1 bogon:django_modes01 zk$ python3 manage.py makemigrations 2 Migrations for ‘app01‘: 3 app01/migrations/0001_initial.py: 4 - Create model UserInfo 5 - Create model UserType 6 - Add field user_type to userinfo 7 bogon:django_modes01 zk$ python3 manage.py migrate 8 Operations to perform: 9 Apply all migrations: admin, app01, auth, contenttypes, sessions 10 Running migrations: 11 Rendering model states... DONE 12 Applying contenttypes.0001_initial... OK 13 Applying auth.0001_initial... OK 14 Applying admin.0001_initial... OK 15 Applying admin.0002_logentry_remove_auto_add... OK 16 Applying app01.0001_initial... OK 17 Applying contenttypes.0002_remove_content_type_name... OK 18 Applying auth.0002_alter_permission_name_max_length... OK 19 Applying auth.0003_alter_user_email_max_length... OK 20 Applying auth.0004_alter_user_username_opts... OK 21 Applying auth.0005_alter_user_last_login_null... OK 22 Applying auth.0006_require_contenttypes_0002... OK 23 Applying auth.0007_alter_validators_add_error_messages... OK 24 Applying auth.0008_alter_user_username_max_length... OK 25 Applying sessions.0001_initial... OK
如果提示:No changes detected
需要在settings.py的配置文件檢測一下有沒有註冊app
在MySQL中就可以看到生成的表:
外鍵關係:
3.開始創建數據
創建數據的時候有兩種方式:
第一種方式:
obj = models.表名(字段名=‘***‘)
obj.save()
第二種方式:
models.表名.objects.create(字段名=‘***‘)
在views.py中寫入數據:
from django.shortcuts import render,HttpResponse
from app01 import models
# Create your views here.
def index(request):
# 創建用戶類型表
models.UserType.objects.create(caption=‘管路員‘)
models.UserType.objects.create(caption=‘普通用戶‘)
models.UserType.objects.create(caption=‘超級管理員‘)
# 創建用戶信息表
user_info_dict_1 = {‘user‘: ‘ales‘,
‘email‘: ‘[email protected]‘,
‘pwd‘: 123,
‘user_type‘: models.UserType.objects.get(nid=1),
}
user_info_dict_2 = {‘user‘: ‘eric‘,
‘email‘: ‘[email protected]‘,
‘pwd‘: 123,
‘user_type_id‘: 2,
}
models.UserInfo.objects.create(**user_info_dict_1)
models.UserInfo.objects.create(**user_info_dict_2)
print(‘yes‘)
return HttpResponse(‘ok‘)
運行Django 項目訪問指定文件創建數據:
4、了不起的雙下劃線之外鍵正向查找和基本操作
1 # 增 2 # 3 # models.Tb1.objects.create(c1=‘xx‘, c2=‘oo‘) 增加一條數據,可以接受字典類型數據 **kwargs 4 5 # obj = models.Tb1(c1=‘xx‘, c2=‘oo‘) 6 # obj.save() 7 8 # 查 9 # 10 # models.Tb1.objects.get(id=123) # 獲取單條數據,不存在則報錯(不建議) 11 # models.Tb1.objects.all() # 獲取全部 12 # models.Tb1.objects.filter(name=‘seven‘) # 獲取指定條件的數據 13 14 # 刪 15 # 16 # models.Tb1.objects.filter(name=‘seven‘).delete() # 刪除指定條件的數據 17 18 # 改 19 # models.Tb1.objects.filter(name=‘seven‘).update(gender=‘0‘) # 將指定條件的數據更新,均支持 **kwargs 20 # obj = models.Tb1.objects.get(id=1) 21 # obj.c1 = ‘111‘ 22 # obj.save() # 修改單條數據
1 # 獲取個數 2 # 3 # models.Tb1.objects.filter(name=‘seven‘).count() 4 5 # 大於,小於 6 # 7 # models.Tb1.objects.filter(id__gt=1) # 獲取id大於1的值 8 # models.Tb1.objects.filter(id__lt=10) # 獲取id小於10的值 9 # models.Tb1.objects.filter(id__lt=10, id__gt=1) # 獲取id大於1 且 小於10的值 10 11 # in 12 # 13 # models.Tb1.objects.filter(id__in=[11, 22, 33]) # 獲取id等於11、22、33的數據 14 # models.Tb1.objects.exclude(id__in=[11, 22, 33]) # not in 15 16 # contains 17 # 18 # models.Tb1.objects.filter(name__contains="ven") 19 # models.Tb1.objects.filter(name__icontains="ven") # icontains大小寫不敏感 20 # models.Tb1.objects.exclude(name__icontains="ven") 21 22 # range 23 # 24 # models.Tb1.objects.filter(id__range=[1, 2]) # 範圍bettwen and 25 26 # 其他類似 27 # 28 # startswith,istartswith, endswith, iendswith, 29 30 # order by 31 # 32 # models.Tb1.objects.filter(name=‘seven‘).order_by(‘id‘) # asc 33 # models.Tb1.objects.filter(name=‘seven‘).order_by(‘-id‘) # desc 34 35 # limit 、offset 36 # 37 # models.Tb1.objects.all()[10:20] 38 39 # group by 40 from django.db.models import Count, Min, Max, Sum 41 # models.Tb1.objects.filter(c1=1).values(‘id‘).annotate(c=Count(‘num‘)) 42 # SELECT "app01_tb1"."id", COUNT("app01_tb1"."num") AS "c" FROM "app01_tb1" WHERE "app01_tb1"."c1" = 1 GROUP BY "app01_tb1"."id"
- 查
單表查詢:
# ret = models.UserType.objects.all()
# print(ret.query)
# ret.query後臺返回的是查詢的sql語句
結果:
SELECT `app01_usertype`.`nid`, `app01_usertype`.`caption` FROM `app01_usertype`
獲取查詢結果的類型:
ret = models.UserType.objects.all()
print(type(ret), ret)
結果:
<class ‘django.db.models.query.QuerySet‘> <QuerySet [<UserType: UserType object>, <UserType: UserType object>, <UserType: UserType object>]>
可以看到類型是一個QuerySet類型,後面是所有的對象,每一個元素就是一個對象,可以循環拿出每一次的數據:
ret = models.UserType.objects.all()
print(type(ret), ret)
for item in ret:
print(item)
其結果就是每一次循環出來的結果的對象:
UserType object
UserType object
UserType object
每一個對象都代表一個數據,要出去這些數據如下:
ret = models.UserType.objects.all()
print(type(ret), ret)
for item in ret:
print(item, item.nid, item.caption)
取出的結果:
UserType object 1 管路員
UserType object 2 普通用戶
UserType object 3 超級管理員
從結果看出每次輸出item的時候都是一個對象(一行數據中所有的對象,對象中封裝了所有的數據),在modes中有__str__方法(返回什麼,就輸出什麼,就是查看方便), 在python2.7中叫__unicode__如果在UserType這個類裏面使用這個方法:
class UserType(models.Model):
nid = models.AutoField(primary_key=True)
caption = models.CharField(max_length=16)
def __str__(self):
return ‘%s-%s‘ % (self.nid, self.caption)
然後重新訪問下:
1-管路員 1 管路員
2-普通用戶 2 普通用戶
3-超級管理員 3 超級管理員
就可以看到每一個對象都看到了返回的相對應的參數了。
查詢單個字段:
ret = models.UserType.objects.all().values(‘nid‘)
print(type(ret), ret)
結果查詢出nid字段對應的所有的數據 :
<class ‘django.db.models.query.QuerySet‘> <QuerySet [{‘nid‘: 1}, {‘nid‘: 2}, {‘nid‘: 3}]>
可以看查詢的sql語句,用query方法:
ret = models.UserType.objects.all().values(‘nid‘)
print(type(ret), ret.query)
查詢的結果:
<class ‘django.db.models.query.QuerySet‘> SELECT `app01_usertype`.`nid` FROM `app01_usertype`
當通過values循環取值的時候,如下:
ret = models.UserType.objects.all().values(‘nid‘)
print(type(ret), ret.query)
for item in ret:
print(item, type(item))
結果:
<class ‘django.db.models.query.QuerySet‘> SELECT `app01_usertype`.`nid` FROM `app01_usertype`
{‘nid‘: 1} <class ‘dict‘>
{‘nid‘: 2} <class ‘dict‘>
{‘nid‘: 3} <class ‘dict‘>
通過結果可以看出,最外部是QuerySet,內部元素封裝了一個是封裝了這一行所有數據的對象,另外只拿到了某幾列的字典!
當通過values_list循環取值的時候,如下:
ret = models.UserType.objects.all().values_list(‘nid‘)
print(type(ret), ret)
查詢結果:
<class ‘django.db.models.query.QuerySet‘> <QuerySet [(1,), (2,), (3,)]>
依然是queryset,但是結果就是列表中包含的元組,values和values_list的區別就是:values取的是字典類型,values_list把內部元素變成元組了。通過for循環更直觀,如下:
ret = models.UserType.objects.all().values_list(‘nid‘)
print(type(ret), ret)
for item in ret:
print(type(item), item)
結果:
<class ‘django.db.models.query.QuerySet‘> <QuerySet [(1,), (2,), (3,)]>
<class ‘tuple‘> (1,)
<class ‘tuple‘> (2,)
<class ‘tuple‘> (3,)
連表查詢:
連表查詢的時候和sqlachemy有多不同,django沒有join這個方法:
通過UserInfo做連表查詢
ret = models.UserInfo.objects.all()
print(type(ret), ret)
for item in ret:
print(item, item.user_type, item.id, item.email, item.user, item.pwd)
查詢結果:
<class ‘django.db.models.query.QuerySet‘> <QuerySet [<UserInfo: UserInfo object>, <UserInfo: UserInfo object>]>
UserInfo object UserType object 1 [email protected] ales 123
UserInfo object UserType object 2 [email protected] eric 123
首先輸出的是查找出來的UserInfo用戶信息表,封裝了用戶所有的信息,而UserType就是一個對象,這個對象裏封裝的就是一行信息對應的字段(nid和caption),取出UserType對應的信息,例如:
ret = models.UserInfo.objects.all()
print(type(ret), ret)
for item in ret:
print(item, item.user_type, item.id, item.email, item.user, item.pwd)
print(item.user_type.nid, item.user_type.caption)
取出的UserType對應的信息結果:
<class ‘django.db.models.query.QuerySet‘> <QuerySet [<UserInfo: UserInfo object>, <UserInfo: UserInfo object>]>
UserInfo object UserType object 1 [email protected] ales 123
UserInfo object UserType object 2 [email protected] eric 123
1 管路員
2 普通用戶
可以直接取出對應外鍵的那一列user_type_id:
ret = models.UserInfo.objects.all()
print(type(ret), ret)
for item in ret:
print(item, item.user_type, item.id, item.email, item.user, item.pwd)
print(item.user_type.nid, item.user_type.caption, item.user_type_id)
結果:
<class ‘django.db.models.query.QuerySet‘> <QuerySet [<UserInfo: UserInfo object>, <UserInfo: UserInfo object>]>
UserInfo object UserType object 1 [email protected] ales 123
1 管路員 1
UserInfo object UserType object 2 [email protected] eric 123
2 普通用戶 2
如果只想看到數據對應的名稱,就需要加映射values:
ret = models.UserInfo.objects.all().values(‘user‘, ‘user_type__caption‘)
print(ret, ret.query)
結果:
<QuerySet [{‘user‘: ‘ales‘, ‘user_type__caption‘: ‘管路員‘}, {‘user‘: ‘eric‘, ‘user_type__caption‘: ‘普通用戶‘}]> SELECT `app01_userinfo`.`user`, `app01_usertype`.`caption` FROM `app01_userinfo` INNER JOIN `app01_usertype` ON (`app01_userinfo`.`user_type_id` = `app01_usertype`.`nid`)
通過結果可以看到user_type__caption可以跨表直接獲取相應的結果,再看sql語句中django本身加上了一個join。
如果在models中在加上一個表"P",然後在UserType中增加一條外鍵指向"平"P",需求:要查找UserInfo表中的name和UserType表中的caption和P表中的neme的方法就是在找下一個對象的時候繼續加雙下劃線:
增加的表結構:
查詢語法:
ret = models.UserInfo.objects.all().values(‘user‘, ‘user_type__caption‘, ‘user_type__p__name‘)
print(ret, ret.query)
查詢的結果:
<QuerySet [{‘user_type__p__name‘: ‘allan‘, ‘user_type__caption‘: ‘管路員‘, ‘user‘: ‘ales‘}, {‘user_type__p__name‘: ‘allan‘, ‘user_type__caption‘: ‘普通用戶‘, ‘user‘: ‘eric‘}]> SELECT `app01_userinfo`.`user`, `app01_usertype`.`caption`, `app01_p`.`name` FROM `app01_userinfo` INNER JOIN `app01_usertype` ON (`app01_userinfo`.`user_type_id` = `app01_usertype`.`nid`) INNER JOIN `app01_p` ON (`app01_usertype`.`p_id` = `app01_p`.`id`)
如果要拿用戶類型是管理員的所有用戶:
ret = models.UserInfo.objects.filter(user_type__caption="管路員").values(‘user‘, ‘user_type__caption‘)
print(ret)
結果:
<QuerySet [{‘user‘: ‘ales‘, ‘user_type__caption‘: ‘管路員‘}]>
5、了不起的上下劃線值外鍵反向查找
找到管理員相關聯的信息:
obj = models.UserType.objects.filter(caption=‘管理員‘).first()
print(obj.nid, obj.caption)
輸出結果:
1 管理員
這裏查找的是usertype中的數據,如果通過usertype表查找到userinfo表中的信息就得用***_set:
obj = models.UserType.objects.filter(caption=‘管理員‘).first()
print(obj.nid, obj.caption)
print(obj.userinfo_set.all())
ret = models.UserType.objects.all().values(‘nid‘, ‘caption‘, ‘userinfo__user‘)
print(ret)
查詢結果:
1 管理員
<QuerySet [<UserInfo: UserInfo object>]>
<QuerySet [{‘caption‘: ‘管理員‘, ‘userinfo__user‘: ‘alex‘, ‘nid‘: 1}, {‘caption‘: ‘普通用戶‘, ‘userinfo__user‘: ‘eric‘, ‘nid‘: 2}, {‘caption‘: ‘超級管理員‘, ‘userinfo__user‘: None, ‘nid‘: 3}]>
[27/Aug/2016 15:35:31] "GET /index/ HTTP/1.1" 200 2
如果需要固定字段查找:
obj = models.UserType.objects.all().values(‘nid‘, ‘userinfo__user‘)
print(obj)
結果:
<QuerySet [{‘userinfo__user‘: ‘alex‘, ‘nid‘: 1}, {‘userinfo__user‘: ‘eric‘, ‘nid‘: 2}, {‘userinfo__user‘: None, ‘nid‘: 3}]>
6、多對多之表創建
多對多創建表的時候直接使用ManyToManyField讓django自動創建第三張表或者自己手動創建第三張表,第三張表如果指定多個字段的hu
models表結構(自定義的第三張表):
class Host(models.Model):
hid = models.AutoField(primary_key=True)
hostname = models.CharField(max_length=32)
ip = models.CharField(max_length=32)
class Group(models.Model):
gid = models.AutoField(primary_key=True)
name = models.CharField(max_length=16)
h2g = models.ManyToManyField(‘Host‘, through=‘HostToGroup‘)
class HostToGroup(models.Model):
hgid = models.AutoField(primary_key=True)
host_id = models.ForeignKey(‘Host‘)
group_id = models.ForeignKey(‘Group‘)
status = models.IntegerField()
插入數據:
models.Host.objects.create(hostname=‘c1‘, ip=‘1.1.1.1‘)
models.Host.objects.create(hostname=‘c2‘, ip=‘1.1.1.2‘)
models.Host.objects.create(hostname=‘c3‘, ip=‘1.1.1.3‘)
models.Host.objects.create(hostname=‘c4‘, ip=‘1.1.1.4‘)
models.Host.objects.create(hostname=‘c5‘, ip=‘1.1.1.5‘)
models.Group.objects.create(name=‘技術部‘)
models.Group.objects.create(name=‘財務部‘)
models.Group.objects.create(name=‘人事部‘)
models.Group.objects.create(name=‘公關部‘)
models.Group.objects.create(name=‘運營部‘)
models.Group.objects.create(name=‘銷售部‘)
models.Group.objects.create(name=‘客服部‘)
操作表:
獲取財務部的對象:
obj = models.Group.objects.get(gid=2)
print(obj.gid, obj.name, obj.h2g.all())
結果:
2 財務部 <QuerySet []>
給財務部添加主機:
# 添加一臺主機
obj = models.Group.objects.get(gid=2)
# print(obj.gid, obj.name, obj.h2g.all())
h1 = models.Host.objects.get(hid=1)
obj.h2g.add(h1)
# 把剩下的全部添加
obj = models.Group.objects.get(gid=2)
# print(obj.gid, obj.name, obj.h2g.all())
# h1 = models.Host.objects.get(hid=1)
q = models.Host.objects.filter(hid__gt=1)
obj.h2g.add(*q)
將一臺機器分配給多個組(就得用反向操作了):
h = models.Host.objects.get(hid=1)
h.group_set.add(*models.Group.objects.filter(gid__gt=2))
操作自己手動創建的第三張關係表:
表結構:
表的數據還是原來的數據。
創建表之間的關係,需要自己手動創建關係:
models.HostToGroup.objects.create(status=1, group_id_id=2, host_id_id=3)