1. 程式人生 > >Django - ORM資料庫操作 - 表結構、單表操作

Django - ORM資料庫操作 - 表結構、單表操作

目錄

一、ORM (物件關係對映 Object Relational Mapping)

二、表結構的建立和修改

 1、表結構的建立

1-1 setting內建立資料庫連線

1-2 models.py 內建立模型

1-3 migrations 內 __init__.py檔案修改

1-4 遷移命令的兩種執行方式

2、表結構的修改

2-1 增加欄位

2-2 刪除欄位

2-3 修改欄位

3、模型內欄位型別

4、欄位引數

5、元資訊

三、單表記錄操作

1、在py檔案中呼叫Django環境(可用於orm記錄操作語言的測試)

2、查(API)

-  filter() - 返回queryset物件

- 基於filter的雙下劃線模糊查詢

- values(*field):返回特殊的queryset型別

3、增(兩種方式)

方式一、create方法建立記錄物件

方式二、建立物件,save方法儲存

4、改(兩種方式)

1、方式一:update()方法

2、方式二、修改物件,save 儲存

5、刪(delete())

1、所有物件刪除

2、根據記錄刪除


一、ORM (物件關係對映 Object Relational Mapping)

介紹:對pymysql模組的二次封裝,進行操作mysql

優點:

  1. 提高了開發效率
  2. 可以使用程式碼建立表、並對錶進行增刪改查操作

缺點:

  1. 降低了執行效率
  2. 不可以自主創造資料庫

二、表結構的建立和修改

 

 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.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) - 二進位制型別

 

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()