Django ORM 단일 테이블 필드 및 메서드, 다중 데이터베이스 운영

ORM 개요

MVC 또는 MTV 프레임워크에서 ORM(Object-Relational Mapping)은 핵심 구성 요소로, 데이터 모델과 데이터베이스 간의 결합도를 낮추어 특정 데이터베이스에 의존하지 않고 모델을 설계할 수 있게 합니다. 간단한 설정만으로도 데이터베이스를 쉽게 교체할 수 있어 개발 효율성을 크게 향상시킵니다.

# SQL 테이블 생성
CREATE TABLE staff(
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(20),
    gender BIT DEFAULT 1,
    birth_date DATE,
    dept VARCHAR(20),
    salary DECIMAL(8,2) UNSIGNED
);

# SQL 레코드 조작
INSERT INTO staff (name,gender,birth_date,salary,dept) 
VALUES ("john",1,"1990-05-15",7500,"청소팀");

SELECT * FROM staff WHERE age=25;

UPDATE staff SET birth_date="1992-08-20" WHERE id=1;

DELETE FROM staff WHERE name="john";

# Django ORM 방식
class Staff(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)
    gender = models.BooleanField()
    birth_date = models.DateField()
    dept = models.CharField(max_length=32)
    salary = models.DecimalField(max_digits=8, decimal_places=2)

# ORM 객체 조작
staff = Staff(name="john", gender=True, birth_date="1990-05-15", dept="청소팀")
staff.save()

Staff.objects.filter(age=25)
Staff.objects.filter(id=1).update(birth_date="1992-08-20")
Staff.objects.filter(name="john").delete()

단일 테이블 조작

모델 정의

from django.db import models

class Publication(models.Model):
    id = models.AutoField(primary_key=True)
    title = models.CharField(max_length=32)
    status = models.BooleanField()
    publish_date = models.DateField()
    cost = models.DecimalField(max_digits=8, decimal_places=2)
    publisher = models.CharField(max_length=32)

필드 타입 및 파라미터

  • CharField: 문자열 필드, max_length 필수
  • IntegerField: 정수형 필드
  • FloatField: 부동소수점, max_digits와 decimal_places 지정
  • AutoField: 자동 증가 정수형 기본키
  • BooleanField: 불리언 값
  • TextField: 대용량 텍스트
  • EmailField: 이메일 형식 검증 문자열
  • DateField: 날짜 필드, auto_now와 auto_now_add 옵션
  • DateTimeField: 날짜시간 필드
  • TimeField: 시간 필드
  • ImageField/FileField: 파일 업로드 필드, upload_to 필수
  • URLField: URL 형식 검증
  • NullBooleanField: NULL 허용 불리언
  • SlugField: URL 친화적 문자열
  • IPAddressField: IP 주소 형식
  • CommaSeparatedIntegerField: 쉼표 구분 정수
  • SmallIntegerField/PositiveIntegerField: 다양한 정수 범위
  • BigIntegerField: 장정수형
  • UUIDField: UUID 형식

모델 필드 옵션

class UserProfile(models.Model):
    GENDER_CHOICES = ((1, '남성'), (2, '여성'), (0, '미지정'))
    
    user_id = models.AutoField(primary_key=True)
    username = models.CharField(max_length=32, unique=True)
    gender = models.IntegerField(default=1, choices=GENDER_CHOICES)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    
    class Meta:
        db_table = "user_profiles"
        unique_together = (("username", "gender"),)
        indexes = [("created_at", "updated_at")]
        verbose_name = "사용자 프로필"
        verbose_name_plural = "사용자 프로필들"

쿼리셋 메서드

메서드 기능 반환값 예제
all() 전체 조회 QuerySet Publication.objects.all()
filter(**kwargs) 조건 필터링 QuerySet Publication.objects.filter(cost=100)
get(**kwargs) 단일 객체 반환 Model 인스턴스 Publication.objects.get(title="Django 가이드")
exclude(**kwargs) 조건 제외 필터 QuerySet Publication.objects.exclude(status=False)
order_by(*field) 정렬 QuerySet Publication.objects.order_by("-id", "cost")
count() 개수 반환 int Publication.objects.filter(status=True).count()
first()/last() 첫/마지막 레코드 Model 인스턴스 Publication.objects.first()
exists() 데이터 존재 여부 bool Publication.objects.exists()
values(*field) 딕셔너리 형태 반환 QuerySet Publication.objects.values("title", "cost")
values_list(*field) 튜플 형태 반환 QuerySet Publication.objects.values_list("cost", flat=True)
distinct() 중복 제거 QuerySet Publication.objects.values("publisher").distinct()

다중 데이터베이스 운영

데이터베이스 설정

DATABASES = {
    "primary": {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'main_db',
        'USER': 'root',
        'PASSWORD': 'password123',
        'HOST': '192.168.1.10',
        'PORT': 3306,
    },
    "replica": {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'backup_db',
        'USER': 'root',
        'PASSWORD': 'password123',
        'HOST': '192.168.1.11',
        'PORT': 3306,
    }
}

라우터 클래스 구현

class DatabaseRouter:
    def db_for_read(self, model, **hints):
        if model._meta.app_label == 'analytics':
            return 'replica'
        return 'primary'
    
    def db_for_write(self, model, **hints):
        return 'primary'
    
    def allow_migrate(self, db, app_label, model_name=None, **hints):
        if db == 'replica':
            return False
        return True

설정 등록

DATABASE_ROUTERS = ['myproject.routers.DatabaseRouter']

수동 데이터베이스 선택

# 읽기 작업
data = MyModel.objects.using('replica').all()

# 쓰기 작업
obj = MyModel(title="새 항목")
obj.save(using='primary')

마이그레이션 명령

python manage.py migrate --database=primary
python manage.py migrate --database=replica

앱별 데이터베이스 분리 예제

# 라우터 확장
class AppDatabaseRouter:
    route_app_labels = {'auth', 'contenttypes'}
    
    def db_for_read(self, model, **hints):
        if model._meta.app_label in self.route_app_labels:
            return 'auth_db'
        return None
        
    def allow_migrate(self, db, app_label, model_name=None, **hints):
        if app_label in self.route_app_labels:
            return db == 'auth_db'
        elif db == 'auth_db':
            return False
        return None

주의사항

  • 다중 데이터베이스 간 외래키 관계는 지원되지 않음
  • 관련 테이블은 동일한 데이터베이스에 배치 권장
  • 트랜잭션 처리 시 데이터베이스 일관성 고려 필요

태그: Django django-orm Database multidb MySQL

7월 16일 16:12에 게시됨