Djano ORM Cookbook 항목을 생성·갱신·삭제하는 방법

이현준·2022년 4월 23일
0

Django

목록 보기
2/4

https://django-orm-cookbook-ko.readthedocs.io/en/latest/query.html

Django ORM Cookbook을 기반으로 직접 실습해보며 정리하는 글
실습용 모델은 (https://github.com/8percent/django-orm-cookbook-ko) 참고!

1. 여러 행을 한번에 생성하는 방법

bulk_create 메서드를 이용하면 여러개의 신규 객체를 한번에 저장 가능

Category.objects.bulk_create(
    [Category(name="God"),
     Category(name="Demi God"),
     Category(name="Mortal")]
     
Category.objects.all().count()
# 3

2. 저장된 행 복사해서 새로 저장

Django ORM에는 모델을 복사하는 메서드는 없지만, pk값을 None으로 지정하고 저장하면 새로운 행으로 저장됨

Category.objects.all()
# <QuerySet [<Category: Category object (1)>, <Category: Category object (2)>]>

category = Category.objects.first()
category.pk = None
category.save()

Category.objects.all()
# <QuerySet [<Category: Category object (1)>, <Category: Category object (2)>, <Category: Category object (3)>]>

3. 특정 모델의 항목이 하나만 생성되도록 강제 설정(싱글턴)

프로그램의 환경설정 기록, 공유자원에 대한 잠금 제어 등의 경우 특정 모델의 항목이 단 하나만 생성되도록 만들어야 할 때가 있다.

class Origin(models.Model):
    name = models.CharField(max_length=100)
    
	# save() 메서드 재정의
    def save(self, *args, **kwargs):
        if self.__class__.objects.count():
        	# pk 필드를 이미 존재하는 값으로 지정
            self.pk = self.__class__.objects.first().pk
        super().save(*args, **kwargs)

위의 코드를 통해 이미 객체가 있을 경우 해당 객체의 pk로 저장하게 하여 에러가 발생

4. 반정규화된 필드를 함께 갱신하는 법

class Category(models.Model):
    name = models.CharField(max_length=100)
    hero_count = models.PositiveIntegerField()
    villain_count = models.PositiveIntegerField()

class Hero(models.Model):
    name = models.CharField(max_length=100)
    category = models.ForeignKey(Category, on_delete=models.CASCADE)
    # ...

class Villain(models.Model):
    name = models.CharField(max_length=100)
    category = models.ForeignKey(Category, on_delete=models.CASCADE)
    # ...

Hero, Villain 모델의 항목을 새로 저장할 때 Caregory모델의 hero_countvillain_count 필드를 함께 갱신해야 할 때, 다음과 같이 save 메서드를 재정의

class Hero(models.Model):
    # ...

    def save(self, *args, **kwargs):
        if not self.pk:
            Category.objects.filter(pk=self.category_id).update(hero_count=F('hero_count')+1)
        super().save(*args, **kwargs)


class Villain(models.Model):
    # ...

    def save(self, *args, **kwargs):
        if not self.pk:
            Category.objects.filter(pk=self.category_id).update(villain_count=F('villain_count')+1)
        super().save(*args, **kwargs)

save 메서드를 재정의 할 때, self.category.hero_count +=1 과 같이 인스턴스의 값을 수정하지 않고 update 메서드로 데이터베이스의 갱신을 수행

5. TRUNCATE문

SQL의 TRUNCATE 문은 표에 저장된 모든 항목을 제거하는 명령, Django는 TRUNCATE와 같은 명령어를 제공하지 않지만 delete() 메서드를 활용

User.objects.all().delete()

DELETE FROM accounts_user

주로 아래 코드와 같이 모델의 classmethod로 추가해서 사용

class Category(models.Model):
    # ...

    @classmethod
    def truncate(cls):
        with connection.cursor() as cursor:
            cursor.execute(
                f'TRUNCATE TABLE {cls._meta.db_table}'
            )
  • @classmethod : 클래스 변수를 엑세스할 필요가 있을 때 주로 사용
#classmethod
class hello:
    num = 10

    @classmethod
    def calc(cls, x):
        return x + 10

print(hello.calc(10))
#결과
20

7. 시간 정보 저장

Django에는 시간 관련된 텍스트를 다른 양식으로 저장하는 다양한 방법이 있지만 가장 대표적인 두 유형에 대해서만 알아봄

1) parse_date

from django.utils.dateparse import parse_date
user = User.objects.get(id=1)
date_str = "2018-03-11"

temp_date = parse_date(date_str)
a1 = Article(headline="String converted to date", pub_date=temp_date, reporter=user)
a1.save()
a1.pub_date
# datetime.date(2018, 3, 11)

2) datetime

from datetime import datetime

date_str = "2018-03-11"
temp_date = datetime.strptime(date_str, "%Y-%m-%d").date()
a2 = Article(headline="String converted to date way 2", pub_date=temp_date, reporter=user)
a2.save()
a2.pub_date
# datetime.date(2018, 3, 11)
profile
기록, 정리하는 습관 만들기

0개의 댓글