本節內容前端
- 路由系統
- models模型
- admin
- views視圖
- template模板
引子
講django的models以前, 先來想想, 讓你經過django操做數據庫,你怎麼作? 作苦思冥想,可能會這樣寫。python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
import
pymysql
def
index(request):
# 建立鏈接
conn
=
pymysql.connect(host
=
'127.0.0.1'
, port
=
3306
, user
=
'root'
, passwd
=
'alex123'
, db
=
'luffy_dev'
)
# 建立遊標
cursor
=
conn.cursor()
cursor.execute(
"select username,email,mobile from web_account"
)
data_set
=
cursor.fetchall()
cursor.close()
conn.close()
return
HttpResponse(data_set)
|
很方便就實現了從數據庫裏取數據,事實上,不少人確實就是這麼作的。但這樣作會帶來2個問題mysql
- SQL注入危險,由於有的時候你操做數據庫的語句不是寫死在代碼裏的,而是經過前端傳參數拼接的,這就給黑客有了可趁之機,經過拼接參數實現sql注入。
- 語句跟代碼揉在一塊兒了,增長後續維護成本
那怎麼辦呢?ORM提供了新思路。linux
什麼是ORM呢?
對象關係映射(Object Relational Mapping),它的實質就是將關係數據(庫)中的業務數據用對象的形式表示出來,並經過面向對象(Object-Oriented)的方式將這些對象組織起來,實現系統業務邏輯的過程。web
在ORM過程當中最重要的概念是映射(Mapping),經過這種映射可使業務對象與數據庫分離。從面向對象來講,數據庫不該該和業務邏輯綁定到一塊兒,ORM則起到這樣的分離做用,使數據庫層透明,開發人員真正的面向對象。sql
上面的解釋有點矇蔽對不?其實你只須要抓住2個關鍵詞, 「映射」 和 「對象」,就能知道orm是什麼幹什麼的了。shell
- 映射(Mapping) —— 把表結構映射成類
- 對象 —— 像操做類對象同樣,操做數據庫裏的數據
映射
看下面的圖,就是直觀的例子,把右邊的表結構映射成了左邊的類數據庫
Sql語句到對象
ORM可使你不用再寫原生SQL, 而是像操做對象同樣就能夠實現對錶裏數據的增刪改查express
好棒棒,媽媽不再用逼你寫原生sql啦!django
可是不要開心太早,ORM確實提升了開發效率,而且下降了數據操做與代碼之間的耦合,不過有利就有弊,咱們總結一下orm的優缺點。
優勢:
- 實現了代碼與數據操做的解耦合
- 不需本身寫原生sql, 提升開發效率
- 防止SQL注入, 經過對象操做的方式,默認就是防止sql注入的。
缺點:
- 犧牲性能, 對象到原生SQL勢必會有轉換消耗,對性能有必定的影響
- 複雜語句力不從心, 一些複雜的sql語句,用orm對象操做的方式很難實現,就還得用原生sql
講Django爲何說ORM? 哈, 好啦,是時候該引出主角啦,由於Django的models基於架構ORM實現的。
Models模型
Django 的models把數據庫表結構映射成了一個個的類, 表裏的每一個字段就是類的屬性。咱們都知道數據庫有不少字段類型,int,float,char等, Django的models類針對不一樣的字段也設置了不一樣的類屬性。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
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
#存儲文件
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.
|
除了普通的表字段,針對外鍵也有映射
1
2
3
4
|
ForeignKey
# 外鍵關聯
ManyToManyField
#多對多
OneToOneField
# 1對1
|
好啦,接下來就用django的orm來設計一個博客表。
需求
- 每一個用戶有本身的帳戶信息
- 用戶能夠發文章
- 文章能夠打多個標籤
根據需求,咱們設計3張表
注意Article表和Tag表是屬於多對多關係,什麼是多對多?即一個文章有多個標籤,一個標籤又能夠屬於多個文章。
好比上圖的Article表中id爲3的文章 ,它的標籤是4,26, 即投資、大文娛、社交, 你看「投資」這個標籤同時還屬於文章2。 這就是多對多關係 , 即many to many .
那這種多對多的關係如何在表中存儲呢?難道真的像上圖中同樣,在Article表中加個tags字段,關聯Tag表裏的多條數據,經過逗號區分?
這倒確實是個解決辦法。可是也有問題,一個字段裏存多條紀錄的id,就沒辦法作查詢優化了。好比不能作索引等。
因此若想實現多對多關係的高效存儲+查詢優化,能夠在Article and Tag表之間再搞出一張表。
這樣是否是就實現了多對多關聯?
yes, 沒錯, django也是這麼作的, django 有個專門的字段,叫ManyToManyField, 就是用來實現多對多關聯的,它會自動生成一個如上圖同樣的第3張表來存儲多對多關係。
正式的表結構
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
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(
"文章內容"
)
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):
"""文章標籤表"""
name
=
models.CharField(max_length
=
64
,unique
=
True
)
date
=
models.DateTimeField(auto_now_add
=
True
)
|
咱們發現,每一個字段其實都是一個獨立的對象,一張表實際上是不少類的組合。
上面好多字段裏還跟了些參數,咱們來看如下經常使用的:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
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
|
還有幾個特殊的字段屬性須要單獨介紹下
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.
1
2
3
4
5
6
7
8
9
10
11
12
|
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
當一條記錄關聯的外鍵紀錄被刪除時,django 也會根據外鍵關聯限制的配置來決定如何處理當前這條紀錄。舉例,若是你有個能夠爲null的外鍵關聯,而且你想在本紀錄關聯的數據被刪除時,把當前紀錄的關聯字段設爲null,那就配置以下
1
2
3
4
5
6
|
user
=
models.ForeignKey(
User,
on_delete
=
models.SET_NULL,
blank
=
True
,
null
=
True
,
)
|
這個on_delete就是決定在關聯對象被刪除時,如何處理當前紀錄的,經常使用的參數以下:
- CASCADE——Cascade deletes. Django emulates the behavior of the SQL constraint ON DELETE CASCADE and also deletes the object containing the ForeignKey.
- PROTECT——Prevent deletion of the referenced object by raising ProtectedError, a subclass of django.db.IntegrityError.
- SET_NULL——Set the ForeignKey null; this is only possible if null is True.
- SET_DEFAULT——Set the ForeignKey to its default value; a default for the ForeignKey must be set.
配置Django數據庫鏈接信息
Django支持多種數據庫,Sqlite、Mysql、Oracle、PostgreSQL,默認的是小型文件數據庫Sqlite
1
2
3
4
5
6
|
DATABASES
=
{
'default'
: {
'ENGINE'
:
'django.db.backends.sqlite3'
,
'NAME'
: os.path.join(BASE_DIR,
'db.sqlite3'
),
}
}
|
我們是幹大事的人,怎麼也得用個Mysql呀, 改爲mysql 也so easy.
1
2
3
4
5
6
7
8
9
10
|
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默認調用的仍是MySQLdb, so pymysql有個功能可讓django覺得是用了MySQLdb. 即在項目目錄下的__init__.py中加上句代碼就好
1
2
3
|
import
pymysql
pymysql.install_as_MySQLdb()
|
不加的話,一會鏈接數據時會報錯噢 。
同步數據庫
你在ORM定義的表結構如何同步到真實的數據庫裏呢? 只需2條命令。但django只能幫你自動建立表,數據庫自己仍是得你本身來。
1
|
create
database
my_db charset utf8;
|
好了,能夠同步了,說好只需2步。
1. 生成同步文件, django自帶一個專門的工具叫migrations, 負責把你的orm錶轉成實際的表結構,它不旦能夠幫自動建立表,對錶結構的修改,好比增刪改字段、改字段屬性等也都能自動同步。只需經過下面神奇的命令。
1
|
python manage.py makemigrations
|
不出意外的話,會顯示相似如下信息
1
2
3
4
5
6
7
|
$ 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
|
此時你會發現,你的app下的migrations目錄裏多了一個0001_initial.py的文件 ,這個文件就是由於你這條命令而建立的,migrations工具就會根據這個文件來建立數據庫裏的表。
2. 同步到數據
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
$ 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$
|
此時登陸你的數據庫,會發現建立了好多張表
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
mysql> show tables;
+----------------------------+
| Tables_in_luffy_dev2 |
+----------------------------+
| app01_account |
#對應Account表
| app01_article |
#對應Article表
| app01_article_tags |
#自動建立的Article to Tag的多對多關聯表
| app01_tag |
#對應Tag表
| auth_group |
#下面這些,都是django 自帶的表,這個是自動用戶系統的組
| auth_group_permissions |
#自帶的組與權限的多對多關聯表
| auth_permission |
#自帶權限表
| auth_user |
#用戶表
| auth_user_groups |
| auth_user_user_permissions |
| django_admin_log |
#如今你的沒法理解
| django_content_type |
#如今你的沒法理解
| django_migrations |
#紀錄migartions工具同步紀錄的表
| django_session |
#如今你的沒法理解
+----------------------------+
14 rows
in
set
(0.00 sec)
|
好啦,表結構也有了,咱們能夠往裏面插數據啦。
以前說好的是能夠不用SQL語句的,一點不騙你。
用orm對錶數據進行增刪改查
先進入已經鏈接好數據庫的django python環境
1
2
3
4
5
6
7
|
(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
|
建立
建立數據簡單的使人髮指
查
filter 支持不少的過濾條件,咱們來看下:
contains
包含,至關於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:
1
2
|
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
區間過渡,可對數字、日期進行過濾
1
2
3
4
|
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.
1
2
|
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.
1
2
|
Entry.objects.
filter
(pub_date__year
=
2005
)
Entry.objects.
filter
(pub_date__year__gte
=
2005
)
|
SQL equivalent:
1
2
|
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).
1
2
|
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:
1
2
|
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.
1
2
|
Entry.objects.filter(pub_date__day=3)
Entry.objects.filter(pub_date__day__gte=3)
|
SQL equivalent:
1
2
|
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:
1
2
|
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:
1
2
|
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:
1
2
3
|
Event.objects.
filter
(timestamp__hour
=
23
)
Event.objects.
filter
(time__hour
=
5
)
Event.objects.
filter
(timestamp__hour__gte
=
12
)
|
SQL equivalent:
1
2
3
|
SELECT
...
WHERE
EXTRACT(
'hour'
FROM
timestamp
) =
'23'
;
SELECT
...
WHERE
EXTRACT(
'hour'
FROM
time
) =
'5'
;
SELECT
...
WHERE
EXTRACT(
'hour'
FROM
timestamp
) >=
'12'
;同
|
同時,還支持mintue,second
1
2
3
4
|
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:
1
2
3
4
5
6
7
|
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 大小寫不敏感
改刪
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
# 批量修改
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.
1
2
3
4
|
>>> 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 「last」 five items in a queryset, you could do this:
1
|
my_queryset.reverse()[:
5
]
|
ORM對象操做
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
單表對象操做
o
=
models.Article.objects.
all
()[
0
]
o.tilte
外鍵關聯
>>> o.account.username
'jack'
>>> o.account.username
=
rain
外鍵反向關聯操做
>>> 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
萬後,我經歷了抖音盜號風波>]>
|
好啦,orm的操做先點到爲止,後面學項目時再帶你搞複雜的。
練習題
- 基於前面課程設計的表結構,完成如下練習:
- 建立5條account和5條新tag紀錄
- 建立5條article信息,關聯上面的不一樣的用戶和tag
- 在account表裏找到用戶名包含al的紀錄,而後把密碼改掉
- 在article表找到文章內容包含「電影」2個字的,把這些文章加上」大文娛」tag
- 把用戶elina發表的文章找出來,而且把做者都改爲alex
- 找到用戶表裏註冊日期在2018-04月,而且signature爲空的紀錄
- 打到文章中標籤爲「投資」的全部文章
- 找到每月8號註冊的用戶
- 找到每一年5月發表的文章
- 找到2015-2017年5月發表的文章
- 找到文章做者以’a’或’k’開頭的文章