์ ์ฐธ์กฐ : ์์ ์ด ์ฐธ์กฐํ๋ table์ ์ ๊ทผํ๋ ๊ฒ.
์ญ์ฐธ์กฐ : ์์ ์ ์ฐธ์กฐํ๋ table์ ์ ๊ทผํ๋ ๊ฒ.[์ ์ฐธ์กฐ]
์ด ์๋ฆฌ์ฆ์ ์ด์ ํฌ์คํธ์์ select_related()๋ฅผ ํตํด ์ ์ฐธ์กฐ์ ๊ธฐ๋ฅ์ ๋ณผ ์ ์์๋ค.
์ฒ์์ django์ QuerySet ๊ธฐ๋ฅ์ ์ ํ๋ฉด์ ํ ์ด๋ธ์ ๊ฐ์ฒดํํด์ฃผ๋ ์ฉ๋๋ก๋ง ์ธ์ํ์๋ค. ๋๋ฌธ์ "join" ์ฒ๋ฆฌ๊ฐ ํ์ํ ๊ฒฝ์ฐ ๋ฌด์กฐ๊ฑด select_related()๋ฅผ ์ด์ฉํด์ผ ํ๋ ๊ฒ์ผ๋ก ์๊ฐํ์ผ๋ ์ฐฉ๊ฐ์ด์๋ค. foreignKey๋ก ์ง์ ํ ์์ฑ์ id ๊ด๋ จ ๊ฐ๋ง ์๋ ๊ฒ์ด ์๋๋ผ ์ด ์์ฑ์ด relation ํ๊ณ ์๋ ๊ฐ์ฒด์๋ค.
hourplace site์ ๋ชจ๋ธ๋ง ์ค place์ user ์ ๊ด๊ณ๋ฅผ ์๋ก ๋ค์ด๋ณด์.class User(models.Model): name = models.CharField email = models.CharField class Place(models.Model): address = models.CharField floor = models.IntegerField user = models.ForeignKeyField(User, on_delete=models.CASCADE) p = Place.objects.get(id=1) print(p.user.name) print(p.user.email)
์๋ user_id ๋ก related ์ค์ธ user์ ์ ๋ณด๋ฅผ ์ ์ฐธ์กฐ๋ก ์ ๊ทผํ๋ ์์ ์ด๋ค. select_related() ์์ด ๋ฐ๋ก relation ์ค์ธ ๊ฐ์ฒด ์ ๋ณด๋ฅผ ๋ณผ ์ ์๋ค. ๊ทธ๋ฌ๋ฉด select_related()๋ ์ ์ง์ํ๋ ๊ฑธ๊น? ์คํ๋ ค ์ ์์ ์ฒ๋ผ ์ฌ์ฉํ๋๊ฒ ํธ๋ฆฌํ๋ฐ ๋ง์ด๋ค.
์ด๋ Hit(Database์ query๋ฅผ ์์ฒญํ๋ ํ์)๋ฅผ ์ต์ํํ์ฌ ์ฑ๋ฅ์ ์ธ ์ธก๋ฉด์์์ ์ด์ ์ ์ป์ ์ ์๋๋ก ํ๊ธฐ ์ํจ์ผ๋ก SQL๋ก ์น๋ฉด join ์ ์ด์ฉํด ํ๋ฒ์ Hit๋ก ๊ด๊ณ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๋ ๊ธฐ๋ฅ๊ณผ ๊ฐ๋ค.[์ญ์ฐธ์กฐ]
SQL๋ฌธ๋ฒ ์ค join ๊ธฐ๋ฅ์ ์๊ณ ์์๊ธฐ์ ์์ฐ์ค๋ฝ๊ฒ ์ ์ฐธ์กฐ ๊ธฐ๋ฒ์ ์ต์ํ๊ฒ ๋ฐ์๋ค์๋ค. ํ์ง๋ง ์ญ์ฐธ์กฐ๋ผ๋ ๊ฐ๋ ์ ์ดํดํ๊ธฐ ์ฝ์ง ์์๋ค. ์ด์ ๋ํด ๊ณต๋ถํ๋ ๋์ค ์ญ์ฐธ์กฐ๊ฐ ํ์ํ ์ํฉ์ ์ ํ๋ฉด์ ์กฐ๊ธ ์ดํด๊ฐ ๊ฐ๋ค. ์๋๋ ๊ทธ ์ํฉ์ด๋ค.User๋ ์ฌ๋ฌ Place๋ฅผ ์์ ํ ์ ์์ผ๋ฏ๋ก Place๋ user table์ ์ฐธ์กฐํ๋ค. Place๋ง๋ค ์ ์ฐธ์กฐ ๋ฐฉ์์ผ๋ก Place์ ์์ ์ฃผ์ธ user์ ์ ๋ณด(name, email ๋ฑ)๋ฅผ ์ป์ ์ ์๋ค. ๊ทธ๋ฐ๋ฐ ๋ง์ฝ User data๋ฅผ ๊ธฐ์ค์ผ๋ก ์ด User๊ฐ ์์ ํ Place ์ ๋ณด๋ฅผ ์ป์ผ๋ ค๋ฉด ์ด๋ป๊ฒ ํด์ผํ ๊น? Place table์ user_id๋ฅผ ๊ธฐ์ค์ผ๋ก filteringํ๋ ๋ฐฉ๋ฒ์ด ์๊ฒ ์ง๋ง ์ด ๊ฒฐ๊ณผ๋ ์ค์ง Place ์ ๋ํ Queryset๋ง์ด ๋์จ๋ค. ๋๋ User data์ Place data๋ฅผ ๋ชจ๋ ๋ณด์ ํ Queryset์ ์ป๊ณ ์ถ๋ค.
User๊ฐ Place๋ฅผ ์ฐธ์กฐํ๊ณ ์๋ค๋ฉด ์ ์ฐธ์กฐ ๋ฐฉ์ ์ ๊ทผ์ด ๊ฐ๋ฅํ๋ ์ง๊ธ์ ๋ฐ๋ ์ํฉ์ด๋ค. ์ด ๊ฒจ์ฐ๋ฅผ ์ํด ์ญ์ฐธ์กฐ ๊ธฐ๋ฒ์ ์ฌ์ฉํด์ผ ํ๋ค. ์ด๋ฅผ ์ํด prefetch_related() ๋ฅผ ์์๋ณด์.
user = Users.objects.prefetch_related('place_set').get(id=1) print(user.name) print(user.place_set.address)
์ ์ฝ๋์์ prefetch_related()๋ฅผ callํ๋ฉด์ ์ธ์๋ก ์ญ์ฐธ์กฐ ๋์์ธ class์ด๋ฆ + '_set'์ ๋ฃ๊ณ ์๋ค. '_set'์ ์ญ์ฐธ์กฐ๋ฅผ ์๋ฏธํ๋ ์์ฝํค๋ก ์ด๋ฅผ ๋ฃ์ด์ฃผ์ง ์์ผ๋ฉด ์ญ์ฐธ์กฐ๊ฐ ๋ถ๊ฐํ๋ค.
Prefetch_related() ์ญ์ ์ ์ Hit์๋ก ์ฐธ์กฐ๊ด๊ณ์ธ Table๋ค์ ๋ฐ์ดํฐ๋ฅผ ํ๋ฒ์ ๊ฐ์ ธ์ฌ ์ ์๋๋ก ์ง์ํ๋ ํจ์๋ก ์ฃผ๋ก ์ญ์ฐธ์กฐ ์ํฉ์์ ๋ง์ด ์ฌ์ฉํ๋ค.
(๊ทธ๋ ๋ค๊ณ ๊ผญ ์ญ์ฐธ์กฐ์์๋ง ์ฐ๋๊ฑด ์๋๋ค. QuerySet์ 'query'๋ผ๋ ์์ฑ์ ํตํด ์ค์ sql query๋ฌธ์ ํ์ธ, ๋ณด๋ค ์ฑ๋ฅ์ด ์ข์ ๋ฐฉ์์ ์ ํํ ์ค ์์์ผ ํ๋ค).์์์ select_related() ์์ด๋ ์ ์ฐธ์กฐ๊ฐ ๊ฐ๋ฅํ๋ค๊ณ ํ์๋ค. ๋ฌผ๋ก ์ญ์ฐธ์กฐ์ ๊ฒฝ์ฐ๋ ๊ฐ๋ฅํ๋ค.
user = Users.objects.get(id=1) print(user.name) print(user.place_set.address)
prefetch_related()๋ฅผ ์ฌ์ฉํ์ง ์๋๋ค๋ ์ ๋ง ๋นผ๋ฉด ๋๊ฐ๋ค. ๋ค๋ง ์ด ๊ฒฝ์ฐ๋ ์ฑ๋ฅ์ ์ํด prefetch_related๋ฅผ ์ฌ์ฉํ๋ค๋ ๊ฒ๋ง์ด ์ฐจ์ด์ผ ๋ฟ์ด๋ค.
Database ์ค๊ณ์ N:N ๊ด๊ณ์ Table๋ค์ ์ค๊ฐTable์ ๋ง๋ค์ด N:N์ ํํผํด์ผ ํ๋ค๊ณ ๋ฐฐ์ ๋ค. ๊ทธ๋์ django์์ models ์์ ์ ์ค๊ฐtable์ฉ class ๋ฅผ ์ ์, ์์ชฝ id๋ฅผ FK๋ก ํ๋ ์์ฑ์ ๊ฐ๋๋ก ๋ชจ๋ธ๋ง ํ์๋ค. ์ด๋ฐ ์ค๊ฐ table์ ๋งค๋ฒ ๋ง๋ค์ด์ผ ํ ๊น? ์ด๋ฒ์ ์๊ฒ๋ ManyToManyField๋ ์ด๋ฅผ ์๋ํ ํด์ฃผ๋ ๊ธฐ๋ฅ์ด๋ค. ์๋ ์ฝ๋๋ฅผ ๋ณด์.
from django.db import models class Publication(models.Model): title = models.CharField(max_length=30) class Meta: db_table='publications' class Article(models.Model): headline = models.CharField(max_length=100) publications = models.ManyToManyField(Publication) class Meta: ordering ='articles'
Article๊ณผ Publication์ ์ค๊ฐtable๋ก articles_publications๋ฅผ ๋ง๋๋ ์ฝ๋์ด๋ค.
๊ทธ๋ฆฌ๊ณ Article.publications๋ฅผ ํตํด ์ค๊ฐํ ์ด๋ธ์ ์ด์ฉํ๋ค. ๊ฐ์ ๋ฃ์ ๋๋ ๋ ํ ์ด๋ธ์ ๊ฐ์ด ๋จผ์ ์์ฑ๋์ด ์์ด์ผ ํ๋ฏ๋ก ๋ณดํต ์๋์ ๊ฐ์ ์ ์ฐจ๋ก ์งํ๋๋ค.p1 = Publication.objects.create(title="hello") p2 = Publication.objects.create(title="hello2") a1 = Article.objects.create(headline="ํค๋๋ผ์ธ") ๋๋ Article(headline="ํค๋๋ผ์ธ").save() a1.publications.add(p1) a1.publications.add(p2) ๋๋ a1.publications.add(p1, p2)
a1์ Article๊ฐ์ฒด๋ก Create๋ Save๋ฅผ ํ๊ธฐ ์ ๊น์ง Table์ ์ถ๊ฐ๋์ง ์์ผ๋ฉฐ ์ด ์ํฉ์์ a1์ publications๋ฅผ ์ถ๊ฐํ๋ฉด error๊ฐ ๋ฐ์ํ๋ค.
์ ๊ณผ์ ์ ๊ฑฐ์ณ ์ค๊ฐํ ์ด๋ธ์ด ์ฑ์์ก๋ค. ์ฌ๊ธฐ์ ์ง๋ฌธ.... title์ด 'hello'์ธ Publication์ ๊ฐ๋ Article์ ์ฐพ์ผ๋ ค๋ฉด ์ด๋ป๊ฒ ํด์ผ ํ ๊น?
Article.objects.filter('publication__title' = 'hello')
'__'๋ queryset์์ ์ฌ์ฉํ๋ ์์ฝ์ด์ด๋ค. ์์ฑ์ ์ ๊ทผํ๋ ์ฉ๋๋ ๋ฌผ๋ก ๊ฐ์ข ์ฐ์ฐ(gt, lt, gte, lte...)์ ์ ์ฉํ ๋ ์ฌ์ฉํด์ผ ํ๋ฏ๋ก ์ตํ๋์
๋ง์ฝ ์์ฑํด์ผ ํ ์ค๊ฐ table์ด FK ์ธ์ ์ถ๊ฐ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ผ ํ๋ค๋ฉด models์์ ์ค๊ฐtable์ ์ ์ํ๊ณ ManyToManyField() argument ์ค 'through' ์ ์ค๊ฐtable class ์ด๋ฆ์ ๋ฃ์ผ๋ฉด ๋๋ค.
๋ค์์ ๋ table(User, Place)์ relate ํ๋ 'ratings' ๋ผ๋ table์ ManyToManyField๋ก ์ง์ ํ๋ code ์ด๋ค.class User(models.Model): name = models.CharField() email = models.CharField() user_place = models.ManyToManyField(Place, through=Rating) class Place(models.Model): address = models.CharField() class Rating(models.Model): user = models.ForeignKeyField(User, on_delete=models.CASCADE) place = models.ForeignKeyField('place.Place', on_delete=models.CASCADE) starpoint = models.FloatField() comments = models.Text() ...