
一、django ORM簡介
O(objects):類和對象。R(Relation):關(guān)系,關(guān)系數(shù)據(jù)庫中的表格。M(Mapping):映射。
Django ORM框架的功能:
1.建立模型類和表之間的對應(yīng)關(guān)系,允許我們通過面向?qū)ο蟮姆绞絹聿僮鲾?shù)據(jù)庫。
2.根據(jù)設(shè)計的模型類生成數(shù)據(jù)庫中的表格。
3.通過方便的配置就可以進(jìn)行數(shù)據(jù)庫的切換。
二、 數(shù)據(jù)庫的配置
Django可以配置使用sqlite3,mysql,oracle,postgresql等數(shù)據(jù)庫。Django默認(rèn)使用的是sqlite3數(shù)據(jù)庫,settigs.py里面:
DATABASES = {
? ? 'default': {
? ? ? ? 'ENGINE': 'django.db.backends.sqlite3',#默認(rèn)使用的數(shù)據(jù)庫引擎是sqlite3,項目自動創(chuàng)建
? ? ? ? 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),#指定數(shù)據(jù)庫所在的路徑
? ? }
}
Django項目也可以配置使用mysql數(shù)據(jù)庫,使用如下配置:
DATABASES = {
? ? 'default': {
? ? ? ? 'ENGINE': 'django.db.backends.mysql',#表示使用的是mysql數(shù)據(jù)庫的引擎
? ? ? ? 'NAME': 'db1',? ? ? #數(shù)據(jù)庫的名字,可以在mysql的提示符下先創(chuàng)建好
? ? ? ? 'USER':'root',? ? ? #數(shù)據(jù)庫用戶名
? ? ? ? 'PASSWORD':'',? ? ? #數(shù)據(jù)庫密碼
? ? ? ? 'HOST':'',? ? ? ? ? #數(shù)據(jù)庫主機(jī),留空默認(rèn)為"localhost"
? ? ? ? 'PORT':'3306',? ? ? #數(shù)據(jù)庫使用的端口
? ? }
}
配置好數(shù)據(jù)庫的信息后還必須安裝數(shù)據(jù)庫的驅(qū)動程序,Django默認(rèn)導(dǎo)入的mysql的驅(qū)動程序是MySQLdb,然而MySQLdb對于py3支持不全,所以這里使用PyMySQL。
pip install pymysql
在項目名文件下的__init__.py文件中寫入如下配置:
import pymysql
pymysql.install_as_MySQLdb()
三、創(chuàng)建數(shù)據(jù)庫表結(jié)構(gòu)文件
對應(yīng)app目錄下的models.py
1、生成一個簡單的數(shù)據(jù)庫表:
在未指定primary_key的情況下,Django會默認(rèn)創(chuàng)建一個id自增字段作為主鍵。
from django.db import models
class Account(models.Model):
? ? account_name = models.CharField(max_length=20)
? ? account_id = models.IntegerField(primary_key=True)
? ? balance = models.DecimalField(max_digits=2, decimal_places=2)
2、執(zhí)行命令生成到數(shù)據(jù)庫
python manage.py makemigrations
python manage.py migrate # 生成數(shù)據(jù)表
四、數(shù)據(jù)庫字段
AutoField(Field) - int自增列,必須填入?yún)?shù) primary_key=True
BigAutoField(AutoField) - bigint自增列,必須填入?yún)?shù) primary_key=True
SmallIntegerField(IntegerField): - 小整數(shù) -32768 ~ 32767
PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField) - 正小整數(shù) 0 ~ 32767
IntegerField(Field) - 整數(shù)列(有符號的) -2147483648 ~ 2147483647
PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField) - 正整數(shù) 0 ~ 2147483647
BigIntegerField(IntegerField): - 長整型(有符號的) -9223372036854775808 ~ 9223372036854775807
BooleanField(Field) - 布爾值類型
NullBooleanField(Field): - 可以為空的布爾值
CharField(Field) - 字符類型
- 必須提供max_length參數(shù), max_length表示字符長度
TextField(Field) - 文本類型
EmailField(CharField): - 字符串類型,Django Admin以及ModelForm中提供驗證機(jī)制
IPAddressField(Field) - 字符串類型,Django Admin以及ModelForm中提供驗證 IPV4 機(jī)制
GenericIPAddressField(Field) - 字符串類型,Django Admin以及ModelForm中提供驗證 Ipv4和Ipv6
- 參數(shù):
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中提供驗證支持 字母、數(shù)字、下劃線、連接符(減號)
CommaSeparatedIntegerField(CharField) - 字符串類型,格式必須為逗號分割的數(shù)字
UUIDField(Field) - 字符串類型,Django Admin以及ModelForm中提供對UUID格式的驗證
FilePathField(Field) - 字符串,Django Admin以及ModelForm中提供讀取文件夾下文件的功能
- 參數(shù):
path,? ? ? ? ? ? ? ? ? ? ? 文件夾路徑
match=None,? ? ? ? ? ? ? ? 正則匹配
recursive=False,? ? ? ? ? 遞歸下面的文件夾
allow_files=True,? ? ? ? ? 允許文件
allow_folders=False,? ? ? 允許文件夾
FileField(Field) - 字符串,路徑保存在數(shù)據(jù)庫,文件上傳到指定目錄
- 參數(shù):
upload_to = ""? ? ? 上傳文件的保存路徑
storage = None? ? ? 存儲組件,默認(rèn)django.core.files.storage.FileSystemStorage
ImageField(FileField) - 字符串,路徑保存在數(shù)據(jù)庫,文件上傳到指定目錄
- 參數(shù):
upload_to = ""? ? ? 上傳文件的保存路徑
storage = None? ? ? 存儲組件,默認(rèn)django.core.files.storage.FileSystemStorage
width_field=None,? 上傳圖片的高度保存的數(shù)據(jù)庫字段名(字符串)
height_field=None? 上傳圖片的寬度保存的數(shù)據(jù)庫字段名(字符串)
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) - 長整數(shù),時間間隔,數(shù)據(jù)庫中按照bigint存儲,ORM中獲取的值為datetime.timedelta類型
FloatField(Field) - 浮點型
DecimalField(Field) - 10進(jìn)制小數(shù)
- 參數(shù):
max_digits,小數(shù)總長度
decimal_places,小數(shù)位長度
BinaryField(Field)- 二進(jìn)制類型
五、數(shù)據(jù)庫字段參數(shù)
null? ? ? ? ? ? ? ? 數(shù)據(jù)庫中字段是否可以為空
db_column? ? ? ? ? 數(shù)據(jù)庫中字段的列名
default? ? ? ? ? ? 數(shù)據(jù)庫中字段的默認(rèn)值
primary_key? ? ? ? 數(shù)據(jù)庫中字段是否為主鍵
db_index? ? ? ? ? ? 數(shù)據(jù)庫中字段是否可以建立索引
unique? ? ? ? ? ? ? 數(shù)據(jù)庫中字段是否可以建立唯一索引
unique_for_date? ? 數(shù)據(jù)庫中字段【日期】部分是否可以建立唯一索引
unique_for_month? ? 數(shù)據(jù)庫中字段【月】部分是否可以建立唯一索引
unique_for_year? ? 數(shù)據(jù)庫中字段【年】部分是否可以建立唯一索引
verbose_name? ? ? ? Admin中顯示的字段名稱
blank? ? ? ? ? ? ? Admin中是否允許用戶輸入為空
editable? ? ? ? ? ? Admin中是否可以編輯
help_text? ? ? ? ? Admin中該字段的提示信息
choices? ? ? ? ? ? Admin中顯示選擇框的內(nèi)容,用不變動的數(shù)據(jù)放在內(nèi)存中從而避免跨表操作
如:gf = models.IntegerField(choices=[(0, '何穗'),(1, '大表姐'),],default=1)
error_messages? ? ? 自定義錯誤信息(字典類型),從而定制想要顯示的錯誤信息;
字典?。簄ull, blank, invalid, invalid_choice, unique, and unique_for_date
如:{'null': "不能為空.", 'invalid': '格式錯誤'}
validators? ? ? ? ? 自定義錯誤驗證(列表類型),從而定制想要的驗證規(guī)則
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': '優(yōu)先錯信息1',
'c2': '優(yōu)先錯信息2',
'c3': '優(yōu)先錯信息3',
},
validators=[
RegexValidator(regex='root_\d+', message='錯誤了', code='c1'),
RegexValidator(regex='root_112233\d+', message='又錯誤了', code='c2'),
EmailValidator(message='又錯誤了', code='c3'), ]
)
六、數(shù)據(jù)庫Meta元信息
class UserInfo(models.Model):
? ? ? ? nid = models.AutoField(primary_key=True)
? ? ? ? username = models.CharField(max_length=32)
? ? ? ? class Meta:
? ? ? ? ? ? # 數(shù)據(jù)庫中生成的表名稱 默認(rèn) app名稱 + 下劃線 + 類名
? ? ? ? ? ? db_table = "table_name"
? ? ? ? ? ? # 聯(lián)合索引
? ? ? ? ? ? index_together = [
? ? ? ? ? ? ? ? ("pub_date", "deadline"),
? ? ? ? ? ? ]
? ? ? ? ? ? # 聯(lián)合唯一索引
? ? ? ? ? ? unique_together = (("driver", "restaurant"),)
? ? ? ? ? ? # admin中顯示的表名稱
? ? ? ? ? ? verbose_name
? ? ? ? ? ? # verbose_name加s
? ? ? ? ? ? verbose_name_plural
七、關(guān)系字段
關(guān)系字段用于保存數(shù)據(jù)表之間的關(guān)系,包括ForeignKey, ManyToManyField等。
1、ForeignKey
ForeignKey(ForeignObject) # ForeignObject(RelatedField)
? ? ? ? to,? ? ? ? ? ? ? ? ? ? ? ? # 要進(jìn)行關(guān)聯(lián)的表名
? ? ? ? to_field=None,? ? ? ? ? ? ? # 要關(guān)聯(lián)的表中的字段名稱
? ? ? ? on_delete=None,? ? ? ? ? ? # 當(dāng)刪除關(guān)聯(lián)表中的數(shù)據(jù)時,當(dāng)前表與其關(guān)聯(lián)的行的行為
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? - models.CASCADE,刪除關(guān)聯(lián)數(shù)據(jù),與之關(guān)聯(lián)也刪除
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? - models.DO_NOTHING,刪除關(guān)聯(lián)數(shù)據(jù),引發(fā)錯誤IntegrityError
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? - models.PROTECT,刪除關(guān)聯(lián)數(shù)據(jù),引發(fā)錯誤ProtectedError
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? - models.SET_NULL,刪除關(guān)聯(lián)數(shù)據(jù),與之關(guān)聯(lián)的值設(shè)置為null(前提FK字段需要設(shè)置為可空)
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? - models.SET_DEFAULT,刪除關(guān)聯(lián)數(shù)據(jù),與之關(guān)聯(lián)的值設(shè)置為默認(rèn)值(前提FK字段需要設(shè)置默認(rèn)值)
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? - models.SET,刪除關(guān)聯(lián)數(shù)據(jù),
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? a. 與之關(guān)聯(lián)的值設(shè)置為指定值,設(shè)置:models.SET(值)
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? b. 與之關(guān)聯(lián)的值設(shè)置為可執(zhí)行對象的返回值,設(shè)置:models.SET(可執(zhí)行對象)
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? def func():
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? return 10
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? class MyModel(models.Model):
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? user = models.ForeignKey(
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? to="User",
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? to_field="id"
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? on_delete=models.SET(func),)
? ? ? ? related_name=None,? ? ? ? ? # 反向操作時,使用的字段名,用于代替 【表名_set】 如: obj.表名_set.all()
? ? ? ? related_query_name=None,? ? # 反向操作時,使用的連接前綴,用于替換【表名】? ? 如: models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名')
? ? ? ? limit_choices_to=None,? ? ? # 在Admin或ModelForm中顯示關(guān)聯(lián)數(shù)據(jù)時,提供的條件:
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? # 如:
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? - limit_choices_to={'nid__gt': 5}
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? - limit_choices_to=lambda : {'nid__gt': 5}
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? from django.db.models import Q
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? - limit_choices_to=Q(nid__gt=10)
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? - limit_choices_to=Q(nid=8) | Q(nid__gt=10)
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? - limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root')
? ? ? ? db_constraint=True? ? ? ? ? # 是否在數(shù)據(jù)庫中創(chuàng)建外鍵約束
? ? ? ? parent_link=False? ? ? ? ? # 在Admin中是否顯示關(guān)聯(lián)數(shù)據(jù)
2、OneToOneField
OneToOneField(ForeignKey)
? ? ? ? to,? ? ? ? ? ? ? ? ? ? ? ? # 要進(jìn)行關(guān)聯(lián)的表名
? ? ? ? to_field=None? ? ? ? ? ? ? # 要關(guān)聯(lián)的表中的字段名稱
? ? ? ? on_delete=None,? ? ? ? ? ? # 當(dāng)刪除關(guān)聯(lián)表中的數(shù)據(jù)時,當(dāng)前表與其關(guān)聯(lián)的行的行為
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ###### 對于一對一 ######
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? # 1. 一對一其實就是 一對多 + 唯一索引
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? # 2.當(dāng)兩個類之間有繼承關(guān)系時,默認(rèn)會創(chuàng)建一個一對一字段
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? # 如下會在A表中額外增加一個c_ptr_id列且唯一:
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? class C(models.Model):
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? nid = models.AutoField(primary_key=True)
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? part = models.CharField(max_length=12)
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? class A(C):
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? id = models.AutoField(primary_key=True)
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? code = models.CharField(max_length=1)
3、ManyToManyField
ManyToManyField(RelatedField)
? ? ? ? to,? ? ? ? ? ? ? ? ? ? ? ? # 要進(jìn)行關(guān)聯(lián)的表名
? ? ? ? related_name=None,? ? ? ? ? # 反向操作時,使用的字段名,用于代替 【表名_set】 如: obj.表名_set.all()
? ? ? ? related_query_name=None,? ? # 反向操作時,使用的連接前綴,用于替換【表名】? ? 如: models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名')
? ? ? ? limit_choices_to=None,? ? ? # 在Admin或ModelForm中顯示關(guān)聯(lián)數(shù)據(jù)時,提供的條件:
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? # 如:
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? - limit_choices_to={'nid__gt': 5}
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? - limit_choices_to=lambda : {'nid__gt': 5}
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? from django.db.models import Q
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? - limit_choices_to=Q(nid__gt=10)
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? - limit_choices_to=Q(nid=8) | Q(nid__gt=10)
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? - limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root')
? ? ? ? symmetrical=None,? ? ? ? ? # 僅用于多對多自關(guān)聯(lián)時,symmetrical用于指定內(nèi)部是否創(chuàng)建反向操作的字段
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? # 做如下操作時,不同的symmetrical會有不同的可選字段
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? models.BB.objects.filter(...)
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? # 可選字段有:code, id, m1
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? class BB(models.Model):
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? code = models.CharField(max_length=12)
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? m1 = models.ManyToManyField('self',symmetrical=True)
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? # 可選字段有: bb, code, id, m1
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? class BB(models.Model):
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? code = models.CharField(max_length=12)
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? m1 = models.ManyToManyField('self',symmetrical=False)
? ? ? ? through=None,? ? ? ? ? ? ? # 自定義第三張表時,使用字段用于指定關(guān)系表
? ? ? ? through_fields=None,? ? ? ? # 自定義第三張表時,使用字段用于指定關(guān)系表中那些字段做多對多關(guān)系表
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? from django.db import models
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? class Person(models.Model):
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? name = models.CharField(max_length=50)
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? class Group(models.Model):
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? name = models.CharField(max_length=128)
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? members = models.ManyToManyField(
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Person,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? through='Membership',
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? through_fields=('group', 'person'),
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? )
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? class Membership(models.Model):
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? group = models.ForeignKey(Group, on_delete=models.CASCADE)
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? person = models.ForeignKey(Person, on_delete=models.CASCADE)
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? inviter = models.ForeignKey(
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Person,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? on_delete=models.CASCADE,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? related_name="membership_invites",
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? )
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? invite_reason = models.CharField(max_length=64)
? ? ? ? db_constraint=True,? ? ? ? # 是否在數(shù)據(jù)庫中創(chuàng)建外鍵約束
? ? ? ? db_table=None,? ? ? ? ? ? ? # 默認(rèn)創(chuàng)建第三張表時,數(shù)據(jù)庫中表的名稱
八、數(shù)據(jù)庫基本操作
?#創(chuàng)建一個書的類,繼承models類
class Book(models.Model):
? ? #用models類創(chuàng)建書的名字,類型為字符串,CharField相當(dāng)于mysql語句中的varchar,字段最長為32
? ? title = models.CharField(max_length=32)
? ? #創(chuàng)建書的價格,類型為浮點型,小數(shù)點前最長4位,小數(shù)點后最長2位
? ? price = models.DecimalField(max_digits=6, decimal_places=2)
? ? #創(chuàng)建書的出版社信息,其與出版社的外鍵關(guān)系為一對多,所以用外鍵
? ? publish = models.ForeignKey(Publish)
? ? #創(chuàng)建書的出版日期,類型為日期
? ? publication_date = models.DateField()
? ? #創(chuàng)建書的類型信息,為字符串類型,最長為20
? ? classification=models.CharField(max_length=20)
? ? #創(chuàng)建書的作者信息,書籍與作者的關(guān)系為多對多,所以使用many-to-many
? ? authors = models.ManyToManyField("Author")
?
1、增
1.1一對一信息的創(chuàng)建
a、使用create方式
方式一: Publish.objects.create("name"="人民出版社",city="北京"}
方式二: Publish.objects.create(**{"name":"文藝出版社","city":"上海"}}
b、使用save方式
方式一:
book1=Book(title="python",price="88",publish_id="1",publication_date="2017-06-18")
book1.save()
方式二:
author1=Author(name="jerry")
author1.save()
1.2一對多的信息的創(chuàng)建(Foreignkey)
方式一:
#獲取出版社對象
publish_obj=Publish.objects.get(id=4)?
#將出版社的對象綁定到書籍的記錄中
Book.objects.create(
? ? title="python",
? ? price=48.00,
? ? publication_date="2017-07-12",
? ? publish=publish_obj,
)?
方式二:
#直接把出版社的id號插入到書籍的記錄中
Book.objects.create(
? ? title="python",
? ? price=48.00,
? ? publish_id=2,
? ? publication_date="2017-06-18",
)
1.3多對多信息的創(chuàng)建(ManyToManyField())
a、為一本書添加多個作者
author1=Author.objects.get(id=1)#獲取id號為1的作者對象
author2=Author.objects.filter(name="tom")#獲取名字為"tom"的作者對象
book1=Book.objects.get(id=2)#獲取id號為2的書籍對象
book1.authors.add(author1,author2)#為書籍對象添加多個作者對象
也可以用這種方式:
book1.authors.add(*[author1,author2])#為書籍對象添加作者對象的列表
book1.authors.remove(*[author1,author2])#刪除指定書籍的所有作者
b、為一個作者添加多本書
author_obj = Author.objects.filter(name="jerry")#獲取名字為"jerry"的作者對象
book_obj=Book.objects.filter(id__gt=3)#獲取id大于3的書籍對象集合
author_obj.book_set.add(*book_obj)#為作者對象添加書籍對象集合
author_obj.book_set.remove(*book_obj)#刪除指定作者對象所有的書籍
使用models.ManyToManyField()會自動創(chuàng)建第三張表
1.4手動創(chuàng)建多對多的作者與書籍信息表
class Book2Author(models.Models):
? ? author=models.ForeignKey("Author")#為作者指定Author這張表做為外鍵
? ? book=models.ForeignKey("Book")#為書籍指定Book這張表做為外鍵
author_obj=models.Author.objects.filter(id=3)[0]#獲取Author表中id為3的作者對象
book_obj=models.Book.objects.filter(id=4)[0]#獲取Book表中id為4的書籍對象
方式一:
obj1=Book2Author.objects.create(author=author_obj,book=book_obj)
obj1.save()
方式二:
obj2=Book2Author(author=author_obj,book=book_obj)
obj2.save()
2、刪
Book.objects.filter(id=1).delete()
3、改
3.1使用save方法將所有屬性重新設(shè)定一遍,效率低
author1=Author.objects.get(id=3)#獲取id為3的作者對象
author1.name="jobs"#修改作者對象的名字
author1.save()#把更改寫入數(shù)據(jù)庫
3.2使用update方法直接設(shè)置對就的屬性
Publish.objects.filter(id=2).update(name="北京出版社")
注意:update()是QuerySet對象的一個方法,get返回的是一個model對象,其沒有update方法.
filter返回的是一個QuerySet對象,filter里可以設(shè)定多個過濾條件
4、查
查詢數(shù)據(jù)使用QuerySet API。 QuerySet是惰性執(zhí)行的,創(chuàng)建Query Set不會訪問數(shù)據(jù)庫,只有在訪問具體查詢結(jié)果的時候才會訪問數(shù)據(jù)庫。
4.1查詢方法:
filter(**kwargs)? ? ? ? ? ? 包含了與所給篩選條件相匹配的對象
all()? ? ? ? ? ? ? ? ? ? ? 查詢所有結(jié)果
get(**kwargs)? ? ? ? ? ? ? 返回與所給篩選條件相匹配的對象,返回結(jié)果有且只有一個,如果符合篩選條件的對象超過一個或者沒有都是報錯
values(*field)? ? ? ? ? ? ? 返回一個ValueQuerySet,運行后得到的并不是一系列model的實例化對象,而是一個可迭代的字典序列
exclude(**kwargs)? ? ? ? ? 包含了與所給的篩選條件不匹配的對象
order by(*field)? ? ? ? ? ? 對查詢結(jié)果排序
reverse()? ? ? ? ? ? ? ? ? 對查詢結(jié)果反向排序
distinct()? ? ? ? ? ? ? ? ? 從返回結(jié)果中剔除重復(fù)記錄
values_list(*field)? ? ? ? 與values()非常相似,返回一個元組序列,values返回一個字典序列
count()? ? ? ? ? ? ? ? ? ? 返回數(shù)據(jù)庫中匹配的記錄的數(shù)量
first()? ? ? ? ? ? ? ? ? ? 返回數(shù)據(jù)庫中匹配的對象的第一個對象
last()? ? ? ? ? ? ? ? ? ? ? 返回數(shù)據(jù)庫中匹配的對象的最后一個對象
exists()? ? ? ? ? ? ? ? ? ? 判斷一個對象集合中是否包含指定對象,包含返回True,不包含返回False
exclude()? ? ? ? ? ? 排除滿足條件的對象
annotate()? ? ? ? ? ? 使用聚合函數(shù)
dates()? ? ? ? ? ? ? ? 根據(jù)日期獲取查詢集
datetimes()? ? ? ? ? ? 根據(jù)時間獲取查詢集
none()? ? ? ? ? ? ? ? 創(chuàng)建空的查詢集
union()? ? ? ? ? ? ? ? 并集
intersection()? ? ? ? 交集
difference()? ? ? ? 差集
select_related()? ? 附帶查詢關(guān)聯(lián)對象
prefetch_related()? ? 預(yù)先查詢
extra()? ? ? ? ? ? ? ? 附加SQL查詢
defer()? ? ? ? ? ? ? ? 不加載指定字段
only()? ? ? ? ? ? ? ? 只加載指定的字段
using()? ? ? ? ? ? ? ? 選擇數(shù)據(jù)庫
select_for_update()? ? 鎖住選擇的對象,直到事務(wù)結(jié)束。
raw()? ? ? ? ? ? ? ? 接收一個原始的SQL查詢
1.filter():
??? filter(**kwargs)
??? 返回滿足查詢參數(shù)的對象集合。
??? 查找的參數(shù)(**kwargs)應(yīng)該滿足下文字段查找中的格式。多個參數(shù)之間是和AND的關(guān)系。
??? Student.objects.filter(age__lt=10)#查詢滿足年齡小于10歲的所有學(xué)生對象
2.exclude():
??? exclude(**kwargs)
??? 返回一個新的QuerySet,它包含不滿足給定的查找參數(shù)的對象
??? Student.objects.exclude(age__gt=20, name='lin')#排除所有年齡大于20歲且名字為“l(fā)in”的學(xué)員集
3.annotate():
??? nnotate(args, *kwargs)
??? 使用提供的聚合表達(dá)式查詢對象。
??? 表達(dá)式可以是簡單的值、對模型(或任何關(guān)聯(lián)模型)上的字段的引用或者聚合表達(dá)式(平均值、總和等)。
??? annotate()的每個參數(shù)都是一個annotation,它將添加到返回的QuerySet每個對象中。
??? 關(guān)鍵字參數(shù)指定的Annotation將使用關(guān)鍵字作為Annotation 的別名。 匿名參數(shù)的別名將基于聚合函數(shù)的名稱和模型的字段生成。 只有引用單個字段的聚合表達(dá)式才可以使用匿名參數(shù)。 其它所有形式都必須用關(guān)鍵字參數(shù)。
??? 例如,如果正在操作一個Blog列表,你可能想知道每個Blog有多少Entry:
??? >>> from django.db.models import Count
??? >>> q = Blog.objects.annotate(Count('entry'))
??? # The name of the first blog
??? >>> q[0].name
??? 'Blogasaurus'
??? # The number of entries on the first blog
??? >>> q[0].entry__count
??? 42
4.order_by():
??? order_by(*fields)
??? 默認(rèn)情況下,根據(jù)模型的Meta類中的ordering屬性對QuerySet中的對象進(jìn)行排序
??? Student.objects.filter(school="陽關(guān)小學(xué)").order_by('-age', 'name')
??? 上面的結(jié)果將按照age降序排序,然后再按照name升序排序。"-age"前面的負(fù)號表示降序順序。 升序是默認(rèn)的。 要隨機(jī)排序,使用"?",如下所示:
??? Student.objects.order_by('?')
5. reverse():
??? reverse()????
??? 反向排序QuerySet中返回的元素。 第二次調(diào)用reverse()將恢復(fù)到原有的排序。????
??? 如要獲取QuerySet中最后五個元素,可以這樣做:???
??? my_queryset.reverse()[:5]???
??? 這與Python直接使用負(fù)索引有點不一樣。 Django不支持負(fù)索引。
6.distinct():
??? distinct(*fields)
??? 去除查詢結(jié)果中重復(fù)的行。?
??? 默認(rèn)情況下,QuerySet不會去除重復(fù)的行。當(dāng)查詢跨越多張表的數(shù)據(jù)時,QuerySet可能得到重復(fù)的結(jié)果,這時候可以使用distinct()進(jìn)行去重。
7. values():
??? values(fields, *expressions)????
??? 返回一個包含數(shù)據(jù)的字典的queryset,而不是模型實例。????
??? 每個字典表示一個對象,鍵對應(yīng)于模型對象的屬性名稱。如:????
??? # 列表中包含的是Student對象
??? >>> Student.objects.filter(name__startswith='Lin')
??? <QuerySet [<Student: Lin Student>]>????
??? # 列表中包含的是數(shù)據(jù)字典
??? >>> Student.objects.filter(name__startswith='Lin').values()
??? <QuerySet [{'id': 1, 'name': 'Linxiao', 'age': 20}]>????
??? 另外該方法接收可選的位置參數(shù)*fields,它指定values()應(yīng)該限制哪些字段。如果指定字段,每個字典將只包含指定的字段的鍵/值。如果沒有指定字段,每個字典將包含數(shù)據(jù)庫表中所有字段的鍵和值。如下:
??? >>> Student.objects.filter(name__startswith='Lin').values()
??? <QuerySet [{'id': 1, 'name': 'Linxiao', 'age': 20}]>
??? >>> Blog.objects.values('id', 'name')
??? <QuerySet [{'id': 1, 'name': 'Linxiao'}]>
8.values_list():
??? values_list(*fields, flat=False)?? ?
??? 與values()類似,只是在迭代時返回的是元組而不是字典。每個元組包含傳遞給values_list()調(diào)用的相應(yīng)字段或表達(dá)式的值,因此第一個項目是第一個字段等。 像這樣:
??? >>> Student.objects.values_list('id', 'name')
獲取數(shù)據(jù)表的全部數(shù)據(jù)記錄:
Account.objects.all()
返回值可以進(jìn)行切片,但不支持負(fù)索引?;蛘呤褂茫?/p>
Account.objects.get(field_name=val)
示例:
Account.objects.get(account_name='john')
或者使用過濾器查詢多條記錄:
??? Account.objects.filter(accounnt_name=val)
??? 嚴(yán)格等于
??? Account.objects.filter(account_name__iexact=val)
??? 忽略大小寫
??? Account.objects.filter(account_name__contains=val)
??? 名稱中包含val
??? Account.objects.filter(account_name__icontains=val)
??? 忽略大小寫,包含
??? Account.objects.filter(account_name__regex=val)
??? 正則表達(dá)式
??? Account.objects.filter(account_name__iregex=val)
??? 正則表達(dá)式,忽略大小寫
與filter相反exclude用于返回不滿足條件的查詢結(jié)果。
Account.objects.exclude(account_name__contains=val)
filter與exclude可以進(jìn)行鏈?zhǔn)讲樵?/p>
Account.objects.exclude(account_name__contains='john').exlucde(balance=0)
對于查詢結(jié)果可以使用distinct()去重或者使用order_by(field)進(jìn)行排序。
Account.objects.filter(account_name__regex=val).distinct()
Account.objects.filter(account_name__regex=val).oreder_by('balance')
使用reverse()方法可以反轉(zhuǎn)結(jié)果集中的元素順序,調(diào)用兩次將會恢復(fù)原順序。
從SQL 的角度,QuerySet和SELECT 語句等價,過濾器是像WHERE 和LIMIT 一樣的限制子句。
like:
? ? __exact? ? ? ? 精確等于? ? ? like 'aaa'
? ? __iexact? ? ? 精確等于? ? ? 忽略大小寫 ilike 'aaa'
? ? __contains? ? 包含? ? ? ? ? like '%aaa%'
? ? __icontains? ? 包含,忽略大小寫 ilike '%aaa%',但是對于sqlite來說,contains的作用效果等同于icontains。
in:
? ? __in
? ? 查詢在某一范圍的書
? ? Book.objects.filter(publish__in=[10, 20, 30])
is null / is not null:
? ? __isnull? 判空
? ? Book.objects.filter(name__isnull=True)? ? // 查詢用戶名為空的書
? ? Publish.objects.filter(name__isnull=False)? // 查詢用戶名不為空的書
不等于/不包含于:
? ? Book.objects.filter().excute(publishe=10)? ? // 查詢出版社不為10的書
? ? Book.objects.filter().excute(publish__in=[10, 20])? // 查詢出版社不在 [10, 20] 的書
其他常用模糊查詢:
? ? __startswith 以…開頭
? ? __istartswith 以…開頭 忽略大小寫
? ? __endswith 以…結(jié)尾
? ? __iendswith 以…結(jié)尾,忽略大小寫
? ? __range 在…范圍內(nèi)
? ? __year 日期字段的年份
? ? __month 日期字段的月份
? ? __day 日期字段的日
4.2雙下劃線(__)查詢
a、雙下劃線(__)之單表條件查詢
例子:
table1.objects.filter(id__lt=10,id__gt=1)#獲取id小于10,且大于1的記錄
table1.objects.filter(id__in=[11,22,33,44])#獲取id在[11,22,33,44]中的記錄
table1.objects.exclude(id__in=[11,22,33,44])#獲取id不在[11,22,33,44]中的記錄
table1.objects.filter(name__contains="content1")#獲取name中包含有"contents"的記錄(區(qū)分大小寫)
table1.objects.filter(name__icontains="content1")#獲取name中包含有"content1"的記錄(不區(qū)分大小寫)
table1.objects.filter(id__range=[1,4])#獲取id在1到4(不包含4)之間的的記錄
b、雙下劃線(__)之多表條件查詢
正向查找(條件)之一對一查詢
#查詢書名為"python"的書的id號
res3=Book.objects.filter(title="python").values("id")
print(res3)
正向查找(條件)之一對多查詢
#查詢書名為"python"的書對應(yīng)的出版社的地址
res4=Book.objects.filter(title="python").values("publisher__city")
print(res4)
#查詢"aaa"作者所寫的所有的書的名字
res5=Book.objects.filter(author__name="aaa").values("title")
print(res5)
#查詢"aaa"作者所寫的所有的書的名字(與上面的用法沒區(qū)別)
res6=Book.objects.filter(author__name="aaa").values("title")
print(res6)
反向查找之一對多查詢
#查詢出版了書名為"python"這本書的出版社的名字
res7=Publisher.objects.filter(book__title="python").values("name")
print(res7)
#查詢寫了書名為"python"的作者的名字
res8=Publisher.objects.filter(book__title="python").values("book__authors")
print(res8)
反向查找之多對多查詢
#查詢所寫的書名為"python"的作者的名字
res9=Author.objects.filter(bool__title="python").values("name")
print(res9)
條件查詢即與對象查詢對應(yīng),是指filter,values等方法中的通過__來明確查詢條件
4.3F查詢和Q查詢
F查詢專門取對象中某列值的操作,F(xiàn)的作用:用來批量修改數(shù)據(jù)的
#導(dǎo)入F
from django.db.models import F
#把table1表中的num列中的每一個值在的基礎(chǔ)上加10
table1.objects.all().update(num=F("num")+10)
Q構(gòu)建搜索條件,?Q的作用:Q是用來做條件查詢的
#導(dǎo)入Q
from django.db.models import Q
Q對象可以對關(guān)鍵字參數(shù)進(jìn)行封裝,從而更好的應(yīng)用多個查詢
#查詢table2表中以"aaa"開頭的所有的title列
q1=table2.objects.filter(Q(title__startswith="aaa")).all()
print(q1)
Q對象可以組合使用&,|操作符,當(dāng)一個操作符是用于兩個Q對象時,會產(chǎn)生一個新的Q對象
#查找以"aaa"開頭,或者以"bbb"結(jié)尾的所有title
Q(title__startswith="aaa") | Q(title__endswith="bbb")
Q對象可以用"~"操作符放在表達(dá)式前面表示否定,也可允許否定與不否定形式的組合
#查找以"aaa"開頭,且不以"bbb"結(jié)尾的所有title
Q(title__startswith="aaa") & ~Q(title__endswith="bbb")
Q對象可以與關(guān)鍵字參數(shù)查詢一起使用,Q對象放在關(guān)鍵字查詢參數(shù)的前面
查詢條件:
#查找以"aaa"開頭,以"bbb"結(jié)尾的title且書的id號大于4的記錄
Q(title__startswith="aaa") | Q(title__endswith="bbb"),book_id__gt=4
九、實例
1、Django的ORM中如何判斷查詢結(jié)果是否為空,判斷django中的orm為空
result= Booking.objects.filter()
方法一 .exists()
if result.exists():
? ? print "QuerySet has Data"
else:
? ? print "QuerySet is empty"
方法二 .count()==0
if result.count() == 0:
? ? print "empty"
方法三
if result:
? ? print "QuerySet has Data"
else:
? ? print "QuerySet is empty"
總結(jié):
QuerySet.exists() > QuerySet.count()==0 > QuerySet
2、模板中顯示數(shù)據(jù)庫內(nèi)容的方法
?a、創(chuàng)建數(shù)據(jù)庫
from django.db import models
from django.db import models
class Business(models.Model):
? ? caption = models.CharField(max_length=32)
? ? code = models.CharField(max_length=32)
class Host(models.Model):
? ? nid = models.AutoField(primary_key=True)
? ? hostname = models.CharField(max_length=32,db_index=True)
? ? ip = models.GenericIPAddressField(protocol='both',db_index=True)
? ? port = models.IntegerField()
? ? business = models.ForeignKey(to='Business',to_field='id',on_delete=models.CASCADE)
business.html
<!DOCTYPE html>
<html lang="en">
<head>
? ? <meta charset="UTF-8">
? ? <title>Title</title>
</head>
<body>
? ? <h1>業(yè)務(wù)線列表(對象)</h1>
? ? <ul>
? ? ? ? {% for row in v1 %}
? ? ? ? ? ? <li>{{ row.id }}-{{ row.caption }}-{{ row.code }}</li>
? ? ? ? {% endfor %}
? ? </ul>
? ? <h1>業(yè)務(wù)線列表(字典)</h1>
? ? <ul>
? ? ? ? {% for row2 in v2 %}
? ? ? ? ? ? <li>{{ row2.id }}-{{ row2.caption }}</li>
? ? ? ? {% endfor %}
? ? </ul>
</body>
</html>
host.html
<!DOCTYPE html>
<html lang="en">
<head>
? ? <meta charset="UTF-8">
? ? <title>Title</title>
</head>
<body>
? ? <h1>主機(jī)列表(對象)</h1>
? ? <table border="1">
? ? ? ? <tread>
? ? ? ? ? ? <tr>
? ? ? ? ? ? ? ? <th>主機(jī)ID</th>
? ? ? ? ? ? ? ? <th>IP</th>
? ? ? ? ? ? ? ? <th>端口</th>
? ? ? ? ? ? ? ? <th>業(yè)務(wù)線名稱</th>
? ? ? ? ? ? </tr>
? ? ? ? </tread>
? ? ? ? <tbody>
? ? ? ? ? ? {% for row in v1 %}
? ? ? ? ? ? ? ? <tr>
? ? ? ? ? ? ? ? ? ? <td>{{ row.hostname }}</td>
? ? ? ? ? ? ? ? ? ? <td>{{ row.ip }}</td>
? ? ? ? ? ? ? ? ? ? <td>{{ row.port }}</td>
? ? ? ? ? ? ? ? ? ? <td>{{ row.business.caption }}</td>
? ? ? ? ? ? ? ? </tr>
? ? ? ? ? ? {% endfor %}
? ? ? ? </tbody>
? ? </table>
? ? <h1>主機(jī)列表(字典)</h1>
? ? <table border="1">
? ? ? ? <tread>
? ? ? ? ? ? <tr>
? ? ? ? ? ? ? ? <th>主機(jī)ID</th>
? ? ? ? ? ? ? ? <th>主機(jī)名</th>
? ? ? ? ? ? ? ? <th>業(yè)務(wù)線ID</th>
? ? ? ? ? ? ? ? <th>業(yè)務(wù)線名稱</th>
? ? ? ? ? ? </tr>
? ? ? ? </tread>
? ? ? ? <tbody>
? ? ? ? ? ? {% for row in v2 %}
? ? ? ? ? ? ? ? <tr>
? ? ? ? ? ? ? ? ? ? <td>{{ row.nid }}</td>
? ? ? ? ? ? ? ? ? ? <td>{{ row.hostname }}</td>
? ? ? ? ? ? ? ? ? ? <td>{{ row.business__id }}</td>
? ? ? ? ? ? ? ? ? ? <td>{{ row.business__caption }}</td>
? ? ? ? ? ? ? ? </tr>
? ? ? ? ? ? {% endfor %}
? ? ? ? </tbody>
? ? </table>
? ? <h1>主機(jī)列表(元祖)</h1>
? ? <table border="1">
? ? ? ? <tread>
? ? ? ? ? ? <tr>
? ? ? ? ? ? ? ? <th>主機(jī)ID</th>
? ? ? ? ? ? ? ? <th>主機(jī)名</th>
? ? ? ? ? ? ? ? <th>業(yè)務(wù)線ID</th>
? ? ? ? ? ? ? ? <th>業(yè)務(wù)線名稱</th>
? ? ? ? ? ? </tr>
? ? ? ? </tread>
? ? ? ? <tbody>
? ? ? ? ? ? {% for row in v3 %}
? ? ? ? ? ? ? ? <tr>
? ? ? ? ? ? ? ? ? ? <td>{{ row.0 }}</td>
? ? ? ? ? ? ? ? ? ? <td>{{ row.1 }}</td>
? ? ? ? ? ? ? ? ? ? <td>{{ row.2 }}</td>
? ? ? ? ? ? ? ? ? ? <td>{{ row.3 }}</td>
? ? ? ? ? ? ? ? </tr>
? ? ? ? ? ? {% endfor %}
? ? ? ? </tbody>
? ? </table>
</body>
</html>
views.py
from django.shortcuts import render,HttpResponse
from app01 import models
def business(request):
? ? # 第一種方式(是個對象)
? ? v1 = models.Business.objects.all()
? ? # 第二種方式,只取id和caption(是個字典)
? ? v2 = models.Business.objects.all().values('id','caption')
? ? return render(request,'business.html',{'v1':v1,'v2':v2})
def host(request):
? ? #總共三種方式,對象,字典,列表
? ? v1 = models.Host.objects.all()
? ? v2 = models.Host.objects.filter(nid__gt=0).values('nid','hostname','business__id','business__caption')
? ? v3 = models.Host.objects.filter(nid__gt=0).values_list('nid','hostname','business__id','business__caption')
? ? return render(request,'host.html',{'v1':v1,'v2':v2,'v3':v3})