Notes|Django|ORM

d.l.spm
10 min readApr 26, 2020

--

QuerySet API 筆記

ORM(Object-relational mapping):將關聯式資料料庫映射到物件導向
- 使用 Django 提供的 QuerySet API,來操作資料庫(CRUD)。

src=https://medium.com/codeptivesolutions/https-medium-com-codeptivesolutions-commonly-used-sql-queries-using-django-orm-e8466e8d4258
  • CRUD
  • create、save
  • Meta
  • primary key
  • ForeignKey

CRUD

CRUD:Create 新增、Read 讀取、Update 修改、Delete 刪除

  • 使用 shell 來做範例操作
$ python manage.py shell
>>>
  • 先 import 我們的 models
>>> from blog.models import Post

Create

兩種方法差別帶入參數,我們 models.py 裡有設置 default 所以才可以不用帶入參數

>>> Post.objects.create(title='孫子兵法', content='兵不厭詐、這就是戰爭')>>> Post.objects.create()# 若是 ForeignKey情況下避免產生 Django Cannot assign "A1": "B1" must be a "C1" instance
# 要先賦予附類別一個 instance
post = Post.objects.get(title='孫子兵法')
Comment_reply.objects.create(name='孫子', comment=post)

Read

Post.objects.all():查看所有資料只顯示第一個欄位的值
Post.objects.last():查看最後一筆資料

>>> Post.objects.all()# 會發現 object 來代表我們的每一筆資料,但這種方式不易辨別

使用 def __str__ 來複寫 __str__ ,達到改變資料要顯示的值

models.py(加上 def __str__)

def __str__(self):
return self.title
# 這邊可以選擇要顯示的欄位# 也可以自定義
def __str__(self):
return ("標題:{}, 字數:{}, 摘要:{}".format(self.title,len(self.content), self.content[:10]))

Post.objects.get():返回model 物件,符合條件的唯一一筆資料,否則(找不到符合、有多筆符合)會產生exception

Post.objects.filter():返回 QuerySet 集合物件,符合條件的陣列,否則(找不到符合)返回空陣列

>>> p1 = Post.objects.get(title = '孫子兵法')
>>> p2 = Post.objects.filter(title = '孫子兵法')
# 假設要取 id 值
>>> p1.id
>>> p2[0].id
# 使用 conrains 來篩選 title 欄位中所有包含 '兵法' 的 Post
>>> Post.objects.filter(title__contains = '兵法')

把篩選結果放進變數後取內容

>>> title = Post.objects.filter(title__contains = '兵法')>>> title[0].title #取第 0 筆資料的 title 欄位資料

排序

p = Post.objects.all() 
#依照 id 排序
p = Post.objects.order_by('id')
# 反序從新到舊
p = Post.objects.order_by('-id')

Update

>>> title.update(title='兒子兵法') #這樣就把 title 裡每一筆資料的 title 欄位的值改為 "兒子兵法"# 結合 read
>>> Post.objects.filter(title__contains = '兵法').update(title='兒子兵法')
# 回傳修改的資料有幾筆

Delete

# 將 title 裡的所有資料刪除
>>> title.delete()

Meta

Meta

app_label = 'library'
verbose_name = '書籍預約資料'
verbose_name_plural = verbose_name

app_label:指定所屬 appname
verbose_name:admin後台顯示資料表名稱(Django 預設會在複數的情況下在資料表後面加上s)
verbose_name_plural:admin後台顯示複數時的資料表名稱

primary key 主鍵

簡稱 pk:唯一且不重複

Django 自動每個 Model 加上 id 欄位,且設為 primary key、自動遞增

gender = models.IntegerField(unique=True, primary_key = True)

unique=Ture:不允許重複
primary_key = True:設為主鍵

ForeignKey(一對多)外鍵

ForeignKey ( othermodel, on_delete, **options )

  • othermodel
  • on_delete
  • related_name

othermodel

對應父表的主鍵,可以使用 to_field 更改

on_delete

用途:避免出現兩個表數據不一致問題
用法:CASCADE(默認)、PROTECT、SET_NULL、SET_DEFAULT、DO_NOTHING、SET()

  • CASCADE(默認):父表資料被刪除時,關聯的子表資料一併刪除
on_delete = models.CASCADE
  • PROTECT:刪除時會拋出 ProtectedError 錯誤,來阻止刪除
on_delete = models.PROTECT
  • SET_NULL:父表資料被刪除時,關聯的子表資料設為 null(須設置 blank=True, null=True)
models.ForeignKey('父表',on_delete = models.SET_NULL,blank = True,null = True)
  • SET_DEFAULT:父表資料被刪除時,關聯的子表資料替換為 default 值(須設置 default)
models.ForeignKey('父表',on_delete = models.SET_DEFAULT,default ='替代值')
  • DO_NOTHING:父表資料被刪除時,什麼也不做
on_delete = models.DO_NOTHING
  • SET():父表資料被刪除時,關聯的子表資料指定別的值
# 官網例子
def get_sentinel_user():
return get_user_model().objects.get_or_create(username='deleted')[0]
class MyModel(models.Model):
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.SET(get_sentinel_user),
)

範例 Comment、Comment_reply

from django.db import models
from blog_v2.models import Post
class Comment(models.Model):
name = models.CharField(max_length=15, null=False, blank=False, default="Visitors")
text = models.TextField()
class Comment_reply(model.Model):
name = models.CharField(max_length=15, null=False, blank=False, default="Visitors")
text = models.TextField()
comment = models.ForeignKey(Post, on_delete=models.CASCADE)
comment = Comment.objects.all()
c_r = Comment_reply.objects.all()

######################
{% for com in comment %}
<div class="media mb-4">
<img class="d-flex mr-3 rounded-circle" src="http://placehold.it/50x50" alt="">
<div class="media-body">

<h5 class="mt-0">{{com.name}}</h5>
<!-- <span>{{com.create_time|date:"Y.m.d"}}</span> -->
{{com.text}}
<div class="">
<label>
<span>&nbsp;</span>
<input type="submit" class="btn btn-primary" value="回覆"/>
</label>
</div>
</div>

<div class="media mt-4">
<img class="d-flex mr-3 rounded-circle" src="http://placehold.it/50x50" alt="">
<div class="media-body">
<h5 class="mt-0">Commenter Name</h5>
Cras in faucibus.
</div>
</div>
</div>
{% endfor %}

這邊採的坑 (搜尋:資料庫遷移、新增資料表)

related_name

用途:用於反向查詢
用法:自定義一個名稱,用來反向查詢(默認是:小寫的子表名稱+_set)

當多個 foreignkey 指向同一個主表時,related_name 必須設置,比較容易分辨

--

--

d.l.spm
d.l.spm

No responses yet