Django - ORM資料庫操作 - 表結構、單表操作
目錄
一、ORM (物件關係對映 Object Relational Mapping)
1-3 migrations 內 __init__.py檔案修改
1、在py檔案中呼叫Django環境(可用於orm記錄操作語言的測試)
- values(*field):返回特殊的queryset型別
一、ORM (物件關係對映 Object Relational Mapping)
介紹:對pymysql模組的二次封裝,進行操作mysql
優點:
- 提高了開發效率
- 可以使用程式碼建立表、並對錶進行增刪改查操作
缺點:
- 降低了執行效率
- 不可以自主創造資料庫
二、表結構的建立和修改
1、表結構的建立
1-1 setting內建立資料庫連線
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-2 models.py 內建立模型
from django.db import models # 一個類就是一個表 class User(models.Model): # 自增int型別,是主鍵 id = models.AutoField(primary_key=True) # name 是一個varchar型別,長度是32 name = models.CharField(max_length=32) pwd = models.CharField(max_length=32)
1-3 專案 內 __init__.py檔案修改
注意:
- 若只是在app資料夾下的init檔案新增,則只能當前app內使用mysqldb
- 若在總專案資料夾下的init檔案中新增,所有app的資料庫都使用mysqldb
import pymysql pymysql.install_as_MySQLdb()
1-4 遷移命令的兩種執行方式
- 方式一、終端命令
python3 manage.py makemigrations --- 記錄資料庫的修改記錄
python3 manage.py migrate ---- 資料修改同步資料庫- 方式二、pycharm工具欄操作
工具欄 -- tools--->Run manage.py Task
makemigrations
migrate- 注意:
1 資料庫遷移記錄都在 app01下的migrations裡
2 使用showmigrations命令可以檢視沒有執行migrate的檔案(python manage.py showmigrations)
3 makemigrations是生成一個檔案,migrate是將更改提交到資料量
2、表結構的修改
2-1 增加欄位
from django.db import models # 一個類就是一個表 class User(models.Model): # 自增int型別,是主鍵 id = models.AutoField(primary_key=True) # name 是一個varchar型別,長度是32 name = models.CharField(max_length=32) pwd = models.CharField(max_length=32) # 在原有結構上新增欄位,必須帶有預設值 phone=models.CharField(max_length=64,default='120')
2-2 刪除欄位
from django.db import models # 一個類就是一個表 class User(models.Model): # 自增int型別,是主鍵 id = models.AutoField(primary_key=True) # name 是一個varchar型別,長度是32 name = models.CharField(max_length=32) pwd = models.CharField(max_length=32) # 在原有結構上註釋欄位 # phone=models.CharField(max_length=64,default='120') ''' 檔案修改完成,執行兩句遷移命令 '''
2-3 修改欄位
from django.db import models # 一個類就是一個表 class User(models.Model): # 自增int型別,是主鍵 id = models.AutoField(primary_key=True) # name 是一個varchar型別,長度是32 name = models.CharField(max_length=32) pwd = models.CharField(max_length=32) # 在原有結構上修改結構內容 phone=models.CharField(max_length=64,default='11111111111') ''' 檔案修改完成,執行兩句遷移命令 '''
3、模型內欄位型別
- 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)
mallIntegerField(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.FileSystemStorageImageField(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) - 二進位制型別
4、欄位引數
- (0) 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 中的選項。
5、元資訊
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
三、單表記錄操作
1、在py檔案中呼叫Django環境(可用於orm記錄操作語言的測試)
import os if __name__ == '__main__': os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day76orm.settings") import django django.setup() from app01 import models # 記錄的操作 book=models.Book.objects.create(name='紅樓夢',price=23.8,publish='人民出版社',author='曹雪芹',create_data='2018-09-17') print(book.name) …… ……
2、查(API)
總結:
- python資料精度存在盲點,使用查詢數字型別的時候,注意轉換的sql語句所傳輸的數字是否精確
- 可以對queryset物件使用.query方法呼叫,可以查詢最終傳輸到資料的純生sql語句
- 查詢得到的queryset可以進行後續的查詢方法,通過.進行呼叫
all() - models.User.objects.all() 查詢所有結果,得到的是一個queryset物件(列表),列表記憶體儲物件。 filter(**kwargs)
-- models.User.objects.filter(name='紅樓夢').first()包含與所給篩選條件匹配的物件,返回queryset物件 get(**kwargs)
-- models.User.objects.get(name='紅樓夢')
返回篩選條件匹配的物件,且返回結果有且只有一個;若存在符合物件超過一個或者不存在,丟擲異常 exclude(*field)
-- models.User.objects.exclude(name='紅樓夢')
包含了所有與篩選條件不匹配的物件,返回queryset物件 order_by(*field)
-- models.User.objects.all.order_by('id')
-- models.User.objects.all.order_by('-id','name')
對查詢結果排序 ('-id'),預設升序,加- 降序。多個過濾條件可以同時共用,返回queryset物件 reverse()
-- models.User.objects.all().reverse()
對查詢結果反向排序,返回queryset物件 count()
-- models.User.objects.all().count()
queryset為呼叫物件,返回資料庫中匹配查詢(QuerySet)的物件數量 first()
- models.User.objects.first()
返回第一條記錄 last()
-models.User.objects.last()
返回最後一條記錄 exists() 若queryset包含資料,返回True,否則False,返回布林型別 values(*field)
-- models.User.objects.all().values('name')
返回一個ValueQuerySet - 一個特殊的QuerySet,執行後得到一個可迭代的字典序列
<QuerySet [{'name': '紅樓夢'}, {'name': '水滸傳'}, {'name': '西遊記'}]>values_list(*field)
-- models.User.objects.all().values_list('name','id')
同values()相似,返回一個元組列表
<QuerySet [('紅樓夢', Decimal('23.80')), ('水滸傳', Decimal('99.80')), ('西遊記', Decimal('73.80'))]>distinct()
-- models.User.objects.all().distinct()
-- models.Book.objects.all().values('name').distinct()
從返回的結果中剔除重複記錄;distinct seletc * 的時候沒有意義,只要存在唯一的欄位(id段等)都沒有去重意義 - filter() - 返回queryset物件
# 查詢名字叫西遊記的這本書,返回單個物件 ret = models.Book.objects.filter(name='西遊記').first() print(ret) print(type(ret)) # 支援類列表的查詢方式 ret = models.Book.objects.filter(name='西遊記')[1] # 類列表的查詢方式,不支援負數,只支援正數 ret = models.Book.objects.filter(name='西遊記')[-1] # filter內可以傳多個引數,用逗號分隔,他們之間是and的關係 # 返回queryset # 價格使用字串,防止精度不準確,導致無法進行查詢 ret = models.Book.objects.filter(name='西遊記', price='73.8') print(ret) print(type(ret)) # ret.query -->queryset物件列印sql print(ret.query) ''' SELECT `app01_book`.`id`, `app01_book`.`name`, `app01_book`.`price`, `app01_book`.`publish`, `app01_book`.`author`, `app01_book`.`create_data` FROM `app01_book` WHERE ( `app01_book`.`name` = 西遊記 AND `app01_book`.`price` = 73.8 ) '''
- 基於filter的雙下劃線模糊查詢
# filter(欄位名__gt='') ---- 大於 # 查詢價格大於89 的書 ret=models.Book.objects.filter(price__gt='89') # filter(欄位名__lt='') ---- 小於 # 查詢價格小於89 的書 ret=models.Book.objects.filter(price__lt='89') # ret=models.Book.objects.filter(price__lt='89',price='89') --- 錯誤的小於等於 # filter(欄位名__lte='') ---- 小於等於 ret=models.Book.objects.filter(price__lte='89') # filter(欄位名__gte='') ---- 大於等於 ret = models.Book.objects.filter(price__gte='89') # filter(欄位名__in='') ---- 欄位存在列表中 ret=models.Book.objects.filter(price__in=['23.8','89','100']) # filter(欄位名__range='') ---- 欄位資料在範圍內(between and) ret=models.Book.objects.filter(price__range=[50,100]) # filter(欄位名__contains='') ---- 欄位資料包含內容 模糊查詢 like % % # 查詢名字有'%紅%'的書 ret=models.Book.objects.filter(name__contains='紅') # filter(欄位名__icontains='') ---- 欄位資料包含內容,並且忽略大小寫 模糊查詢 like % % # 查詢名字帶p的書,忽略大小寫 ret=models.Book.objects.filter(name__icontains='P') # filter(欄位名__startswith='') ---- 欄位資料以內容開頭 ret=models.Book.objects.filter(name__startswith='紅') # filter(欄位名__endswith='') ---- 欄位資料以內容結尾 ret=models.Book.objects.filter(name__endswith='夢') # filter(欄位名__year='') ---- 查詢欄位內容以指定年份查詢 ret=models.Book.objects.filter(create_data__year='2018') # filter(欄位名__month='') ---- 查詢欄位內容以指定月份查詢 ret = models.Book.objects.filter(create_data__month='9') # filter(欄位名__day='') ---- 查詢欄位內容以指定日期查詢 ret = models.Book.objects.filter(create_data__day='8')
- values(*field):返回特殊的queryset型別
# values(*field): queryset物件裡套字典 ret=models.Book.objects.all().values('name','price') print(ret) # <QuerySet [{'name': '紅樓夢', 'price': Decimal('23.80')}, {'name': '水滸傳', 'price': Decimal('99.80')}, {'name': '西遊記', 'price': Decimal('73.80')}]> print(ret[1]) # {'name': '水滸傳'} print(ret.query) ''' SELECT `app01_book`.`name`, `app01_book`.`price` FROM `app01_book` ''' ret=models.Book.objects.all().values('name') print(ret) # <QuerySet [{'name': '紅樓夢'}, {'name': '水滸傳'}, {'name': '西遊記'}]> print(ret[1]) # {'name': '水滸傳'} print(ret.query) ''' SELECT `app01_book`.`name` FROM `app01_book` '''
3、增(兩種方式)
方式一、create方法建立記錄物件
name=request.POST.get('name') pwd=request.POST.get('password') addr=request.POST.get('addr') user=models.User.objects.create(name=name,password=pwd,address=addr)
方式二、建立物件,save方法儲存
name=request.POST.get('name') pwd=request.POST.get('password') addr=request.POST.get('addr') user=models.User(name=name,password=pwd,address=addr) user.save()
4、改(兩種方式)
1、方式一:update()方法
注意:update方法對於任何結果集(queryset)有效,可以同時更新多條記錄,使用update()方法會返回一個整數數值,表示受影響的記錄條數。
name=request.POST.get('name') pwd=request.POST.get('password') addr=request.POST.get('addr') models.User.objects.filter(id=id).update(name=name,password=pwd,address=addr)
2、方式二、修改物件,save 儲存
book = models.Book.objects.filter(name='西遊記').first() book.price=89 book.save()
5、刪(delete())
1、所有物件刪除
models.User.objects.all().delete()
2、根據記錄刪除
id = request.GET.get('id') ret = models.User.objects.filter(id=id).delete() ret = models.Book.objects.filter(name='西遊記').first() ret.delete()