一文讀懂|Django之Model操作數(shù)據(jù)庫詳解


一、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})

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容