本節(jié)內(nèi)容
?
?
?
講django的models之前, 先來想一想, 讓你通過django操作數(shù)據(jù)庫,你怎么做? 做苦思冥想,可能會(huì)這樣寫。
12345678910111213141516 | import ?pymysql ??def ?index(request): ???? # 創(chuàng)建連接 ???? conn? = ?pymysql.connect(host = '127.0.0.1' , port = 3306 , user = 'root' , passwd = 'alex123' , db = 'luffy_dev' ) ???? # 創(chuàng)建游標(biāo) ???? cursor? = ?conn.cursor() ????? cursor.execute( "select username,email,mobile from web_account" ) ???? data_set? = ?cursor.fetchall() ????? cursor.close() ???? conn.close() ????? return ?HttpResponse(data_set) |
?
很方便就實(shí)現(xiàn)了從數(shù)據(jù)庫里取數(shù)據(jù),事實(shí)上,很多人確實(shí)就是這么做的。但這樣做會(huì)帶來2個(gè)問題
?
那怎么辦呢?ORM提供了新思路。
對象關(guān)系映射(Object Relational Mapping),它的實(shí)質(zhì)就是將關(guān)系數(shù)據(jù)(庫)中的業(yè)務(wù)數(shù)據(jù)用對象的形式表示出來,并通過面向?qū)ο螅∣bject-Oriented)的方式將這些對象組織起來,實(shí)現(xiàn)系統(tǒng)業(yè)務(wù)邏輯的過程。
在ORM過程中最重要的概念是映射(Mapping),通過這種映射可以使業(yè)務(wù)對象與數(shù)據(jù)庫分離。從面向?qū)ο髞碚f,數(shù)據(jù)庫不應(yīng)該和業(yè)務(wù)邏輯綁定到一起,ORM則起到這樣的分離作用,使數(shù)據(jù)庫層透明,開發(fā)人員真正的面向?qū)ο蟆?/p>
上面的解釋有點(diǎn)蒙蔽對不?其實(shí)你只需要抓住2個(gè)關(guān)鍵詞, “映射” 和 “對象”,就能知道orm是什么干什么的了。
看下面的圖,就是直觀的例子,把右邊的表結(jié)構(gòu)映射成了左邊的類
ORM可以使你不用再寫原生SQL, 而是像操作對象一樣就可以實(shí)現(xiàn)對表里數(shù)據(jù)的增刪改查
?
好棒棒,媽媽再也不用逼你寫原生sql啦!
但是不要開心太早,ORM確實(shí)提高了開發(fā)效率,并且降低了數(shù)據(jù)操作與代碼之間的耦合,不過有利就有弊,我們總結(jié)一下orm的優(yōu)缺點(diǎn)。
優(yōu)點(diǎn):
缺點(diǎn):
?
講Django為什么說ORM? 哈,? 好啦,是時(shí)候該引出主角啦,因?yàn)镈jango的models基于架構(gòu)ORM實(shí)現(xiàn)的。
Django 的models把數(shù)據(jù)庫表結(jié)構(gòu)映射成了一個(gè)個(gè)的類, 表里的每個(gè)字段就是類的屬性。我們都知道數(shù)據(jù)庫有很多字段類型,int,float,char等, Django的models類針對不同的字段也設(shè)置了不同的類屬性。
12345678910111213141516171819202122232425 | AutoField????????? #An IntegerField that automatically increments according to available IDs BigAutoField?????? #A 64-bit integer, guaranteed to fit numbers from 1 to 9223372036854775807. BigIntegerField??? #-9223372036854775808 to 9223372036854775807 BinaryField??????? #A field to store raw binary data. It only supports bytes assignment BooleanField??? CharField DateField????????? #e.g 2019-04-27 DateTimeField????? #e.g 2019-04-27 17:53:21 DecimalField????? DurationField????? #storing periods of time ,e.g [DD] [HH:[MM:]]ss[.uuuuuu]" EmailField FileField????????? #存儲(chǔ)文件 FloatField ImageField???????? #Inherits all attributes and methods from FileField, but also validates that the uploaded object is a valid image. IntegerField GenericIPAddressField? #IP地址,支持ipv4 NullBooleanField?????? #Like a BooleanField, but allows NULL as one of the options PositiveIntegerField?? #Like an IntegerField, but must be either positive or zero (0). Values from 0 to 2147483647 PositiveSmallIntegerField? #only allows positive? values from 0 to 32767 SlugField? # A slug is a short label for something, containing only letters, numbers, underscores or hyphens. SmallIntegerField TextField??? #A large text field. TimeField??? #A time, represented in Python by a datetime.time instance. URLField UUIDField??? #A field for storing universally unique identifiers. Uses Python’s UUID class. |
?
除了普通的表字段,針對外鍵也有映射
1234 | ForeignKey?? # 外鍵關(guān)聯(lián) ManyToManyField?? #多對多 ?OneToOneField?? # 1對1 |
好啦,接下來就用django的orm來設(shè)計(jì)一個(gè)博客表。
需求
根據(jù)需求,我們設(shè)計(jì)3張表
注意Article表和Tag表是屬于多對多關(guān)系,什么是多對多?即一個(gè)文章有多個(gè)標(biāo)簽,一個(gè)標(biāo)簽又可以屬于多個(gè)文章。?
比如上圖的Article表中id為3的文章 ,它的標(biāo)簽是4,26, 即投資、大文娛、社交, 你看“投資”這個(gè)標(biāo)簽同時(shí)還屬于文章2。 這就是多對多關(guān)系 , 即many to many .?
那這種多對多的關(guān)系如何在表中存儲(chǔ)呢?難道真的像上圖中一樣,在Article表中加個(gè)tags字段,關(guān)聯(lián)Tag表里的多條數(shù)據(jù),通過逗號(hào)區(qū)分?
這倒確實(shí)是個(gè)解決辦法。但是也有問題,一個(gè)字段里存多條紀(jì)錄的id,就沒辦法做查詢優(yōu)化了。比如不能做索引等。
所以若想實(shí)現(xiàn)多對多關(guān)系的高效存儲(chǔ) 查詢優(yōu)化,可以在Article and Tag表之間再搞出一張表。
這樣是不是就實(shí)現(xiàn)了多對多關(guān)聯(lián)?
yes, 沒錯(cuò), django也是這么做的, django 有個(gè)專門的字段,叫ManyToManyField, 就是用來實(shí)現(xiàn)多對多關(guān)聯(lián)的,它會(huì)自動(dòng)生成一個(gè)如上圖一樣的第3張表來存儲(chǔ)多對多關(guān)系。
?
123456789101112131415161718192021222324252627 | from ?django.db? import ?models ?# Create your models here. ??class ?Account(models.Model): ???? username? = ?models.CharField(max_length = 64 ,unique = True ) ???? email? = ?models.EmailField() ???? password? = ?models.CharField(max_length = 128 ) ???? register_date? = ?models.DateTimeField( "注冊日期" ,auto_now_add = True ) ???? signature? = ?models.CharField(verbose_name = "簽名" ,max_length = 128 ,blank = True ,null = True ) ??class ?Article(models.Model): ???? """文章表""" ???? title? = ?models.CharField(max_length = 255 ,unique = True ) ???? content? = ?models.TextField( "文章內(nèi)容" ) ???? account? = ?models.ForeignKey( "Account" ,verbose_name = "作者" ,on_delete = models.CASCADE) ???? tags? = ?models.ManyToManyField( "Tag" ,blank = True ) ???? pub_date? = ?models.DateTimeField() ???? read_count? = ?models.IntegerField(default = 0 ) ??class ?Tag(models.Model): ???? """文章標(biāo)簽表""" ???? name? = ?models.CharField(max_length = 64 ,unique = True ) ???? date? = ?models.DateTimeField(auto_now_add = True ) |
我們發(fā)現(xiàn),每個(gè)字段其實(shí)都是一個(gè)獨(dú)立的對象,一張表其實(shí)是很多類的組合。
上面好多字段里還跟了些參數(shù),我們來看以下常用的:
123456789101112131415 | null???????? #If True, Django will store empty values as NULL in the database. Default is False. blank??????? #If True, the field is allowed to be blank. Default is False. ?db_column??? #The name of the database column to use for this field. If this isn’t given, Django will use the field’s name. db_index???? #If True, a database index will be created for this field. default????? #The default value for the field. This can be a value or a callable object. If callable it will be called every time a new object is created. editable???? # django admin中用,后面講 help_text??? # django admin中用,后面講 primary_key? # If True, this field is the primary key for the model. unique?????? #If True, this field must be unique throughout the table unique_for_date???? #Set this to the name of a DateField or DateTimeField to require that this field be unique for the value of the date field. For example, if you have a field title that has unique_for_date="pub_date", then Django wouldn’t allow the entry of two records with the same title and pub_date. ?unique_for_month??? #Like unique_for_date, but requires the field to be unique with respect to the month. unique_for_year??? verbose_name???? #A human-readable name for the field. If the verbose name isn’t given, Django will automatically create it using the field’s attribute name |
?
還有幾個(gè)特殊的字段屬性需要單獨(dú)介紹下
?
choices
An iterable (e.g., a list or tuple) consisting itself of iterables of exactly two items (e.g. [(A, B), (A, B) ...]) to use as choices for this field.
The first element in each tuple is the actual value to be set on the model, and the second element is the human-readable name.
123456789101112 | class ?Student(models.Model): ???? YEAR_IN_SCHOOL_CHOICES? = ?( ???????? ( 'FR' ,? 'Freshman' ), ???????? ( 'SO' ,? 'Sophomore' ), ???????? ( 'JR' ,? 'Junior' ), ???????? ( 'SR' ,? 'Senior' ), ???? ) ???? year_in_school? = ?models.CharField( ???????? max_length = 2 , ???????? choices = YEAR_IN_SCHOOL_CHOICES, ???????? default = FRESHMAN, ???? ) |
?
ForeignKey.on_delete
當(dāng)一條記錄關(guān)聯(lián)的外鍵紀(jì)錄被刪除時(shí),django 也會(huì)根據(jù)外鍵關(guān)聯(lián)限制的配置來決定如何處理當(dāng)前這條紀(jì)錄。舉例,如果你有個(gè)可以為null的外鍵關(guān)聯(lián),并且你想在本紀(jì)錄關(guān)聯(lián)的數(shù)據(jù)被刪除時(shí),把當(dāng)前紀(jì)錄的關(guān)聯(lián)字段設(shè)為null,那就配置如下
123456 | user? = ?models.ForeignKey( ???? User, ???? on_delete = models.SET_NULL, ???? blank = True , ???? null = True , ) |
這個(gè)on_delete就是決定在關(guān)聯(lián)對象被刪除時(shí),如何處理當(dāng)前紀(jì)錄的,常用的參數(shù)如下:
?
Django支持多種數(shù)據(jù)庫,Sqlite、Mysql、Oracle、PostgreSQL,默認(rèn)的是小型文件數(shù)據(jù)庫Sqlite
123456 | DATABASES? = ?{ ???? 'default' : { ???????? 'ENGINE' :? 'django.db.backends.sqlite3' , ???????? 'NAME' : os.path.join(BASE_DIR,? 'db.sqlite3' ), ???? } } |
?
咱們是干大事的人,怎么也得用個(gè)Mysql呀, 改成mysql 也so easy.
12345678910 | DATABASES? = ?{ ???? 'default' : { ???????? 'ENGINE' :? 'django.db.backends.mysql' , ???????? 'NAME' :? 'my_db' , ???????? 'USER' :? 'mydatabaseuser' , ???????? 'PASSWORD' :? 'mypassword' , ???????? 'HOST' :? '127.0.0.1' , ???????? 'PORT' :? '3306' , ???? } } |
?
不過注意,python3 連接mysql的得使用pymysql,MysqlDB模塊300年沒更新了,但django默認(rèn)調(diào)用的還是MySQLdb, so pymysql有個(gè)功能可以讓django以為是用了MySQLdb. 即在項(xiàng)目目錄下的__init__.py中加上句代碼就好
123 | import ?pymysql ?pymysql.install_as_MySQLdb() |
?
不加的話,一會(huì)連接數(shù)據(jù)時(shí)會(huì)報(bào)錯(cuò)噢 。
?
你在ORM定義的表結(jié)構(gòu)如何同步到真實(shí)的數(shù)據(jù)庫里呢? 只需2條命令。但django只能幫你自動(dòng)創(chuàng)建表,數(shù)據(jù)庫本身還是得你自己來。
1 | create ?database ?my_db charset utf8; |
好了,可以同步了,說好只需2步。
1. 生成同步文件,?django自帶一個(gè)專門的工具叫migrations, 負(fù)責(zé)把你的orm表轉(zhuǎn)成實(shí)際的表結(jié)構(gòu),它不旦可以幫自動(dòng)創(chuàng)建表,對表結(jié)構(gòu)的修改,比如增刪改字段、改字段屬性等也都能自動(dòng)同步。只需通過下面神奇的命令。
1 | python manage.py makemigrations |
?不出意外的話,會(huì)顯示類似以下信息
1234567 | $ python manage.py makemigrations Migrations? for ?'app01' : ?? app01 /migrations/0001_initial .py ???? - Create model Account ???? - Create model Article ???? - Create model Tag ???? - Add field tags to article |
?
此時(shí)你會(huì)發(fā)現(xiàn),你的app下的migrations目錄里多了一個(gè)0001_initial.py的文件 ,這個(gè)文件就是因?yàn)槟氵@條命令而創(chuàng)建的,migrations工具就會(huì)根據(jù)這個(gè)文件來創(chuàng)建數(shù)據(jù)庫里的表。
2. 同步到數(shù)據(jù)
1234567891011121314151617181920 | $ python manage.py migrate Operations to perform: ?? Apply all migrations: admin, app01, auth, contenttypes, sessions Running migrations: ?? Applying contenttypes.0001_initial... OK ?? Applying auth.0001_initial... OK ?? Applying admin.0001_initial... OK ?? Applying admin.0002_logentry_remove_auto_add... OK ?? Applying app01.0001_initial... OK ?? Applying contenttypes.0002_remove_content_type_name... OK ?? Applying auth.0002_alter_permission_name_max_length... OK ?? Applying auth.0003_alter_user_email_max_length... OK ?? Applying auth.0004_alter_user_username_opts... OK ?? Applying auth.0005_alter_user_last_login_null... OK ?? Applying auth.0006_require_contenttypes_0002... OK ?? Applying auth.0007_alter_validators_add_error_messages... OK ?? Applying auth.0008_alter_user_username_max_length... OK ?? Applying auth.0009_alter_user_last_name_max_length... OK ?? Applying sessions.0001_initial... OK (venv_django2) Alexs-MacBook-Pro:mysite alex$ |
?
此時(shí)登錄你的數(shù)據(jù)庫,會(huì)發(fā)現(xiàn)創(chuàng)建了好多張表
1234567891011121314151617181920 | mysql> show tables; ---------------------------- | Tables_in_luffy_dev2?????? | ---------------------------- | app01_account????????????? |?? #對應(yīng)Account表 | app01_article????????????? |?? #對應(yīng)Article表 | app01_article_tags???????? |?? #自動(dòng)創(chuàng)建的Article to Tag的多對多關(guān)聯(lián)表 | app01_tag????????????????? |?? #對應(yīng)Tag表 | auth_group???????????????? |?? #下面這些,都是django 自帶的表,這個(gè)是自動(dòng)用戶系統(tǒng)的組 | auth_group_permissions???? |?? #自帶的組與權(quán)限的多對多關(guān)聯(lián)表 | auth_permission??????????? |?? #自帶權(quán)限表 | auth_user????????????????? |?? #用戶表 | auth_user_groups?????????? | | auth_user_user_permissions | | django_admin_log?????????? |?? #現(xiàn)在你的無法理解?? | django_content_type??????? |?? #現(xiàn)在你的無法理解 | django_migrations????????? |?? #紀(jì)錄migartions工具同步紀(jì)錄的表 | django_session???????????? |?? #現(xiàn)在你的無法理解 ---------------------------- 14 rows? in ?set ?(0.00 sec) |
好啦,表結(jié)構(gòu)也有了,我們可以往里面插數(shù)據(jù)啦。
之前說好的是可以不用SQL語句的,一點(diǎn)不騙你。
?
先進(jìn)入已經(jīng)連接好數(shù)據(jù)庫的django python環(huán)境
1234567 | (venv_django2) Alexs-MacBook-Pro:mysite alex$ python manage.py shell? Python 3.5.2 (v3.5.2:4def2a2901a5, Jun 26 2016, 10:47:25) [GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin Type? "help" ,? "copyright" ,? "credits" ?or? "license" ?for ?more ?information. (InteractiveConsole) >>> >>> from app01? import ?models |
創(chuàng)建
創(chuàng)建數(shù)據(jù)簡單的令人發(fā)指
?
?
?
查
filter 支持很多的過濾條件,我們來看下:
?
?
contains
包含,相當(dāng)于sql的like條件
1 | Entry.objects.get(headline__contains= 'Lennon' ) |
SQL equivalent:
1 | SELECT ?...? WHERE ?headline? LIKE ?'%Lennon%' ; |
Note this will match the headline 'Lennon honored today' but not 'lennon honored today'.
icontains? 大小寫不敏感
in
In a given iterable; often a list, tuple, or queryset.
1 | Entry.objects. filter (id__in = [ 1 ,? 3 ,? 4 ]) |
SQL equivalent:
1 | SELECT ?...? WHERE ?id? IN ?(1, 3, 4); |
You can also use a queryset to dynamically evaluate the list of values instead of providing a list of literal values:
12 | inner_qs? = ?Blog.objects. filter (name__contains = 'Cheddar' ) entries? = ?Entry.objects. filter (blog__in = inner_qs) |
This queryset will be evaluated as subselect statement:
1 | SELECT ?...? WHERE ?blog.id? IN ?( SELECT ?id? FROM ?...? WHERE ?NAME ?LIKE ?'%Cheddar%' ) |
gt
1 | Entry.objects. filter (id__gt = 4 ) |
SQL equivalent:
1 | SELECT ?...? WHERE ?id > 4; |
gte
Greater than or equal to.
lt
Less than.
lte
Less than or equal to.
startswith
Case-sensitive starts-with.
1 | Entry.objects. filter (headline__startswith = 'Lennon' ) |
SQL equivalent:
1 | SELECT ?...? WHERE ?headline? LIKE ?'Lennon%' ; |
SQLite doesn’t support case-sensitive LIKE statements; startswith acts like istartswith for SQLite
istartswith
Case-insensitive starts-with.
endswith
Case-sensitive ends-with.
iendswith
Case-insensitive ends-with
range
區(qū)間過渡,可對數(shù)字、日期進(jìn)行過濾
1234 | import ?datetime start_date? = ?datetime.date( 2005 ,? 1 ,? 1 ) end_date? = ?datetime.date( 2005 ,? 3 ,? 31 ) Entry.objects. filter (pub_date__range = (start_date, end_date)) |
SQL equivalent:
1 | SELECT ... WHERE pub_date BETWEEN? '2005-01-01' ?and ?'2005-03-31' ; |
Warning!
Filtering a DateTimeField with dates won’t include items on the last day, because the bounds are interpreted as “0am on the given date”. If pub_date was a DateTimeField, the above expression would be turned into this SQL:
SELECT ... WHERE pub_date BETWEEN '2005-01-01 00:00:00' and '2005-03-31 00:00:00';
Generally speaking, you can’t mix dates and datetimes.
date
For datetime fields, casts the value as date. Allows chaining additional field lookups. Takes a date value.
12 | Entry.objects. filter (pub_date__date = datetime.date( 2005 ,? 1 ,? 1 )) Entry.objects. filter (pub_date__date__gt = datetime.date( 2005 ,? 1 ,? 1 )) |
year
For date and datetime fields, an exact year match. Allows chaining additional field lookups. Takes an integer year.
12 | Entry.objects. filter (pub_date__year = 2005 ) Entry.objects. filter (pub_date__year__gte = 2005 ) |
SQL equivalent:
12 | SELECT ?...? WHERE ?pub_date? BETWEEN ?'2005-01-01' ?AND ?'2005-12-31' ; SELECT ?...? WHERE ?pub_date >=? '2005-01-01' ; |
When USE_TZ is True, datetime fields are converted to the current time zone before filtering. 簡單解決辦法是把USE_TZ=False
month
For date and datetime fields, an exact month match. Allows chaining additional field lookups. Takes an integer 1 (January) through 12 (December).
12 | Entry.objects. filter (pub_date__month = 12 ) Entry.objects. filter (pub_date__month__gte = 6 ) |
When?USE_TZ
?is?True
, datetime fields are converted to the current time zone before filtering. This requires?time zone definitions in the database.
SQL equivalent:
12 | SELECT ?...? WHERE ?EXTRACT( 'month' ?FROM ?pub_date) =? '12' ; SELECT ?...? WHERE ?EXTRACT( 'month' ?FROM ?pub_date) >=? '6' ; |
day
For date and datetime fields, an exact day match. Allows chaining additional field lookups. Takes an integer day.
12 | Entry.objects.filter(pub_date__day=3) Entry.objects.filter(pub_date__day__gte=3) |
SQL equivalent:
12 | SELECT ?...? WHERE ?EXTRACT( 'day' ?FROM ?pub_date) =? '3' ; SELECT ?...? WHERE ?EXTRACT( 'day' ?FROM ?pub_date) >=? '3' ; |
week
For date and datetime fields, return the week number (1-52 or 53) according to?ISO-8601, i.e., weeks start on a Monday and the first week contains the year’s first Thursday.
Example:
12 | Entry.objects. filter (pub_date__week = 52 ) Entry.objects. filter (pub_date__week__gte = 32 , pub_date__week__lte = 38 ) |
week_day
For date and datetime fields, a ‘day of the week’ match. Allows chaining additional field lookups.
Takes an integer value representing the day of week from 1 (Sunday) to 7 (Saturday).
Example:
12 | Entry.objects.filter(pub_date__week_day=2) Entry.objects.filter(pub_date__week_day__gte=2) |
hour
For datetime and time fields, an exact hour match. Allows chaining additional field lookups. Takes an integer between 0 and 23.
Example:
123 | Event.objects. filter (timestamp__hour = 23 ) Event.objects. filter (time__hour = 5 ) Event.objects. filter (timestamp__hour__gte = 12 ) |
SQL equivalent:
123 | SELECT ?...? WHERE ?EXTRACT( 'hour' ?FROM ?timestamp ) =? '23' ; SELECT ?...? WHERE ?EXTRACT( 'hour' ?FROM ?time ) =? '5' ; SELECT ?...? WHERE ?EXTRACT( 'hour' ?FROM ?timestamp ) >=? '12' ;同 |
同時(shí),還支持mintue,second
1234 | Event.objects.filter(time__minute=46) ??Event.objects.filter(timestamp__second=31) |
isnull
Takes either?True
?or?False
, which correspond to SQL queries of?IS?NULL
?and?IS?NOT?NULL
, respectively.
Example:
1 | Entry.objects. filter (pub_date__isnull = True ) |
SQL equivalent:
1 | SELECT ?...? WHERE ?pub_date? IS ?NULL ; |
regex
Case-sensitive regular expression match.
Example:
1 | Entry.objects.get(title__regex = r '^(An?|The) ' ) |
SQL equivalents:
1234567 | SELECT ?...? WHERE ?title REGEXP? BINARY ?'^(An?|The) ' ;? -- MySQL ?SELECT ?...? WHERE ?REGEXP_LIKE(title,? '^(An?|The) ' ,? 'c' );? -- Oracle ?SELECT ?...? WHERE ?title ~? '^(An?|The) ' ;? -- PostgreSQL ?SELECT ?...? WHERE ?title REGEXP? '^(An?|The) ' ;? -- SQLite |
iregex?大小寫不敏感
改刪
123456789101112131415 | # 批量修改 models.Account.objects. filter (username = 'elina' ).update(password = "Luffy#21" ) ?# 單條修改 obj? = ?models.Account.objects.get(username = 'linux' ) obj.username? = ?'python' obj.save() ??# 批量刪除 models.User.objects.get(password = 'oldboy' ).delete() ?# 單條刪除 obj? = ?models.User.objects.get( id = 3 ) obj.delete() |
?
?
values()
Returns a?QuerySet
?that returns dictionaries, rather than model instances, when used as an iterable.
1234 | >>> Blog.objects.values() <QuerySet [{ 'id' :? 1 ,? 'name' :? 'Beatles Blog' ,? 'tagline' :? 'All the latest Beatles news.' }]> >>> Blog.objects.values( 'id' ,? 'name' ) <QuerySet [{ 'id' :? 1 ,? 'name' :? 'Beatles Blog' }]> |
order_by()
By default, results returned by a?QuerySet
?are ordered by the ordering tuple given by the?ordering
?option in the model’s?Meta
. You can override this on a per-QuerySet
?basis by using the?order_by
?method.
1 | Entry.objects. filter (pub_date__year = 2005 ).order_by( '-pub_date' ,? 'headline' ) |
The result above will be ordered by?pub_date
?descending, then by?headline
?ascending. The negative sign in front of?"-pub_date"
indicates?descending?order. Ascending order is implied.?
reverse()
Use the?reverse()
?method to reverse the order in which a queryset’s elements are returned. Calling?reverse()
?a second time restores the ordering back to the normal direction.
To retrieve the “l(fā)ast” five items in a queryset, you could do this:
1 | my_queryset.reverse()[: 5 ] |
123456789101112131415161718192021222324252627 | 單表對象操作 o? = ?models.Article.objects. all ()[ 0 ] o.tilte ?外鍵關(guān)聯(lián) >>> o.account.username 'jack' >>> o.account.username? = ?rain ?外鍵反向關(guān)聯(lián)操作 >>> a? = ?models.Account.objects.get(username = 'alex' ) >>> a.article_set. all () <QuerySet [<Article: 你好, 2018 >]> >>> a.article_set.select_related() <QuerySet [<Article: 你好, 2018 >]> ??多對多操作 >>> o? = ?models.Article.objects. all ()[ 1 ] >>> o.tags. all () <QuerySet [<Tag: 投資>, <Tag: 科技>]> ??多對多反向操作 >>> t? = ?models.Tag.objects.get(name = "投資" ) >>> t.article_set. all () <QuerySet [<Article: 你好, 2018 >, <Article: 粉絲超過 10 萬后,我經(jīng)歷了抖音盜號(hào)風(fēng)波>]> |
?
好啦,orm的操作先點(diǎn)到為止,后面學(xué)項(xiàng)目時(shí)再帶你搞復(fù)雜的。
練習(xí)題
來源:https://www.icode9.com/content-4-328551.html
聯(lián)系客服