๐Ÿ“

Model(RDB, ERD, 1:N, N:M, 1:1)

  • ์ด ์ฑ•ํ„ฐ์˜ ์ „์ฒด ์†Œ์Šค์ฝ”๋“œ

๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ž€?

๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค(database, DB)๋Š” ์—ฌ๋Ÿฌ ์‚ฌ๋žŒ๋“ค์ด ๊ณต์œ ๋ฅผ ๋ชฉ์ ์œผ๋กœ ํ•˜๋Š” ๋ฐ์ดํ„ฐ๋“ค์˜ ์ง‘ํ•ฉ์ž…๋‹ˆ๋‹ค.

1. ๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค(RDB, Relational Database)

ํ•™์ƒ
ํ•™๋ฒˆ
์ด๋ฆ„
๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋Š” ์œ„์ฒ˜๋Ÿผ ํ…Œ์ด๋ธ”์ด๋ผ๊ณ  ๋ถˆ๋ฆฌ๋Š” ํ‘œ๋ฅผ ํ†ตํ•ด ๋ฐ์ดํ„ฐ ์ง‘ํ•ฉ์„ ํ‘œํ˜„ํ•˜๋Š” ๋ฐฉ์‹์˜ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์ž…๋‹ˆ๋‹ค.

1.1 ๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ์ข…๋ฅ˜

  • ๊ณ„์ธตํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค(1:N)
  • ๋งํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค(N:M)
  • ๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค(๋‹จ์ˆœํ•œ ํ‘œ ํ˜•ํƒœ์˜ ์ƒํ˜ธ ๊ด€๊ณ„, 1:1, 1:N, N:M๊ด€๊ณ„ ํ‘œํ˜„)
  • ๊ฐ์ฒด ์ง€ํ–ฅํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค

1.2 ํ‚ค์˜ ๊ฐœ๋…๊ณผ ์ข…๋ฅ˜

  • ๊ธฐ๋ณธํ‚ค๋Š” ๋ฉ”์ธ์œผ๋กœ ์‚ฌ์šฉํ•  ํ‚ค๋ฅผ ๋งํ•ฉ๋‹ˆ๋‹ค. ๊ณ ์œ ํ•œ(์œ ์ผํ•œ) ์ฃผ๋ฏผ๋“ฑ๋ก๋ฒˆํ˜ธ๋‚˜, ๊ณ„์ขŒ๋ฒˆํ˜ธ, ์ „ํ™”๋ฒˆํ˜ธ ๋“ฑ์„ ๊ธฐ๋ณธํ‚ค๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ธฐ๋ณธํ‚ค๋Š” NULL์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.
  • ํ›„๋ณดํ‚ค๋Š” ๊ธฐ๋ณธํ‚ค๋ฅผ ์ œ์™ธํ•˜๊ณ  ๊ณ ์œ ํ•œ ํ‚ค๋“ค์„ ๋งํ•ฉ๋‹ˆ๋‹ค.
  • ์™ธ๋ž˜ํ‚ค๋Š” ๊ด€๊ณ„๋˜์–ด ์žˆ๋Š” ํ…Œ์ด๋ธ”์—์„œ ์ฐธ๊ณ ํ•˜๊ณ  ์žˆ๋Š” ํ‚ค๋ฅผ ์–˜๊ธฐํ•ฉ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ ํ•™์ƒ ๋ฆด๋ ˆ์ด์…˜๊ณผ ์ˆ˜๊ฐ•์‹ ์ฒญ ๊ณผ๋ชฉ ๋ฆด๋ ˆ์ด์…˜์€ ์„œ๋กœ ํ•™๋ฒˆ์œผ๋กœ ์—ฐ๊ฒฐ๋˜์–ด ์žˆ์ฃ .

1.3 ํ…Œ์ด๋ธ”

notion imagenotion image
  • ํŠœํ”Œ(Tuple)์€ ํ…Œ์ด๋ธ”์˜ ํ–‰์ž…๋‹ˆ๋‹ค.
  • ์†์„ฑ(Attribute)์€ HTML๋กœ ๋”ฐ์ง€์ž๋ฉด Table Heading ์ž…๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ๋Š” ํ•™๋ฒˆ, ์ด๋ฆ„, ์ฃผ์†Œ, ์ „ํ™”๋ฒˆํ˜ธ๊ฐ€ ์†์„ฑ์ด์ฃ .
  • ๋„๋ฉ”์ธ(Domain)์€ ํ•˜๋‚˜์˜ ์†์„ฑ์—์„œ ์ทจํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ’์˜ ๋ฒ”์œ„๋ฅผ ๋งํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์œ„์—์„œ๋Š” ์‹ ์ฒญ ๊ณผ๋ชฉ์—์„œ ์ „์ฒด ๊ณผ๋ชฉ์˜ ๋ฒ”์œ„๋ฅผ ์–˜๊ธฐํ•ฉ๋‹ˆ๋‹ค.
  • ์ฐจ์ˆ˜(Degree)๋Š” ์†์„ฑ์˜ ๊ฐœ์ˆ˜์ž…๋‹ˆ๋‹ค. ํ•™์ƒ ๋ฆด๋ ˆ์ด์…˜์—์„œ๋Š” ํ•™๋ฒˆ, ์ด๋ฆ„, ์ฃผ์†Œ, ์ „ํ™”๋ฒˆํ˜ธ์ด๋‹ˆ ์ด 4๊ฐœ๊ฐ€ ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.
  • ๊ธฐ์ˆ˜(Cardinality)๋Š” ํŠœํ”Œ์˜ ๊ฐœ์ˆ˜์ž…๋‹ˆ๋‹ค. ์œ„์—์„œ๋Š” ์–ดํŠธ๋ฆฌ๋ทฐํŠธ๋ฅผ ์ œ์™ธํ•˜๊ณ  ์ด 5๊ฐœ์˜ ํŠœํ”Œ์ด ์กด์žฌํ•ฉ๋‹ˆ๋‹ค.

1.5 Django์˜ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค

์žฅ๊ณ ์—์„œ๋Š” ORM์ด๋ผ๋Š” ๊ธฐ๋Šฅ์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ํŒŒ์ด์ฌ ๋ฌธ๋ฒ•์œผ๋กœ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋•Œ, ํ…Œ์ด๋ธ”๊ณผ ๋Œ€์‘๋˜๋Š” ๊ฒƒ์ด ์žฅ๊ณ ์˜ ๋ชจ๋ธ(Model)์ž…๋‹ˆ๋‹ค.
์œ„์˜ ํ•™์ƒ์— ๋Œ€ํ•œ ํ…Œ์ด๋ธ”์„ ์žฅ๊ณ ์˜ ๋ชจ๋ธ๋กœ ํ‘œํ˜„ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.
from django.db import models class Student(models.Model): number = models.IntegerField("ํ•™๋ฒˆ") name = models.CharField("์ด๋ฆ„", max_length=20)
์œ„์˜ Studentํด๋ž˜์Šค๊ฐ€ ํ•™์ƒ ๋ฐ์ดํ„ฐ์— ๋Œ€ํ•œ ๋ชจ๋ธ์ž…๋‹ˆ๋‹ค. ํ…Œ์ด๋ธ”์—์„œ ํ•™๋ฒˆ, ํ•™๊ณผ, ์ด๋ฆ„ ๊ฐ™์€ ๊ฐ ์ปฌ๋Ÿผ(column)์€ ์†์„ฑ(Attribute)์ด๋ผ๊ณ  ๋ถ€๋ฅด๋Š”๋ฐ, ์ด๋Š” ์žฅ๊ณ  ๋ชจ๋ธ์—์„œ ํ•„๋“œ์— ๋Œ€์‘๋ฉ๋‹ˆ๋‹ค. number, department, name์ด ๊ทธ๊ฒƒ์ž…๋‹ˆ๋‹ค.

2. ERD

ERD(Entity Relation Diagram)๋ž€ ๊ฐœ์ฒด๋“ค ๊ฐ„์˜ ๊ด€๊ณ„๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ๋‹ค์ด์–ด๊ทธ๋žจ์œผ๋กœ, ์—ฌ๊ธฐ์„œ ๊ฐœ์ฒด๋ž€ ๊ด€๊ณ„ํ˜• DB์—์„œ ํ…Œ์ด๋ธ”๋กœ ํ‘œํ˜„๋  ์ˆ˜ ์žˆ๋Š” ๊ฐœ๋…์„ ๋œปํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์œ„์—์„œ๋Š” 'ํ•™์ƒ'์ด๋ผ๋Š” ๊ฐœ์ฒด๋ฅผ ํ…Œ์ด๋ธ”๋กœ ํ‘œํ˜„ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค. 'ํ•™์ƒ'์ด๋ผ๋Š” ๊ฐœ์ฒด๋ฅผ ERD๋กœ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
notion imagenotion image
์—ฌ๊ธฐ์„œ id๋Š” ๊ธฐ๋ณธํ‚ค(Primary Key, PK)๋กœ ๊ฐœ์ฒด๋“ค ๊ฐ„์— ๊ตฌ๋ณ„ํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ฒน์น˜์ง€ ์•Š๊ฒŒ๋” ์ •ํ•˜๋Š” ์‹๋ณ„์ž ์—ญํ• ์˜ ์†์„ฑ์ž…๋‹ˆ๋‹ค. ์›๋ž˜ ํ•™๋ฒˆ์ด ๊ทธ๋Ÿฌํ•œ ์—ญํ• ์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ์žฅ๊ณ ์—์„œ๋Š” PK๋ฅผ ๋”ฐ๋กœ ์„ค์ •ํ•˜์ง€ ์•Š์•„๋„ ์ž๋™์œผ๋กœ id๋ผ๋Š” ์ด๋ฆ„์˜ PK ํ•„๋“œ๋ฅผ ์ƒ์„ฑํ•ด์ค๋‹ˆ๋‹ค.
ย 
ERD๋Š” ERDcloud ๊ฐ™์€ ์„œ๋น„์Šค์—์„œ ์‰ฝ๊ฒŒ ์ž‘์„ฑํ•˜์‹ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ…์ŠคํŠธ๋กœ ๋œ ์„œ๋น„์Šค๋Š” ChatGPT์™€ ์‚ฌ์šฉํ•˜๊ธฐ ์ข‹์Šต๋‹ˆ๋‹ค.

2.1 ๊ด€๊ณ„

์ด๋•Œ๊นŒ์ง€ ๊ฐœ์ฒด(Entity)์— ๋Œ€ํ•ด์„œ ๋‹ค๋ฃจ์—ˆ์œผ๋‹ˆ ์ด์ œ๋Š” ๊ด€๊ณ„(Relation)์— ๋Œ€ํ•ด ์ด์•ผ๊ธฐํ•  ์ฐจ๋ก€์ž…๋‹ˆ๋‹ค. ํ•™์ƒ์ด๋ผ๋Š” ๊ฐœ์ฒด๋Š” ๋‹ค๋ฅธ ๊ฐœ์ฒด์™€ ๊ด€๊ณ„๋ฅผ ๊ฐ€์ง€๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผํ…Œ๋ฉด ํ•™๊ณผ๋ผ๋Š” ๊ฐœ์ฒด๊ฐ€ ๊ทธ๋ ‡์Šต๋‹ˆ๋‹ค.
ํ•™๊ณผ
ํ•™๊ณผ๋ช…
ํ•™๊ณผ์žฅ
ํ…Œ์ด๋ธ” ๊ฐ„ ๊ด€๊ณ„๋ฅผ ๋งž์„ ์ˆ˜ ์žˆ์œผ๋ฉฐ ๊ทธ ์ข…๋ฅ˜๋Š” ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.
  • 1 : N : ํ•˜๋‚˜์˜ ํ…Œ์ด๋ธ”์— ์—ฌ๋Ÿฌ๊ฐœ์˜ ํ…Œ์ด๋ธ”์ด ๋‹ฌ๋ฆด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ๊ฒŒ์‹œํŒ๊ณผ ๊ฒŒ์‹œํŒ ๋Žƒ๊ธ€์˜ ๊ด€๊ณ„๋กœ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ฒŒ์‹œํŒ ํ•˜๋‚˜์— ์—ฌ๋Ÿฌ๊ฐœ์˜ ๋Žƒ๊ธ€์ด ๋‹ฌ๋ฆฌ๋‹ˆ๊นŒ์š”.
  • N : M : ์—ฌ๋Ÿฌ๊ฐœ์˜ ํ…Œ์ด๋ธ”์— ๋‹ค์ค‘์ ์œผ๋กœ ์—ฌ๋Ÿฌ๊ฐœ์˜ ํ…Œ์ด๋ธ”์ด ๋‹ฌ๋ฆฌ๋Š” ๊ตฌ์กฐ์ž…๋‹ˆ๋‹ค.
  • 1 : 1 : ํ•˜๋‚˜์˜ ํ…Œ์ด๋ธ”์— ํ•˜๋‚˜์˜ ํ…Œ์ด๋ธ”์ด ๋งค์นญ๋˜๋Š” ๊ตฌ์กฐ์ž…๋‹ˆ๋‹ค.
๐Ÿ‘‰
Django์—์„œ model์„ ํ†ตํ•œ ๊ด€๊ณ„๋ฅผ ํ‘œ์‹œํ•  ๋•Œ ์–‘๋ฐฉํ–ฅ์œผ๋กœ ์ •์˜๊ฐ€ ํ•„์š”ํ•  ๊ฒƒ ๊ฐ™์ง€๋งŒ, ํ•œ์ชฝ ํด๋ž˜์Šค์—์„œ ๊ด€๊ณ„๋ฅผ ์ •์˜ํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

2.2 1:N, ์™ธ๋ž˜ํ‚ค

๊ฐ ํ•™์ƒ๋“ค์€ ์ž์‹ ์˜ ์ฃผ์ „๊ณต ํ•™๊ณผ๊ฐ€ ์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฏ€๋กœ ํ•™์ƒ ๊ฐœ์ฒด์™€ ํ•™๊ณผ ๊ฐœ์ฒด ์‚ฌ์ด์—๋Š” ๊ด€๊ณ„๊ฐ€ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค. ์ง€๊ธˆ ํ•™๊ณผ:ํ•™์ƒ์˜ ๊ด€๊ณ„๋ฅผ 1:N์ด๋ผ๊ณ  ๋ถ€๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•œ ํ•™์ƒ์€ ์ฃผ์ „๊ณต์„ ์˜ค๋กœ์ง€ 1๊ฐœ๋งŒ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋Š” ํ•œํŽธ, ํ•œ ํ•™๊ณผ์—๋Š” ์—ฌ๋Ÿฌ ํ•™์ƒ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ERD๋กœ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
notion imagenotion image
ํ•™์ƒ ๊ฐœ์ฒด๊ฐ€ ํ•™๊ณผ ๊ฐœ์ฒด์˜ PK ๊ฐ’์„ '์ฐธ์กฐ'ํ•˜๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ์™ธ๋ถ€์—์„œ ๊ฐ€์ ธ์˜จ ํ‚ค๋ผ๊ณ  ํ•ด์„œ ์™ธ๋ž˜ํ‚ค(Foreign Key, FK)๋ผ๊ณ  ๋ถ€๋ฆ…๋‹ˆ๋‹ค. ์žฅ๊ณ ์—์„œ๋Š” 1 : N์˜ ๊ด€๊ณ„๋ฅผ ์ •์˜ํ•˜๊ธฐ ์œ„ํ•ด ForeignKey๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ ForeignKey ํ•„๋“œ๋Š” 1์— ์ •์˜ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ N์— ์ •์˜ํ•ฉ๋‹ˆ๋‹ค.
์ด๋ฒˆ์—๋Š” ์ด๋ฅผ ์žฅ๊ณ ์˜ ๋ชจ๋ธ๋กœ ํ‘œํ˜„ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ ์ ‘๋‘์‚ฌ e.๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ๋Š” ํ•ด๋‹น ๋ชจ๋ธ์ด ๋‹ค๋ฅธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ์†ํ•ด ์žˆ์„ ๋•Œ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Django์—์„œ ๋ชจ๋ธ ๊ฐ„์˜ ๊ด€๊ณ„๋ฅผ ์ •์˜ํ•  ๋•Œ, ๊ฐ™์€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋‚ด์˜ ๋ชจ๋ธ์„ ์ฐธ์กฐํ•˜๋ฉด ๋‹จ์ˆœํžˆ ๋ชจ๋ธ์˜ ์ด๋ฆ„๋งŒ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ฐธ์กฐํ•˜๋ ค๋Š” ๋ชจ๋ธ์ด ๋‹ค๋ฅธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ์†ํ•ด ์žˆ๋Š” ๊ฒฝ์šฐ, ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜๋ช….๋ชจ๋ธ๋ช… ํ˜•ํƒœ๋กœ ์ „์ฒด ๊ฒฝ๋กœ๋ฅผ ๋ช…์‹œํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
from django.db import models # ํ•™์ƒ class Student(models.Model): number = models.IntegerField("ํ•™๋ฒˆ") name = models.CharField("์ด๋ฆ„", max_length=20) major = models.ForeignKey(verbose_name="์ฃผ์ „๊ณต", to='e.Department', on_delete=models.SET_NULL, null=True) def __str__(self): return self.name # ํ•™๊ณผ class Department(models.Model): name = models.CharField("ํ•™๊ณผ๋ช…", max_length=20) head = models.CharField("ํ•™๊ณผ์žฅ", max_length=20) def __str__(self): return self.name
on_delete์˜ต์…˜์€ ์—ฐ๊ฒฐ๋œ ๊ฐ์ฒด๊ฐ€ ์‚ญ์ œ๋  ๊ฒฝ์šฐ ํ˜„์žฌ ๊ฐ์ฒด๋ฅผ ์–ด๋–ป๊ฒŒ ์ฒ˜๋ฆฌํ• ์ง€ ๋ฌป๋Š” ๊ฐ’์ž…๋‹ˆ๋‹ค.
  • CASCADE : ์—ฐ๊ฒฐ๋œ ๊ฐ์ฒด๊ฐ€ ์‚ญ์ œ๋˜๋ฉด ํ•ด๋‹น ๊ฐ์ฒด๋„ ํ•จ๊ป˜ ์‚ญ์ œ
  • PROTECT : ํ•ด๋‹น ๊ฐ์ฒด๊ฐ€ ์žˆ๋‹ค๋ฉด ์—ฐ๊ฒฐ๋œ ๊ฐ์ฒด๊ฐ€ ์‚ญ์ œ๋˜์ง€ ์•Š์Œ
  • SET : ์—ฐ๊ฒฐ๋œ ๊ฐ์ฒด๋งŒ ์‚ญ์ œํ•˜๊ณ , ํ•ด๋‹น ๊ฐ์ฒด๋Š” ์ง€์ •ํ•˜๊ณ  ์žˆ๋Š” ๊ฐ’์œผ๋กœ ์„ค์ •
  • SET_DEFAULT : ์—ฐ๊ฒฐ๋œ ๊ฐ์ฒด๋งŒ ์‚ญ์ œํ•˜๊ณ , ํ•ด๋‹น ๊ฐ์ฒด๋Š” ๊ธฐ๋ณธ ๊ฐ’์œผ๋กœ ์„ค์ •
  • SET_NULL : ์—ฐ๊ฒฐ๋œ ๊ฐ์ฒด๋งŒ ์‚ญ์ œํ•˜๊ณ , ํ•ด๋‹น ๊ฐ์ฒด๋Š” None๊ฐ’์œผ๋กœ ์„ค์ •
  • DO_NOTHING : ์•„๋ฌด๊ฒƒ๋„ ํ•˜์ง€ ์•Š์Œ

2.3 N:M

๊ด€๊ณ„์—์„œ๋Š” ํ•ญ์ƒ 1:N๋งŒ ๋‚˜ํƒ€๋‚˜๋Š” ๊ฑด ์•„๋‹™๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์„œ๋กœ ๋‹ค๋ฅธ ๊ฐœ์ฒด๋“ค ๊ฐ„์—์„œ๋งŒ ๊ด€๊ณ„๊ฐ€ ํ˜•์„ฑ๋˜๋Š” ๊ฒƒ๋„ ์•„๋‹™๋‹ˆ๋‹ค. ์ž๊ธฐ ์ž์‹ ๊ณผ๋„ ๊ด€๊ณ„๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๋ฐ”๋กœ ํ•™์ƒ๋“ค ๊ฐ„์˜ ์นœ๊ตฌ ๊ด€๊ณ„๊ฐ€ ๊ทธ๋ ‡์Šต๋‹ˆ๋‹ค. ํ•™์ƒ ํ•œ ๋ช…์€ ์—ฌ๋Ÿฌ ๋ช…์˜ ์นœ๊ตฌ๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์œผ๋ฉฐ, ํ•œํŽธ์œผ๋กœ๋Š” ๊ทธ ํ•™์ƒ์€ ์—ฌ๋Ÿฌ๋ช…์—๊ฒŒ ์นœ๊ตฌ์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๊ด€๊ณ„๋ฅผ N:M ์ด๋ผ ํ‘œํ˜„ํ•˜๊ณ  ์ด๋ฅผ ERD๋กœ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋‚˜ํƒ€๋‚ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
notion imagenotion image
๋ณด์‹œ๋ฉด '์นœ๊ตฌ๊ด€๊ณ„'๋ผ๋Š” ํ…Œ์ด๋ธ”์„ ํ•˜๋‚˜ ๋” ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค. N:M ๊ด€๊ณ„์—์„œ๋Š” ์ด๋Ÿฌํ•œ ์ค‘๊ณ„ ํ…Œ์ด๋ธ”์ด ํ•„์ˆ˜ ์ž…๋‹ˆ๋‹ค. ์™œ๋ƒํ•˜๋ฉด ํ•œ ์†์„ฑ์—๋Š” ํ•˜๋‚˜์˜ ๊ฐ’๋งŒ ๋“ค์–ด๊ฐˆ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๋งŒ์•ฝ ์™ธ๋ž˜ํ‚ค๋ฅผ ํ•™์ƒ ํ…Œ์ด๋ธ”์— ๋„ฃ๋Š”๋‹ค๋ฉด ์นœ๊ตฌ๊ฐ€ ์—ฌ๋Ÿฌ ๋ช…์ผ ์‹œ ์—ฌ๋Ÿฌ PK ๊ฐ’์ด ๋“ค์–ด๊ฐ€์•ผ ํ•˜๋Š”๋ฐ ์ด๋Š” ๋ถˆ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ๊ทธ ๋Œ€์‹  ์ค‘๊ณ„ ํ…Œ์ด๋ธ”์„ ์ƒ์„ฑํ•˜๊ณ  ๊ฑฐ๊ธฐ์— ์นœ๊ตฌ ๊ด€๊ณ„๋ฅผ pk๋ผ๋ฆฌ ์ง์ง€์–ด์„œ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.
์ด๋ฅผ ์žฅ๊ณ ์˜ ๋ชจ๋ธ๋กœ ํ‘œํ˜„ํ•ด ๋ด…๋‹ˆ๋‹ค.
from django.db import models # ํ•™์ƒ class Student(models.Model): number = models.IntegerField("ํ•™๋ฒˆ") name = models.CharField("์ด๋ฆ„", max_length=20) major = models.ForeignKey(verbose_name="์ฃผ์ „๊ณต", to='e.Department', on_delete=models.SET_NULL, null=True) friends = models.ManyToManyField(verbose_name="์นœ๊ตฌ๋“ค", to='self', db_table='e_friendship', blank=True) def __str__(self): return self.name
์žฅ๊ณ ์˜ ManyToManyField๋ฅผ ์ด์šฉํ•ด ์‰ฝ๊ฒŒ N:M ๊ด€๊ณ„๋ฅผ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Student ํด๋ž˜์Šค์— ์ง์ ‘ ๋“ค์–ด๊ฐ€์ง€๋งŒ ์ด๋Š” ๊ด€๊ณ„๋ฅผ ๋ช…์‹œํ•  ๋ฟ ์‹ค์ œ DB์—๋Š” Student ํ…Œ์ด๋ธ”์— friends๋ผ๋Š” ์†์„ฑ์€ ์ƒ๊ฒจ๋‚˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ ๋Œ€์‹  e_friendship์ด๋ผ๋Š” ์ค‘๊ณ„ ํ…Œ์ด๋ธ”์ด ์ƒ์„ฑ๋˜๊ณ  ํ•™์ƒ์˜ pk๋ฅผ ์ฐธ์กฐํ•˜๋Š” ๋‘ ๊ฐœ์˜ ์™ธ๋ž˜ํ‚ค๋ฅผ ๊ฐ€์ง‘๋‹ˆ๋‹ค.
notion imagenotion image
๐Ÿ‘‰
๋‘ ํ…Œ์ด๋ธ” ๋ชจ๋‘ ManyToMany ํ•„๋“œ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์–ด์„œ๋Š” ์•ˆ๋ฉ๋‹ˆ๋‹ค.
ย 
makemigrations์™€ migrate๋ฅผ ํ•˜๊ณ  admin์—์„œ ํ™•์ธํ•ด๋ณด์„ธ์š”. admin.py์—์„œ ์•„๋ž˜ ์ฝ”๋“œ๋ฅผ ์ž…๋ ฅํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
from django.contrib import admin from .models import Student, Department admin.site.register(Student) admin.site.register(Department)
notion imagenotion image

2.3 1:1

๐Ÿ‘‰
1:1 ๊ด€๊ณ„๋Š” ์‹ค์Šต์„ ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
1:1 ๊ด€๊ณ„๋Š” OneToOneField๋กœ ํ‘œํ˜„์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ForeignKey์—์„œ unique=True ์˜ต์…˜์„ ์ค€ ๊ฒƒ๊ณผ ์œ ์‚ฌํ•˜๊ฒŒ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. ์œ„์˜ ์‹ค์Šต์—์„œ ์ง„ํ–‰ํ•œ ๊ฒƒ์— StudentCard๋ฅผ ๋งŒ๋“ค์–ด 1:1 ๊ด€๊ณ„๋ฅผ ๋งŒ๋“ค์–ด๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ํ•™์ƒ์—๊ฒŒ๋Š” ์œ ์ผํ•œ ํ•™์ƒ ์นด๋“œ๊ฐ€ ๋งค์นญ์ด ๋˜๋‹ˆ๊นŒ์š”.
ย 
from django.db import models # ํ•™์ƒ ๋ชจ๋ธ class Student(models.Model): number = models.IntegerField("ํ•™๋ฒˆ") name = models.CharField("์ด๋ฆ„", max_length=20) major = models.ForeignKey(verbose_name="์ฃผ์ „๊ณต", to='Department', on_delete=models.SET_NULL, null=True) friends = models.ManyToManyField(verbose_name="์นœ๊ตฌ๋“ค", to='self', db_table='e_friendship', blank=True) def __str__(self): return self.name # ํ•™์ƒ์นด๋“œ ๋ชจ๋ธ class StudentCard(models.Model): student = models.OneToOneField(Student, on_delete=models.CASCADE, related_name='card') studentCardID = models.IntegerField() def __str__(self): return str(self.studentCardID)
ย 

3. shell_plus

์žฅ๊ณ  shell์˜ ๋ถˆํŽธํ•œ ์ ์€ ํ•„์š”ํ•œ ๋ชจ๋ธ์ด ์žˆ์œผ๋ฉด ํ•ญ์ƒ import๋ฅผ ํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค๋Š” ์ ์ž…๋‹ˆ๋‹ค.
ํ•˜์ง€๋งŒ django-extensions๋ผ๋Š” ํŒจํ‚ค์ง€๋ฅผ ์„ค์น˜ํ•˜๋ฉด shell_plus๋ผ๋Š” ๊ฒƒ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ, ๊ธฐ๋ณธ์ ์œผ๋กœ ์žฅ๊ณ  shell๊ณผ ๋™์ผํ•˜์ง€๋งŒ, ์‹คํ–‰ ์‹œ ํ•ด๋‹น ํ”„๋กœ์ ํŠธ ๋‚ด์˜ ํ•„์š”ํ•œ ๊ฒƒ๋“ค์„ ์ž๋™์œผ๋กœ importํ•ด์ค€๋‹ค๋Š” ์ ์ž…๋‹ˆ๋‹ค.
  • django-extensions๋ฅผ ๋จผ์ € ์„ค์น˜ํ•ด์ค๋‹ˆ๋‹ค.
    • pip install django-extensions
      notion imagenotion image
      ย 
  • ํ•ด๋‹น ํ”„๋กœ์ ํŠธ์˜ settings.py์˜ INSTALLED_APPS์— django_extensions๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. ์„ค์น˜ ํ•  ๋•Œ์™€ ๋‹ค๋ฅด๊ฒŒ - (dash)๊ฐ€ ์•„๋‹ˆ๋ผ _(underscore)๋ผ๋Š” ์ ์— ์œ ์˜ํ•ฉ๋‹ˆ๋‹ค.
    • INSTALLED_APPS = [ ..., 'django_extensions', ..., ]
ย 
  • ์ด์ œ shell_plus๋ฅผ ์‹คํ–‰์‹œ์ผœ ๋ด…๋‹ˆ๋‹ค.
    • python manage.py shell_plus
      ย 
      ์‚ฌ์ง„๊ณผ ๊ฐ™์ด ํ”„๋กœ์ ํŠธ๋ฅผ ๋‹ค๋ฃจ๋Š”๋ฐ ํ•„์š”ํ•œ ๋ชจ๋“ˆ๋“ค์„ ์‹คํ–‰๋งŒ ์‹œ์ผœ๋„ ์ž๋™์œผ๋กœ importํ•ด์ค๋‹ˆ๋‹ค.
      ย 
      notion imagenotion image
ย 
์ฝ”๋“œ๊ฐ€ ๊ธธ์–ด ์ด ์ฑ•ํ„ฐ์˜ ์ฃผ์š”ํ•œ ์ถœ๋ ฅ ๋‚ด์šฉ๋งŒ ๊ธฐ์ˆ ํ•ฉ๋“œ๊ฐ€ ๊ธธ์–ด ์ด ์ฑ•ํ„ฐ์˜ ์ฃผ์š”ํ•œ ์ถœ๋ ฅ ๋‚ด์šฉ๋งŒ ๊ธฐ์ˆ ํ•ฉ๋‹ˆ๋‹ค.
>>> Student.objects.filter(pk=1) <QuerySet [<Student: ์ดํ˜ธ์ค€>]> >>> q = Student.objects.filter(pk=1) >>> q >>> type(q) >>> dir(q) >>> q[0] >>> q[0].name #str ์ž…๋‹ˆ๋‹ค. >>> type(q[0]) >>> dir(q[0]) >>> q[0].major <Department: ์ปดํ“จํ„ฐ๊ณตํ•™๊ณผ> >>> q[0].major_id 1 >>> type(q[0].major) <class 'e.models.Department'> >>> dir(q[0].major) >>> q[0].major.name '์ปดํ“จํ„ฐ๊ณตํ•™๊ณผ' >>> q[0].friends <django.db.models.fields.related_descriptors.create_forward_many_to_many_manager.<lo cals>.ManyRelatedManager object at 0x7f2e8ac369d0> >>> type(q[0].friends) <class 'django.db.models.fields.related_descriptors.create_forward_many_to_many_mana ger.<locals>.ManyRelatedManager'> >>> dir(q[0].friends) >>> q[0].friends[0] # Error >>> q[0].friends.values() <QuerySet [{'id': 2, 'number': 2, 'name': 'ํ™ํ˜ธ์ค€', 'major_id': 1}, {'id': 3, 'numbe r': 3, 'name': '์ตœํ˜ธ์ค€', 'major_id': 1}]>

์ข‹์€ ๊ธ€