Django之 Models組件

本節內容前端

 

  • 路由系統
  • 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的優缺點。

優勢:

  1. 實現了代碼與數據操做的解耦合
  2. 不需本身寫原生sql, 提升開發效率
  3. 防止SQL注入, 經過對象操做的方式,默認就是防止sql注入的。

缺點:

  1. 犧牲性能, 對象到原生SQL勢必會有轉換消耗,對性能有必定的影響 
  2. 複雜語句力不從心, 一些複雜的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來設計一個博客表。

需求

  1. 每一個用戶有本身的帳戶信息
  2. 用戶能夠發文章
  3. 文章能夠打多個標籤

根據需求,咱們設計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

New in Django 1.11.

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()

values( *fields**expressions)

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()

order_by( *fields)

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
單表對象操做
=  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的操做先點到爲止,後面學項目時再帶你搞複雜的。

練習題

  1. 基於前面課程設計的表結構,完成如下練習:
  2. 建立5條account和5條新tag紀錄
  3. 建立5條article信息,關聯上面的不一樣的用戶和tag
  4. 在account表裏找到用戶名包含al的紀錄,而後把密碼改掉
  5. 在article表找到文章內容包含「電影」2個字的,把這些文章加上」大文娛」tag
  6. 把用戶elina發表的文章找出來,而且把做者都改爲alex
  7. 找到用戶表裏註冊日期在2018-04月,而且signature爲空的紀錄
  8. 打到文章中標籤爲「投資」的全部文章
  9. 找到每月8號註冊的用戶
  10. 找到每一年5月發表的文章 
  11. 找到2015-2017年5月發表的文章 
  12. 找到文章做者以’a’或’k’開頭的文章
相關文章
相關標籤/搜索