Django中不溜教程(6)模型層(3)之增刪改查curd

@TOC

前言

關(guān)于模型層的介紹我們已經(jīng)涉及了Model類(lèi)創(chuàng)建的常用細(xì)節(jié)和多表關(guān)系,當(dāng)前章節(jié)我們著重學(xué)習(xí)Django中對(duì)模型類(lèi)的API的操作,也就是增傷改查,尤其是查詢(xún)是我們的重點(diǎn)。
再講具體操作之前我們需要再次重復(fù),Django提供ORM的形式操作數(shù)據(jù)庫(kù),主要表現(xiàn)在兩個(gè)方面:
1Django會(huì)根據(jù)我們定義的Model類(lèi)自動(dòng)在數(shù)據(jù)庫(kù)中創(chuàng)建表結(jié)構(gòu)。
2Django自動(dòng)提供給我們一套數(shù)據(jù)庫(kù) API,允許你創(chuàng)建,檢索,更新和刪除對(duì)象。
這些API就是我們本章節(jié)的重點(diǎn)。

案例需求描述

我們現(xiàn)有學(xué)生,老師,班級(jí)三種數(shù)據(jù)。
他們之間關(guān)系:
1學(xué)生和班級(jí):多對(duì)一關(guān)系,一個(gè)班級(jí)多個(gè)學(xué)生,一個(gè)學(xué)生屬于某一個(gè)班級(jí)。
2學(xué)生和老師:多對(duì)多,一個(gè)學(xué)生有不同課程的老師,一個(gè)老師給多個(gè)學(xué)生授課。
以下他們的Model類(lèi)代碼:

from django.db import models
# 班級(jí)
class Classmy(models.Model):
    name = models.CharField(max_length=20)
    num = models.IntegerField()

# 老師
class Teacher(models.Model):
    name = models.CharField(max_length=20)
    course = models.CharField("課程", max_length=10)
    age = models.IntegerField()

# 學(xué)生
class Student(models.Model):
    name = models.CharField(max_length=20)
    age = models.IntegerField()
    #學(xué)生和班級(jí)多一對(duì)關(guān)系
    classmy =models.ForeignKey(Classmy,on_delete=models.CASCADE)
    # 學(xué)生和老師是多對(duì)多關(guān)系
    teachers = models.ManyToManyField(Teacher)

生成與執(zhí)行遷移文件之后我們開(kāi)始接下來(lái)的代碼測(cè)試。

Create新增記錄

Django中一個(gè)模型類(lèi)代表一張數(shù)據(jù)表,一個(gè)模型類(lèi)的實(shí)例代表數(shù)據(jù)庫(kù)表中的一行記錄,
新增記錄有兩種方式,一是save()函數(shù),二是create()函數(shù)。

save()

創(chuàng)建一個(gè)對(duì)象,然后調(diào)用它的save()函數(shù),遍可將其存入數(shù)據(jù)庫(kù)。

python manage.py shell
>>>from CURD.models import Classmy,Teacher,Student
>>>c = Classmy(name='三年二班',num=50)
>>>c.save() #創(chuàng)建并保存記錄,Django執(zhí)行了insert語(yǔ)句,save()函數(shù)沒(méi)有返回值
>>>t=Teacher(name='pfdu',course='python',age='18')
>>>t.save() #保存教師記錄
>>>s=Student(name='張三',age='15',classmy=c) #創(chuàng)建Student對(duì)象,指定classmy
>>>s.save() #保存到數(shù)據(jù)庫(kù)
>>>s.teachers.add(t)#綁定教師和學(xué)生之間的關(guān)系

create()

create創(chuàng)建對(duì)象相比save()函數(shù)使用起來(lái)更便捷,一個(gè)步驟到位,最終效果都一樣。

#   模型.objects 獲取到一個(gè)Manager對(duì)象
c2 = Classmy.objects.create(name='三年二班',num=50)

我們這里著重解釋一下objects,objects是Django幫我們自動(dòng)生成的管理器對(duì)象,通過(guò)這個(gè)管理器提供了對(duì)對(duì)數(shù)據(jù)的操作的API函數(shù),比如create創(chuàng)建新的記錄, objects類(lèi)型是models.Manager。

bulk_create()批量插入

如果想要一次性插入100條數(shù)據(jù)到數(shù)據(jù)庫(kù),使用循環(huán)在代碼上看起來(lái)沒(méi)有什么問(wèn)題,但是這是一種十分消耗內(nèi)能的方式因?yàn)槊看尾迦霐?shù)據(jù)的動(dòng)作都會(huì)開(kāi)啟一個(gè)和數(shù)據(jù)庫(kù)的連接,所以禁止使用循環(huán)的方式,Django提供了bulk_create()函數(shù)解決批量插入問(wèn)題。

#舉例
#tlist是一個(gè)集合,每一個(gè)item都是一個(gè)Teacher對(duì)象。bulk_create函數(shù)執(zhí)行一條SQL存入多條數(shù)據(jù)
>>>Teacher.objects.bulk_create(tlist)

Select查詢(xún)記錄

查詢(xún)是相對(duì)比較復(fù)雜,同樣在開(kāi)發(fā)過(guò)程中最常用的,我們從簡(jiǎn)單的一步步深入。

查詢(xún)所有數(shù)據(jù)

語(yǔ)法:

all_entries = Entry.objects.all()

簡(jiǎn)單的例子:

>>>#獲取到的一個(gè)QuerySet
>>> stus = Student.objects.all()
>>># QuerySet并不方便進(jìn)行查詢(xún)數(shù)據(jù)的細(xì)節(jié),我們可以通過(guò)values將QuerySet中的數(shù)據(jù)字典列表的方式進(jìn)行輸出
>>>stus.values()

返回的是一個(gè)QuerySet 對(duì)象,QuerySet包含數(shù)據(jù)庫(kù)中模型對(duì)應(yīng)的表的所有記錄,稍后我們會(huì)介紹它的特性細(xì)節(jié)。

values()和 values_list()

values()和 values_list()的區(qū)別,這是一道常見(jiàn)的Django面試題,values_list與values是作用是一樣的,只是返回?cái)?shù)據(jù)的格式不同,values返回的是字典列表,values_list返回元祖列表.元祖是由指定的字段查詢(xún)到的值組成的。

values結(jié)構(gòu):

>>><QuerySet [{'id': 1, 'name': 'qqq', 'age': 15, 'classmy_id': 1}, {'id': 2, 'name': 'aaa', 'age': 30, 'classm
y_id': 2}, {'id': 3, 'name': 'cccc', 'age': 25, 'classmy_id': 1}]>

values_list結(jié)構(gòu):

<QuerySet [(1, 'qqq', 15, 1), (2, 'aaa', 30, 2), (3, 'cccc', 25, 1)]>

當(dāng)然values()和values_list()不僅僅只有這些功能,在后續(xù)的聚合函數(shù)的使用中我們會(huì)在將來(lái)的章節(jié)繼續(xù)深入學(xué)習(xí)。

條件查詢(xún)

有時(shí)候我們需要對(duì)數(shù)據(jù)庫(kù)中的記錄進(jìn)行條件篩選獲取其中的部分內(nèi)容。實(shí)現(xiàn)方式我們需要用用到QuerySet 對(duì)象,QuerySet除了保存記錄以外還允許在添加過(guò)濾條件對(duì)原始QuerySet進(jìn)行篩選,主要提供了兩個(gè)函數(shù)進(jìn)行過(guò)濾。
filter(kwargs):獲取一個(gè)新的 QuerySet,包含的對(duì)象滿(mǎn)足給定查詢(xún)參數(shù)
exclude(
kwargs):獲取一個(gè)新的 QuerySet,包含的對(duì)象 不 滿(mǎn)足給定查詢(xún)參數(shù)。
(**kwargs)就是查詢(xún)參數(shù)。
我們先演示一個(gè)簡(jiǎn)單的案例,代碼Django代碼如下

>>> ts=Teacher.objects.filter(name='pfdu')   #查詢(xún)名字叫pfdu的Teacher

最終Django會(huì)自動(dòng)執(zhí)行對(duì)應(yīng)的sql語(yǔ)句,轉(zhuǎn)化的sql語(yǔ)句為:

SELECT * FROM CURD_teacher WHERE name='pfdu';

filter函數(shù)和exclude函數(shù)在調(diào)用后返回的仍然是一個(gè)QuerySet對(duì)象,所以我們可以在此基礎(chǔ)上繼續(xù)篩選,繼續(xù)調(diào)用下一組filter或者exclude,這種方式我們叫做鏈?zhǔn)竭^(guò)濾器。

>>>ts2=Teacher.objects.filter(name='pfdu').exclude(age=18)#獲取名字叫做pfdu,并且年齡不等于18的老師的集合

filter函數(shù)中可傳入多個(gè)條件參數(shù):

#一個(gè)filter函數(shù)的多個(gè)條件參數(shù)之間的關(guān)系是and,所以以下語(yǔ)句的含義是查詢(xún)id<=2并且age<20的老師
>>>ts=Teacher.objects.filter(id__lte='2',age__lte='20') 

兩個(gè)filter()鏈?zhǔn)秸{(diào)用的效果:

#以下語(yǔ)句的含義是查詢(xún)id<=2或者age<20的老師,同樣也是and的關(guān)系
>>>ts=Teacher.objects.filter(id__lte='2') .filter(age__lte='20')

過(guò)濾條件語(yǔ)法

過(guò)濾條件指的是比如年齡大于18的,id大于等于10的,名字像du的等等,在sql語(yǔ)句中我們有不同的關(guān)系運(yùn)算符,比如 =,>=,<=,like,in,between等,這些符號(hào)在django中不能直接使用,我們需要使用查詢(xún)關(guān)鍵字來(lái)實(shí)現(xiàn)不同的關(guān)系運(yùn)算。
舉例:


>>> Teacher.objects.filter(age__lte=30)#查詢(xún)年齡小于等于30的記錄
>>>> Teacher.objects.filter(age__in=[30,34,50])#年齡是30,或34,或50歲的人
>>>> Teacher.objects.filter(age__rang=(20,30)) #查詢(xún)年齡在20到30之間的

過(guò)濾條件的語(yǔ)法規(guī)則:field__lookuptype=value,field是字段名,中間兩個(gè)下劃線(xiàn),后面跟不同的條件關(guān)鍵字。

常用條件關(guān)鍵字一覽:

關(guān)鍵字 解釋
__exact =
__iexact 忽略大小寫(xiě)=
__contains 包含 like '%aaa%'
__icontains 忽略大小寫(xiě) ilike '%aaa%'
__gt 大于
__gte 大于等于
__lt 小于
__lte 小于等于
__in 存在于一個(gè)list范圍內(nèi)
__startswith 以...開(kāi)頭
__endswith 以...結(jié)尾
__range 在范圍之內(nèi)

QuerySet特性

我們需要對(duì)QuerySet有根深一步的講解,目前已知是它表示的是一個(gè)查詢(xún)結(jié)果集合,并且可以鏈?zhǔn)降睦^續(xù)篩選。除此之外我們還需要知道它的其他特性:
1在鏈?zhǔn)竭^(guò)濾器中,每一次篩選返回的是獨(dú)立唯一的QuerySet對(duì)象。
2 QuerySet是惰性的,只有當(dāng)真正使用時(shí),如遍歷的時(shí)候,才會(huì)真正去數(shù)據(jù)庫(kù)進(jìn)行查詢(xún),也就說(shuō)調(diào)用all(),filter(),exclude()函數(shù)的時(shí)候并不會(huì)執(zhí)行sql查詢(xún),只有在使用集合中的數(shù)據(jù)的時(shí)候才去操作數(shù)據(jù)庫(kù)。
3QuerySet帶有緩存,多次調(diào)用同一個(gè)查詢(xún)結(jié)果對(duì)象,不再進(jìn)行數(shù)據(jù)庫(kù)查詢(xún),而是使用緩存結(jié)果

select_related與prefetch_related

描述一個(gè)場(chǎng)景:在帶有表關(guān)系的情況下,比如要查詢(xún)所有的Student數(shù)據(jù),使用剛才學(xué)習(xí)的方式很簡(jiǎn)單就是能實(shí)現(xiàn):

ts=Teacher.objects.all() #查詢(xún)所有的教師

這里請(qǐng)思考一個(gè)問(wèn)題,:在Django中我們查詢(xún)所有的教師信息的同時(shí)是否將所屬的學(xué)生信息一并進(jìn)行了獲取?
答案是沒(méi)有的,因?yàn)槲覀儚腄jango的特性中知道QuerySet的設(shè)計(jì)是惰性的,不僅僅針對(duì)單個(gè)對(duì)象,在表關(guān)系中惰性也是存在的,也就是說(shuō)默認(rèn)情況下,只有我們主動(dòng)的使用教師的學(xué)生信息的時(shí)候Django才會(huì)再次去查詢(xún)學(xué)生表。

但如果我們的需求就是同時(shí)需要獲取到教師和學(xué)生的信息呢?惰性查詢(xún)無(wú)疑會(huì)增加查詢(xún)的次數(shù),此時(shí)惰性查詢(xún)不再是一種合適的方式了,為了解決表關(guān)聯(lián)查詢(xún)時(shí)減少與數(shù)據(jù)庫(kù)的交互次數(shù),Django提供了select_related和prefetch_related。
簡(jiǎn)單解釋他們的功能:對(duì)QuerySet使用select_related()函數(shù)后,Django會(huì)獲取相應(yīng)外鍵對(duì)應(yīng)的對(duì)象,從而在之后需要的時(shí)候不必再查詢(xún)數(shù)據(jù)庫(kù)了。

#一次查詢(xún)。將所有學(xué)生和學(xué)生所屬的教師都查詢(xún)出來(lái),調(diào)用學(xué)生獲取教師信息不會(huì)再查詢(xún)數(shù)據(jù)庫(kù)
>>>stus= Student.objects.select_related().all()

prefetch_related效果和select_related類(lèi)似,不過(guò)使用的場(chǎng)景不同:

1,select_related適用于外鍵和多對(duì)一的關(guān)系查詢(xún);

2,prefetch_related適用于一對(duì)多或者多對(duì)多的查詢(xún)。

獲取單個(gè)數(shù)據(jù)

all(),filter(),exclude得到的結(jié)果總是一個(gè)QuerySet集合,即使開(kāi)發(fā)者已知符合條件的記錄只有一條。此時(shí)我們可以使用Manager的get()函數(shù),它返回的直接是一個(gè)對(duì)象。
使用案例:

>>>#獲取主鍵值等于1的對(duì)象
>>>t2  =Teacher.objects.get(pk=1)

等價(jià)于

>>>#獲取主鍵值等于1的對(duì)象
>>>t2  =Teacher.objects.filter(pk=1)[0]

get(**kwargs)函數(shù)的參數(shù)與filter一樣,可以過(guò)濾條件。需要注意的是使用get()函數(shù)如果沒(méi)有符合條件的記錄或者符合條件的記錄超過(guò)1條會(huì)拋出異常,使用時(shí)注意異常的處理。

數(shù)據(jù)分頁(yè)

mysql中使用limit和offset關(guān)鍵字可以實(shí)現(xiàn)數(shù)據(jù)的分頁(yè)效果,這在數(shù)據(jù)庫(kù)龐大的時(shí)下經(jīng)常會(huì)用到。limit表示結(jié)果集最大條目數(shù),offset是游標(biāo)偏移量。
Django中對(duì)分頁(yè)也進(jìn)行了封裝,可以對(duì)QuerySet的條目數(shù)進(jìn)行限制,采用python切片的語(yǔ)法。

例如,這將返回前 5 個(gè)對(duì)象 (LIMIT 5):

>>> Teacher.objects.all()[:5]

這會(huì)返回第 6 至第 10 個(gè)對(duì)象 (OFFSET 5 LIMIT 5):

>>> Teacher.objects.all()[5:10]

不支持負(fù)索引 (例如 Teacher.objects.all()[-1])。

排序

排序也是查詢(xún)中常用的子句,Django提供了:QuerySet.order_by(args)*來(lái)實(shí)現(xiàn),源關(guān)于排序這不是我們第一次提到,在之前的Django模型層詳解之定義Model章節(jié)中我們?cè)贛eta定義時(shí)有介紹到,ordering選項(xiàng)提供默認(rèn)的排序,開(kāi)發(fā)中需要根據(jù)不同需求按照不同的方式排序,所以當(dāng)前介紹的排序其實(shí)是對(duì)Meta中ordering排序的覆蓋。
使用方式:

>>>#參數(shù)可指定一個(gè)或者多個(gè),“-”表示降序
>>>#查詢(xún)所有學(xué)生,先按照年齡降序排序,再按照id升序排序
>>>Student.objects.all().order_by('-age', 'id')


orm跨關(guān)系查詢(xún)

跨關(guān)系查詢(xún)指的是mysql中的聯(lián)合查詢(xún),在mysql找那個(gè)我們可以使用內(nèi)聯(lián)(inner join),左外聯(lián)(left outer join),右外聯(lián)(right outer join),全聯(lián)(union)等,相信這些是很多初學(xué)者的噩夢(mèng),在Django中提供了ORM方式的更加方便的表關(guān)聯(lián)查詢(xún)方式。

Django中要跨越關(guān)系,只需使用跨模型的相關(guān)字段的字段名稱(chēng),用雙下劃線(xiàn)分隔,直到到達(dá)所需的字段。跨域的深度隨你所想

舉例1:查詢(xún)?nèi)甓嗟膶W(xué)生


>>>stus=Student.objects.filter(classmy__name='三年二班')#classmy是Student類(lèi)中的classmy屬性,雙下劃線(xiàn)"__"表示到達(dá)classmy屬性對(duì)應(yīng)的模型類(lèi),name是classmy的屬性。
>>>stus

當(dāng)調(diào)用stus的時(shí)候回看到打印出來(lái)的sql語(yǔ)句,我們發(fā)現(xiàn)django自動(dòng)為我們執(zhí)行的就是inner join語(yǔ)句。

舉例2:查詢(xún)pfdu所在的班級(jí)

>>> clas=Classmy.objects.filter(student__name='張三')#這是一個(gè)反向查詢(xún),因?yàn)楸黻P(guān)系我們是在Student模型中指定的,django支持反向關(guān)聯(lián)查詢(xún)

Update修改記錄

Django中對(duì)于單個(gè)對(duì)象的update操作對(duì)應(yīng)的API函數(shù)也是save()函數(shù),也就是說(shuō)save()函數(shù)既可以新增記錄,也可以修改已經(jīng)存在的記錄。

修改單個(gè)已存在對(duì)象:

>>># c對(duì)象是我們剛才已經(jīng)添加到數(shù)據(jù)庫(kù)的對(duì)象,我們?cè)谒幕A(chǔ)上進(jìn)行修改,為他的name屬性重新賦值
>>>c.name='二年五班'
>>>c.save() # 再次調(diào)用c對(duì)象的save()函數(shù),此處數(shù)據(jù)庫(kù)執(zhí)行的是update函數(shù)
>>>c.name #取出來(lái)name的值進(jìn)行查看
'二年五班'

代碼上很簡(jiǎn)單,但我們需要知道Django是怎么區(qū)分save()函數(shù)到底是新增操作還是修改操作的?
官方介紹它的算法是這樣的:

  • 如果對(duì)象的主鍵屬性設(shè)置為計(jì)算值 True(即,除None空字符串以外的值),則Django執(zhí)行UPDATE。
  • 如果未設(shè)置對(duì)象的主鍵屬性或未UPDATE 更新任何內(nèi)容(例如,如果主鍵設(shè)置為數(shù)據(jù)庫(kù)中不存在的值),Django將執(zhí)行INSERT。
    一句話(huà)總結(jié):Django是根據(jù)模型對(duì)象的主鍵屬性的值進(jìn)行判斷的,如果對(duì)象主鍵屬性的值在數(shù)據(jù)庫(kù)中已經(jīng)存在則執(zhí)行更新,其他情形則執(zhí)行新建。

批量修改

這里使用QuerySet.update()函數(shù)。

#將所有叫張三的人的年齡修改成30
Student.objects.filter(name='張三').update(age=30)

Delete刪除記錄

在Django中刪除記錄主要依靠delete()函數(shù)。
使用方式很簡(jiǎn)單,分為單個(gè)對(duì)象刪除和批量刪除。

單個(gè)對(duì)象刪除

#獲取主鍵值為1的學(xué)生
s = Student.objects.get(pk=1)
#調(diào)用刪除函數(shù)進(jìn)行刪除
s.delete()

批量刪除,刪除符合條件所有數(shù)據(jù):

#刪除所有的學(xué)生
Student.objects.all().delete()
#刪除所有名字叫張三的學(xué)生
Student.objects.filter(name='張三').delete()

F()和Q()

Q()

Q()的作用是用于復(fù)雜查詢(xún),使用符號(hào)&(and)、|(or)、~(not)將多個(gè)Q()對(duì)象組合起來(lái)傳遞給filter(),exclude(),get()等函數(shù),來(lái)實(shí)現(xiàn)邏輯與,或,非的操作。
案例:

#導(dǎo)入Q模塊
from django.db.models import Q
#每一個(gè)Q函數(shù)包裹一個(gè)條件,有前綴'~'的表示非,使用&,|將他們鏈接,然后作為一個(gè)整體傳遞給filter
stu=Student.objects.filter(Q(name='張三') | ~Q(age=10))

F()

提問(wèn):怎么實(shí)現(xiàn)將id為1的學(xué)生的年齡在原來(lái)年齡的基礎(chǔ)上加一?

原生sql語(yǔ)句:

update curd_student set age=age+1 where id =1

當(dāng)然以上的sql語(yǔ)句并不是我們討論的重點(diǎn),我們要做的是在Django的ORM方式中實(shí)現(xiàn)。

使用Django很容易想到的一種方式:

>>>stu =Student.objects.get(pk=1)  #先得到id=1的學(xué)生對(duì)象
>>>stu.age+=1  #使用python代碼在內(nèi)存中進(jìn)行計(jì)算賦值
>>>stu.save() #執(zhí)行數(shù)據(jù)庫(kù)修改

這種方式是并不是采用數(shù)據(jù)庫(kù)的sql方式進(jìn)行原數(shù)據(jù)基礎(chǔ)上修改(上面所說(shuō)的原生sql語(yǔ)句),計(jì)算發(fā)生在python執(zhí)行的內(nèi)存中,雖然也能實(shí)現(xiàn)效果,但是我們并不推薦這種方式。
如果我們修改一下提問(wèn)的內(nèi)容:將所有的學(xué)生的年齡在原來(lái)年齡的基礎(chǔ)上加一。此時(shí)在使用python計(jì)算的方式就暴露出是十分笨拙,性能低下的缺點(diǎn)。F()函數(shù)的作用就體現(xiàn)出來(lái)了,Django使用F()對(duì)象生成一個(gè)描述數(shù)據(jù)庫(kù)級(jí)別所需操作的SQL表達(dá)式。它能做的是參考某個(gè)字段創(chuàng)建SQL語(yǔ)法來(lái)描述操作

我們接下里使用以下F()來(lái)實(shí)現(xiàn)剛才的兩個(gè)提問(wèn):
1實(shí)現(xiàn)將id為1的學(xué)生的年齡在原來(lái)年齡的基礎(chǔ)上加一

>>>stu =Student.objects.get(pk=1)  #先得到id=1的學(xué)生對(duì)象
>>>stu.age=F('age')+1  #覆蓋Python運(yùn)算符來(lái)創(chuàng)建一個(gè)封裝的SQL表達(dá)式
>>>stu.save() #執(zhí)行數(shù)據(jù)庫(kù)修改

2修改所有學(xué)生的年齡在原來(lái)的基礎(chǔ)上加一:

>>>from django.db.models import F
>>>stus=Student.objects.all() #獲取所有的學(xué)生對(duì)象
>>>stus.update(age=F('age')+1) #執(zhí)行更新,使用sql的方式
>>># UPDATE `CURD_student` SET `age` = (`CURD_student`.`age` + 1); 

使用F()避免競(jìng)爭(zhēng)關(guān)系
使用F()的另一個(gè)好處是使用數(shù)據(jù)庫(kù)來(lái)更新字段而不是用Python,以此避免競(jìng)爭(zhēng)關(guān)系。
如果有兩個(gè)Python線(xiàn)程執(zhí)行上面的示例,A線(xiàn)程可能在B線(xiàn)程從數(shù)據(jù)庫(kù)檢索數(shù)據(jù)后來(lái)檢索、增加并保存某個(gè)字段值。那么B線(xiàn)程的保存將基于他最初檢索到的原始值;而A線(xiàn)程的工作將會(huì)丟失。如果有數(shù)據(jù)庫(kù)自身負(fù)責(zé)更新字段,這個(gè)過(guò)程將會(huì)更加健壯:在執(zhí)行sasve()和update()時(shí)基于數(shù)據(jù)庫(kù)中當(dāng)前的字段值,而不是基于被檢索出的實(shí)例的值。

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

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

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