一、model 到目前為止,當我們的程式涉及到資料庫相關操作時,我們一般都會這麼搞: 創建資料庫,設計表結構和欄位 使用 MySQLdb 來連接資料庫,並編寫數據訪問層代碼 業務邏輯層去調用數據訪問層執行資料庫操作 django為使用一種新的方式,即:關係對象映射(Object Relational ...
一、model
到目前為止,當我們的程式涉及到資料庫相關操作時,我們一般都會這麼搞:
- 創建資料庫,設計表結構和欄位
- 使用 MySQLdb 來連接資料庫,並編寫數據訪問層代碼
- 業務邏輯層去調用數據訪問層執行資料庫操作
import MySQLdb def GetList(sql): db = MySQLdb.connect(user='root', db='wupeiqidb', passwd='1234', host='localhost') cursor = db.cursor() cursor.execute(sql) data = cursor.fetchall() db.close() return data def GetSingle(sql): db = MySQLdb.connect(user='root', db='wupeiqidb', passwd='1234', host='localhost') cursor = db.cursor() cursor.execute(sql) data = cursor.fetchone() db.close() return data
django為使用一種新的方式,即:關係對象映射(Object Relational Mapping,簡稱ORM)。
PHP:activerecord
Java:Hibernate
C#:Entity Framework
django中遵循 Code Frist 的原則,即:根據代碼中定義的類來自動生成資料庫表。
1、創建表
基本結構
from django.db import models class userinfo(models.Model): name = models.CharField(max_length=30) email = models.EmailField() memo = models.TextField()
欄位
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) - 二進位類型
參數
null 資料庫中欄位是否可以為空 db_column 資料庫中欄位的列名 db_tablespace 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': '格式錯誤'} validators 自定義錯誤驗證(列表類型),從而定製想要的驗證規則 from django.core.validators import RegexValidator from django.core.validators import EmailValidator,URLValidator,DecimalValidator,\ MaxLengthValidator,MinLengthValidator,MaxValueValidator,MinValueValidator 如: test = models.CharField( max_length=32, error_messages={ 'c1': '優先錯信息1', 'c2': '優先錯信息2', 'c3': '優先錯信息3', }, validators=[ RegexValidator(regex='root_\d+', message='錯誤了', code='c1'), RegexValidator(regex='root_112233\d+', message='又錯誤了', code='c2'), EmailValidator(message='又錯誤了', code='c3'), ] )
元信息
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 更多:https://docs.djangoproject.com/en/1.10/ref/models/options/
拓展
1.觸發Model中的驗證和錯誤提示有兩種方式: a. Django Admin中的錯誤信息會優先根據Admiin內部的ModelForm錯誤信息提示,如果都成功,才來檢查Model的欄位並顯示指定錯誤信息 b. 調用Model對象的 clean_fields 方法,如: # models.py class UserInfo(models.Model): nid = models.AutoField(primary_key=True) username = models.CharField(max_length=32) email = models.EmailField(error_messages={'invalid': '格式錯了.'}) # views.py def index(request): obj = models.UserInfo(username='11234', email='uu') try: print(obj.clean_fields()) except Exception as e: print(e) return HttpResponse('ok') # Model的clean方法是一個鉤子,可用於定製操作,如:上述的異常處理。 2.Admin中修改錯誤提示 # admin.py from django.contrib import admin from model_club import models from django import forms class UserInfoForm(forms.ModelForm): username = forms.CharField(error_messages={'required': '用戶名不能為空.'}) email = forms.EmailField(error_messages={'invalid': '郵箱格式錯誤.'}) age = forms.IntegerField(initial=1, error_messages={'required': '請輸入數值.', 'invalid': '年齡必須為數值.'}) class Meta: model = models.UserInfo # fields = ('username',) fields = "__all__" class UserInfoAdmin(admin.ModelAdmin): form = UserInfoForm admin.site.register(models.UserInfo, UserInfoAdmin)連表結構
- 一對多:models.ForeignKey(其他表)
- 多對多:models.ManyToManyField(其他表)
- 一對一:models.OneToOneField(其他表)
1 ForeignKey(ForeignObject) # ForeignObject(RelatedField) 2 to, # 要進行關聯的表名 3 to_field=None, # 要關聯的表中的欄位名稱 4 on_delete=None, # 當刪除關聯表中的數據時,當前表與其關聯的行的行為 5 - models.CASCADE,刪除關聯數據,與之關聯也刪除 6 - models.DO_NOTHING,刪除關聯數據,引發錯誤IntegrityError 7 - models.PROTECT,刪除關聯數據,引發錯誤ProtectedError 8 - models.SET_NULL,刪除關聯數據,與之關聯的值設置為null(前提FK欄位需要設置為可空) 9 - models.SET_DEFAULT,刪除關聯數據,與之關聯的值設置為預設值(前提FK欄位需要設置預設值) 10 - models.SET,刪除關聯數據, 11 a. 與之關聯的值設置為指定值,設置:models.SET(值) 12 b. 與之關聯的值設置為可執行對象的返回值,設置:models.SET(可執行對象) 13 14 def func(): 15 return 10 16 17 class MyModel(models.Model): 18 user = models.ForeignKey( 19 to="User", 20 to_field="id" 21 on_delete=models.SET(func),) 22 related_name=None, # 反向操作時,使用的欄位名,用於代替 【表名_set】 如: obj.表名_set.all() 23 related_query_name=None, # 反向操作時,使用的連接首碼,用於替換【表名】 如: models.UserGroup.objects.filter(表名__欄位名=1).values('表名__欄位名') 24 limit_choices_to=None, # 在Admin或ModelForm中顯示關聯數據時,提供的條件: 25 # 如: 26 - limit_choices_to={'nid__gt': 5} 27 - limit_choices_to=lambda : {'nid__gt': 5} 28 29 from django.db.models import Q 30 - limit_choices_to=Q(nid__gt=10) 31 - limit_choices_to=Q(nid=8) | Q(nid__gt=10) 32 - limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root') 33 db_constraint=True # 是否在資料庫中創建外鍵約束 34 parent_link=False # 在Admin中是否顯示關聯數據 35 36 37 OneToOneField(ForeignKey) 38 to, # 要進行關聯的表名 39 to_field=None # 要關聯的表中的欄位名稱 40 on_delete=None, # 當刪除關聯表中的數據時,當前表與其關聯的行的行為 41 42 ###### 對於一對一 ###### 43 # 1. 一對一其實就是 一對多 + 唯一索引 44 # 2.當兩個類之間有繼承關係時,預設會創建一個一對一欄位 45 # 如下會在A表中額外增加一個c_ptr_id列且唯一: 46 class C(models.Model): 47 nid = models.AutoField(primary_key=True) 48 part = models.CharField(max_length=12) 49 50 class A(C): 51 id = models.AutoField(primary_key=True) 52 code = models.CharField(max_length=1) 53 54 ManyToManyField(RelatedField) 55 to, # 要進行關聯的表名 56 related_name=None, # 反向操作時,使用的欄位名,用於代替 【表名_set】 如: obj.表名_set.all() 57 related_query_name=None, # 反向操作時,使用的連接首碼,用於替換【表名】 如: models.UserGroup.objects.filter(表名__欄位名=1).values('表名__欄位名') 58 limit_choices_to=None, # 在Admin或ModelForm中顯示關聯數據時,提供的條件: 59 # 如: 60 - limit_choices_to={'nid__gt': 5} 61 - limit_choices_to=lambda : {'nid__gt': 5} 62 63 from django.db.models import Q 64 - limit_choices_to=Q(nid__gt=10) 65 - limit_choices_to=Q(nid=8) | Q(nid__gt=10) 66 - limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root') 67 symmetrical=None, # 僅用於多對多自關聯時,symmetrical用於指定內部是否創建反向操作的欄位 68 # 做如下操作時,不同的symmetrical會有不同的可選欄位 69 models.BB.objects.filter(...) 70 71 # 可選欄位有:code, id, m1 72 class BB(models.Model): 73 74 code = models.CharField(max_length=12) 75 m1 = models.ManyToManyField('self',symmetrical=True) 76 77 # 可選欄位有: bb, code, id, m1 78 class BB(models.Model): 79 80 code = models.CharField(max_length=12) 81 m1 = models.ManyToManyField('self',symmetrical=False) 82 83 through=None, # 自定義第三張表時,使用欄位用於指定關係表 84 through_fields=None, # 自定義第三張表時,使用欄位用於指定關係表中那些欄位做多對多關係表 85 from django.db import models 86 87 class Person(models.Model): 88 name = models.CharField(max_length=50) 89 90 class Group(models.Model): 91 name = models.CharField(max_length=128) 92 members = models.ManyToManyField( 93 Person, 94 through='Membership', 95 through_fields=('group', 'person'), 96 ) 97 98 class Membership(models.Model): 99 group = models.ForeignKey(Group, on_delete=models.CASCADE) 100 person = models.ForeignKey(Person, on_delete=models.CASCADE) 101 inviter = models.ForeignKey( 102 Person, 103 on_delete=models.CASCADE, 104 related_name="membership_invites", 105 ) 106 invite_reason = models.CharField(max_length=64) 107 db_constraint=True, # 是否在資料庫中創建外鍵約束 108 db_table=None, # 預設創建第三張表時,資料庫中表的名稱欄位和參數
2、操作表
基本操作
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() # 修改單條數據View Code
進階操作(了不起的雙下劃線)
利用雙下劃線將欄位和對應的操作連接起來
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__gte=1) # 獲取id大於等於1的值 9 # models.Tb1.objects.filter(id__lt=10) # 獲取id小於10的值 10 # models.Tb1.objects.filter(id__lte=10) # 獲取id小於10的值 11 # models.Tb1.objects.filter(id__lt=10, id__gt=1) # 獲取id大於1 且 小於10的值 12 13 # in 14 # 15 # models.Tb1.objects.filter(id__in=[11, 22, 33]) # 獲取id等於11、22、33的數據 16 # models.Tb1.objects.exclude(id__in=[11, 22, 33]) # not in 17 18 # isnull 19 # Entry.objects.filter(pub_date__isnull=True) 20 21 # contains 22 # 23 # models.Tb1.objects.filter(name__contains="ven") 24 # models.Tb1.objects.filter(name__icontains="ven") # icontains大小寫不敏感 25 # models.Tb1.objects.exclude(name__icontains="ven") 26 27 # range 28 # 29 # models.Tb1.objects.filter(id__range=[1, 2]) # 範圍bettwen and 30 31 # 其他類似 32 # 33 # startswith,istartswith, endswith, iendswith, 34 35 # order by 36 # 37 # models.Tb1.objects.filter(name='seven').order_by('id') # asc 38 # models.Tb1.objects.filter(name='seven').order_by('-id') # desc 39 40 # group by 41 # 42 # from django.db.models import Count, Min, Max, Sum 43 # models.Tb1.objects.filter(c1=1).values('id').annotate(c=Count('num')) 44 # SELECT "app01_tb1"."id", COUNT("app01_tb1"."num") AS "c" FROM "app01_tb1" WHERE "app01_tb1"."c1" = 1 GROUP BY "app01_tb1"."id" 45 46 # limit 、offset 47 # 48 # models.Tb1.objects.all()[10:20] 49 50 # regex正則匹配,iregex 不區分大小寫 51 # 52 # Entry.objects.get(title__regex=r'^(An?|The) +') 53 # Entry.objects.get(title__iregex=r'^(an?|the) +') 54 55 # date 56 # 57 # Entry.objects.filter(pub_date__date=datetime.date(2005, 1, 1)) 58 # Entry.objects.filter(pub_date__date__gt=datetime.date(2005, 1, 1)) 59 60 # year 61 # 62 # Entry.objects.filter(pub_date__year=2005) 63 # Entry.objects.filter(pub_date__year__gte=2005) 64 65 # month 66 # 67 # Entry.objects.filter(pub_date__month=12) 68 # Entry.objects.filter(pub_date__month__gte=6) 69 70 # day 71 # 72 # Entry.objects.filter(pub_date__day=3) 73 # Entry.objects.filter(pub_date__day__gte=3) 74 75 # week_day 76 # 77 # Entry.objects.filter(pub_date__week_day=2) 78 # Entry.objects.filter(pub_date__week_day__gte=2) 79 80 # hour 81 # 82 # Event.objects.filter(timestamp__hour=23) 83 # Event.objects.filter(time__hour=5) 84 # Event.objects.filter(timestamp__hour__gte=12) 85 86 # minute 87