반응형

데이터 타입: Oracle과 SQL Server을 비교하면서 이해하기

데이터 타입에 대해 이해하기 위해, Oracle과 SQL Server의 데이터 타입을 비교해보겠다. 이 두 데이터베이스 시스템은 업계에서 가장 널리 사용되는 RDBMS이지만, 각각의 특성과 사용 방법에는 중요한 차이가 있다.

 

개요

데이터베이스 설계에서 가장 중요한 결정 중 하나는 적절한 데이터 타입의 선택이다. 잘못된 데이터 타입 선택은 성능 저하, 저장 공간 낭비, 데이터 정확성 손실 등의 문제를 일으킬 수 있다. Oracle과 SQL Server는 각각 고유한 데이터 타입 체계를 가지고 있다.

 

데이터 타입 비교표

1. 숫자형 데이터 타입

분류 Oracle SQL Server 설명
정수 NUMBER(p,0) INT 정수형 데이터 (-2,147,483,648 ~ 2,147,483,647)
십진수 NUMBER(p,s) DECIMAL/NUMERIC(p,s) 정밀도(p)와 스케일(s)을 지정할 수 있는 숫자형
부동소수점 FLOAT FLOAT/REAL 부동 소수점 숫자
이진 부동소수점 BINARY_FLOAT - 32비트 부동 소수점
  BINARY_DOUBLE - 64비트 부동 소수점
통화 - MONEY 통화 데이터

 

2. 문자형 데이터 타입

분류 Oracle SQL Server 설명
가변 길이 VARCHAR2(n) VARCHAR(n) Oracle: 최대 4000바이트
SQL Server: 최대 8000바이트
고정 길이 CHAR(n) CHAR(n) Oracle: 최대 2000바이트
유니코드 가변 NVARCHAR2(n) NVARCHAR(n) 유니코드 문자열 저장
대용량 텍스트 CLOB TEXT Oracle: 최대 4GB
SQL Server: 최대 2GB

 

3. 날짜/시간형 데이터 타입

분류 Oracle SQL Server 설명
날짜+시간 DATE DATETIME Oracle: 날짜와 시간 포함
SQL Server: 1753-01-01 ~ 9999-12-31
고정밀 날짜/시간 TIMESTAMP DATETIME2 더 높은 정밀도 제공
날짜만 - DATE 날짜 정보만 저장
시간만 - TIME 시간 정보만 저장
기간 INTERVAL - 시간 간격 저장

 

4. 이진 데이터 타입

분류 Oracle SQL Server 설명
대용량 이진 BLOB IMAGE 대용량 이진 데이터 저장
소용량 이진 RAW VARBINARY 작은 크기의 이진 데이터
파일스트림 - FILESTREAM 파일 시스템에 저장되는 이진 데이터

 

주요 차이점 상세 분석

1. 문자열 처리의 차이

Oracle의 VARCHAR2와 SQL Server의 VARCHAR는 비슷해 보이지만 중요한 차이가 있다. Oracle에서는 VARCHAR2를 사용하는 것이 권장되는데, 이는 향후 VARCHAR의 구현이 변경될 수 있기 때문이다. 또한, Oracle의 VARCHAR2는 실제 저장된 문자열의 길이만큼만 저장 공간을 사용하지만, SQL Server의 VARCHAR는 지정된 길이만큼의 공간을 미리 할당한다.

2. 숫자 데이터 처리

Oracle은 NUMBER 타입 하나로 대부분의 숫자 데이터를 처리할 수 있다. 반면 SQL Server는 더 세분화된 숫자 타입(TINYINT, SMALLINT, INT, BIGINT 등)을 제공한다. 이는 각각의 장단점이 있다:

  • Oracle의 접근방식: 단순하고 유연하지만 저장 공간 최적화가 어려울 수 있음
  • SQL Server의 접근방식: 더 세밀한 제어가 가능하고 저장 공간을 최적화할 수 있지만, 설계 시 더 많은 고려가 필요함

 

3. 날짜와 시간 처리

날짜와 시간 처리에서도 두 시스템은 큰 차이를 보인다:

  • Oracle의 DATE는 기본적으로 시간 정보를 포함
  • SQL Server는 DATE와 TIME을 별도로 제공하여 더 명확한 구분이 가능
  • SQL Server의 DATETIME2는 Oracle의 TIMESTAMP와 비슷한 정밀도를 제공

 

실무에서의 선택 기준

데이터 타입을 선택할 때는 다음 사항을 고려해야 한다:

  1. 데이터의 특성
    • 저장할 데이터의 크기와 형식
    • 필요한 정밀도 수준
    • 예상되는 데이터 증가량
  2. 성능 요구사항
    • 검색 속도
    • 저장 공간 효율성
    • 인덱싱 전략
  3. 애플리케이션 요구사항
    • 다른 시스템과의 호환성
    • 향후 마이그레이션 가능성
    • 개발 팀의 익숙도

 

결론

Oracle과 SQL Server는 각각의 장단점을 가지고 있다. Oracle은 단순하고 일관된 데이터 타입 체계를 제공하는 반면, SQL Server는 더 세분화되고 명시적인 데이터 타입을 제공한다.

데이터베이스 설계자는 프로젝트의 요구사항, 성능 목표, 그리고 팀의 경험을 고려하여 적절한 데이터 타입을 선택해야 한다. 특히 대규모 시스템에서는 초기의 데이터 타입 선택이 향후 시스템의 성능과 확장성에 큰 영향을 미칠 수 있음을 항상 명심해야 한다.

마지막으로, 데이터 타입 선택은 한 번의 결정으로 끝나는 것이 아니라, 시스템의 요구사항 변화에 따라 지속적으로 검토하고 최적화해야 하는 과정임을 기억해야 한다.

반응형

'Database > SQL' 카테고리의 다른 글

[SQL] SQL 명령어 종류  (0) 2025.01.27
반응형

SQL은 관계형  데이터베이스를 다루는 데 있어 필수적인 도구이다. 본 글을 통해 SQL 명령어의 전체적인 구조를 이해할 수 있도록, SQL의 기본적인 명령어들을 알기 쉽게 정리해봤다.

 

SQL 명령어의 4 가지 종류

SQL 명령어는 용도에 따라 크게 네 가지로 분류된다. 각각의 특징과 주요 명령어들을 살펴보자.

 

1. 데이터 조작어(DML)

DML(Data Manipulation Language)은 데이터의 조회/입력/수정/삭제와 같이 실제 데이터를 다루는 데 사용되는 명령어들이다. 개발자들이 가장 자주 사용하는 명령어들이 여기에 속한다.

  • SELECT: 데이터 조회
  • INSERT: 새로운 데이터 삽입
  • UPDATE: 기존 데이터 수정
  • DELETE: 데이터 삭제
SELECT * FROM users;                    -- 데이터 조회
INSERT INTO users VALUES ('Kim', 30);   -- 데이터 삽입
UPDATE users SET age = 31 WHERE name = 'Kim';  -- 데이터 수정
DELETE FROM users WHERE name = 'Kim';   -- 데이터 삭제

 

2. 데이터 정의어(DDL)

DDL(Data Definition Language)은 데이터베이스의 구조를 정의하는 명령어들이다. 테이블을 생성하거나 수정할 때 사용된다.

  • CREATE: 새로운 데이터베이스 객체 생성
  • ALTER: 기존 데이터베이스 객체 구조 수정
  • DROP: 데이터베이스 객체 삭제
  • TRUNCATE: 테이블의 모든 데이터 삭제
  • RENAME: 객체 이름 변경
CREATE TABLE users (
    id INT PRIMARY KEY,
    name VARCHAR(50),
    age INT
);

ALTER TABLE users ADD COLUMN email VARCHAR(100);
DROP TABLE users;
TRUNCATE TABLE users;

 

3. 데이터 제어어(DCL)

DCL(Data Control Language)은 데이터베이스의 접근 권한을 관리한다. 주로 데이터베이스 관리자가 사용하는 명령어들이다.

  • GRANT: 사용자에게 권한 부여
  • REVOKE: 사용자의 권한 회수
GRANT SELECT ON users TO employee;
REVOKE SELECT ON users FROM employee;

 

4. 트랜잭션 제어어(TCL)

TCL(Transaction Control Language)은 데이터베이스의 트랜잭션을 관리한다. 데이터의 일관성을 유지하는 데 중요한 역할을 한다.

  • COMMIT: 트랜잭션의 작업 내용을 영구적으로 저장
  • ROLLBACK: 트랜잭션의 작업을 취소하고 이전 상태로 복구
  • SAVEPOINT: 트랜잭션 내에 저장점 설정
BEGIN TRANSACTION;
    UPDATE accounts SET balance = balance - 1000 WHERE id = 1;
    UPDATE accounts SET balance = balance + 1000 WHERE id = 2;
COMMIT;

 

 

실무에서 자주 사용되는 조합

실제 개발 환경에서는 여러 명령어를 조합해서 사용하는 경우가 많다. 다음은 자주 사용되는 패턴의 예시이다:

-- 새로운 테이블 생성
CREATE TABLE employees (
    id INT PRIMARY KEY,
    name VARCHAR(50),
    department VARCHAR(50)
);

-- 데이터 삽입
INSERT INTO employees (id, name, department)
VALUES (1, 'Kim', 'IT'), (2, 'Lee', 'HR');

-- 데이터 조회 및 수정
SELECT * FROM employees WHERE department = 'IT';
UPDATE employees SET department = 'Development' WHERE department = 'IT';

 

마치며

SQL은 데이터베이스를 다루는 데 있어 가장 기본이 되는 도구이다. 위의 네 가지 유형의 명령어들을 잘 이해하고 있다면, 대부분의 데이터베이스 작업을 수행할 수 있다. 특히 처음에는 DML 명령어들을 중점적으로 학습하시는 것이 추천된다.

반응형

'Database > SQL' 카테고리의 다른 글

[SQL] SQL 데이터 타입  (0) 2025.01.27
반응형

Django의 Class-Based Views(CBV)는 객체 지향적인 방식으로 뷰를 구현할 수 있게 해주며, 코드의 재사용성과 확장성을 크게 향상시켜주는 강력한 기능이다. CBV의 내부 동작 방식과 주요 메서드들의 실행 흐름을 자세히 살펴보려고 한다.

 

CBV의 기본 구조

사용자가 웹 브라우저에서 요청을 보내면, Django는 URL 패턴을 통해 해당 요청을 적절한 CBV로 라우팅한다.
Django CBV는 View 클래스as_view() 클래스 메서드를 통해 URL 패턴에 연결되며, 이는 실제로 뷰 함수로 변환된다. 관련해서는 아래 포스팅을 참고하면 된다.

https://comgu.tistory.com/entry/Django-View-클래스의-asview-메서드

 

[Django] View 클래스의 as_view() 메서드

Django를 사용시 as_view() 메서드를 자주 마주치게 된다. URL 설정에서 클래스 기반 뷰(Class-based View)를 연결할 때 항상 이 메서드를 호출한다. 이 메서드가 어떤 일을 하는지, 그리고 왜 필요한지 알

comgu.tistory.com

뷰 함수가 실행되면, CBV 내부에서는 일련의 메서드들이 순차적으로 실행되면서 요청을 처리한다.

초기 설정 단계: setup()

모든 요청은 먼저 setup() 메서드를 통과한다. setup()은 가장 먼저 실행되며, 뷰 인스턴스에 필요한 기본 속성들을 설정한다. 여기서 request 객체와 URL로부터 전달받은 인자들이 인스턴스 변수로 저장된다.

def setup(self, request, *args, **kwargs):
    """
    모든 요청 처리의 시작점
    request 객체와 URL 파라미터들을 클래스 속성으로 설정
    """
    self.request = request
    self.args = args
    self.kwargs = kwargs

Dispatch 단계: dispatch()

그 다음으로 dispatch() 메서드가 호출된다. 이 메서드는 트래픽 관리자와 같은 역할을 하여, HTTP 메서드에 따라 적절한 핸들러 메서드를 호출한다. 예를 들어, GET 요청이 들어오면 get() 메서드를, POST 요청이 들어오면 post() 메서드를 실행한다.

def dispatch(self, request, *args, **kwargs):
    """
    요청의 HTTP 메서드를 확인하고 적절한 핸들러로 라우팅
    """
    if request.method.lower() in self.http_method_names:
        handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
    else:
        handler = self.http_method_not_allowed
    return handler(request, *args, **kwargs)

 

이후 단계들은 View 클래스의 용도에 따른 구현이 매우 다양하다. 먼저 generic view들부터 살펴본다.

 

Generic CBV

Django의 Generic CBV들은 웹 애플리케이션 개발에서 자주 사용되는 일반적인 패턴들을 추상화하여 제공하며, 일반적인 CRUD 작업을 쉽게 처리할 수 있도록 추가적인 메서드들을 제공한다. 대표적인 generic view들을 살펴보자.

View

최상위 CBV 클래스인 View도 generic view에 해당된다. 모든 View는 이 View 클래스를 상속한다. as_view() 클래스 메서드로 URL 패턴에 연결되며, dispatch() 메서드를 통해 요청을 적절한 핸들러로 라우팅한다.

TemplateView

TemplateView는 주로 정적인 콘텐츠를 보여주는 데 사용되며, 템플릿을 렌더링하는 것이 주요 목적이다.

  • get_context_data() 메소드를 통해 템플릿에 데이터를 전달할 수 있다.
  • GET 요청을 자동으로 처리한다(get() 메소드)

RedirectView

RedirectView는 들어오는 요청을 다른 URL로 리다이렉트하는 기능을 수행한다. URL 변경, 레거시 URL 처리, 조건부 리다이렉션 등 다양한 시나리오에서 활용된다.

주요 속성:

  • url: 리다이렉트할 URL
  • pattern_name: 리다이렉트할 URL 패턴
  • query_string: URL 파라미터 유지 여부

ListView

ListView는 모델의 객체 목록을 표시하는데 사용된다. (ex. 블로그 포스트 목록이나 상품 카탈로그 등을 구현)

  • 객체 목록을 표시한다.
  • get_queryset()이 핵심 메서드이다.
  • paginate_by 설정으로 페이지네이션이 가능하다.

DetailView

DetailView는 단일 객체의 상세 정보를 표시하는데 사용된다.

  • 단일 객체의 상세 정보를 표시한다.
  • get_object()가 핵심 메서드이다.
  • 객체가 없을 경우 404 에러로 처리한다.

FormView

FormView는 폼 처리를 위한 generic view로, GET 요청과 POST 요청에 따라 다른 흐름을 가진다.

  • 폼 처리 전용 뷰이다.
  • form_valid(), form_invalid()가 핵심 메서드이다.
  • success_url 처리가 중요하다.

CreateView

CreateView는 모델 객체 생성을 담당한다.

  • 자동으로 모델 폼 생성한다.
  • GET 요청시 빈 폼을 표시하며, POST 요청시 폼 데이터를 처리 및 저장한다.
  • 유효성 검사 통과 시 실행되는 form_valid()로 객체 저장 전 추가 처리를 할 수 있다.
  • 성공 시 success_url로 리다이렉트된다.
  • get_context_data()로 템플릿에 추가 컨텍스트 데이터 전달이 가능하다.

UpdateView

UpdateView는 모델 객체 수정을 담당한다.

  • 자동으로 객체를 조회하여 폼에 데이터를 채운다.
  • GET 요청시 기존 데이터가 채워진 폼을 표시하며, POST 요청시 수정된 데이터를 처리 및 저장한다.
  • pkslug로 객체를 식별한다.
  • CreateView와 거의 동일한 인터페이스를 제공한다.

DeleteView

DeleteView는 모델 객체 삭제를 담당한다.

  • GET 요청시 삭제 확인 페이지를 표시하며, POST 요청시 실제 객체의 삭제를 수행한다.
  • success_url로 삭제 후 리다이렉트된다.
  • pk 또는 slug로 삭제할 객체를 식별한다.

 

 

CBV 주요 메서드

CBV에서 중요한 메서드이거나, CBV를 커스터마이징할 때 가장 자주 오버라이드되는 메서드들의 용도를 살펴보자:

dispatch()

모든 요청에 대한 선처리가 필요할 때 사용한다.

class BookView(View):
    def dispatch(self, request, *args, **kwargs):
        # 모든 요청 처리 전에 실행
        if not request.user.is_authenticated:
            return redirect('login')
        return super().dispatch(request, *args, **kwargs)

get_queryset()

데이터베이스에서 객체를 조회하는 방식을 커스터마이징할 때 사용한다.

class BookListView(ListView):
    model = Book
    
    def get_queryset(self):
        # 출판된 책만 필터링
        return Book.objects.filter(is_published=True)

get_context_data()

템플릿에 전달할 컨텍스트 데이터를 추가하거나 수정할 때 사용한다.

class BookDetailView(DetailView):
    model = Book
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        # 추가 컨텍스트 데이터 전달
        context['related_books'] = Book.objects.filter(
            category=self.object.category
        ).exclude(id=self.object.id)[:3]
        return context

get_object()

단일 객체를 조회하는 방식을 커스터마이징할 때 사용한다.

class BookDetailView(DetailView):
    model = Book
    
    def get_object(self, queryset=None):
        obj = super().get_object(queryset)
        # 조회수 증가
        obj.views += 1
        obj.save()
        return obj

form_valid() / form_invalid()

form_valid(): 폼 데이터가 유효할 때 실행된다. 이 함수는 post() 함수의 내부에서 호출된다.

form_invalid(): 폼이 유효하지 않을 때 실행된다. 이 함수 역시도 post() 함수의 내부에서 호출된다.

class BookCreateView(CreateView):
    model = Book
    form_class = BookForm
    success_url = reverse_lazy('book-list')
    
    def form_valid(self, form):
        # 폼이 유효할 때 실행
        form.instance.author = self.request.user
        return super().form_valid(form)
    
    def form_invalid(self, form):
        # 폼이 유효하지 않을 때 실행
        messages.error(self.request, "입력 정보를 확인해주세요.")
        return super().form_invalid(form)

get() / post() 등 HTTP 메소드 별 핸들러

HTTP 메서드별 처리 로직을 직접 정의할 때 사용한다.

class BookView(View):
    def get(self, request, *args, **kwargs):
        # GET 요청 처리
        return render(request, 'book_detail.html', {'book': self.get_object()})
    
    def post(self, request, *args, **kwargs):
        # POST 요청 처리
        book = self.get_object()
        book.likes += 1
        book.save()
        return redirect('book-detail', pk=book.pk)

get_form_class()

동적으로 폼 클래스를 결정할 때 사용한다. 오버라이드 되지 않는다면, 기본적으로는 뷰의 form_class 속성에 할당된 폼 클래스가 반환된다.

class BookCreateView(CreateView):
    model = Book
    
    def get_form_class(self):
        # 사용자 권한에 따라 다른 폼 반환
        if self.request.user.is_staff:
            return AdminBookForm
        return UserBookForm

get_success_url()

요청 처리를 성공힌 후 리다이렉트할 URL을 동적으로 생성할 때 사용한다.

class BookUpdateView(UpdateView):
    model = Book
    form_class = BookForm
    
    def get_success_url(self):
        # 수정 완료 후 리다이렉트할 URL 동적 생성
        messages.success(self.request, "책 정보가 수정되었습니다.")
        return reverse('book-detail', kwargs={'pk': self.object.pk})

get_template_names()

조건에 따라 다른 템플릿을 사용해야 할 때 사용한다.

class BookDetailView(DetailView):
    model = Book
    
    def get_template_names(self):
        # 조건에 따라 다른 템플릿 사용
        if self.request.user.is_mobile:
            return ['books/mobile/book_detail.html']
        return ['books/book_detail.html']

get_initial()

폼의 초기값을 동적으로 설정할 때 사용한다.

class BookCreateView(CreateView):
    model = Book
    form_class = BookForm
    
    def get_initial(self):
        # 폼의 초기값 설정
        initial = super().get_initial()
        initial['category'] = self.request.GET.get('category')
        initial['author'] = self.request.user
        return initial

get_form_kwargs()

폼 인스턴스 생성 시 추가 인자를 전달할 때 사용한다. 

class BookCreateView(CreateView):
    model = Book
    form_class = BookForm
    
    def get_form_kwargs(self):
        # 폼 인스턴스 생성 시 추가 인자 전달
        kwargs = super().get_form_kwargs()
        kwargs['user'] = self.request.user
        return kwargs

get_form()

get_form_class()으로부터 얻은 폼 클래스의 인스턴스를 생성한다. 인스턴스 생성시, get_form_kwargs()에서 얻은 kwargs 딕셔너리가 사용된다.

get_context_object_name()

템플릿에서 사용할 객체나 리스트의 변수명을 커스터마이징할 때 사용한다.

class BookListView(ListView):
    model = Book
    
    def get_context_object_name(self, object_list):
        # 템플릿에서 사용할 컨텍스트 변수명 설정
        return 'book_list_custom'

 

 

사용자 정의 뷰

실제 프로젝트에서는 제네릭 뷰만으로 해결할 수 없는 복잡한 요구사항들이 있다. 이러한 경우 사용자 정의 뷰를 만들어 사용한다.

사용자 정의 뷰의 특징

  • HTTP 메서드별로 별도의 처리 로직을 구현할 수 있다.
  • Mixin을 통해 공통 기능을 재사용할 수 있다.
  • 요청과 응답을 세밀하게 제어할 수 있다.

 

1. 기본적인 사용자 정의 뷰 예시

from django.views import View
from django.shortcuts import render

class SimpleView(View):
    def get(self, request, *args, **kwargs):
        context = {'message': 'Hello, World!'}
        return render(request, 'simple.html', context)
        
    def post(self, request, *args, **kwargs):
        data = request.POST.get('data')
        # 데이터 처리 로직
        return redirect('success-page')

2. Mixin을 활용한 뷰 예시

from django.contrib.auth.mixins import LoginRequiredMixin

class LogMixin:
    def dispatch(self, request, *args, **kwargs):
        print(f"접근 시간: {timezone.now()}")
        return super().dispatch(request, *args, **kwargs)

class DashboardView(LoginRequiredMixin, LogMixin, View):
    def get(self, request, *args, **kwargs):
        user_data = {
            'username': request.user.username,
            'last_login': request.user.last_login
        }
        return render(request, 'dashboard.html', user_data)

3. API 응답을 위한 뷰 예시

from django.http import JsonResponse

class UserAPIView(View):
    def get(self, request, *args, **kwargs):
        user = request.user
        data = {
            'id': user.id,
            'username': user.username,
            'email': user.email
        }
        return JsonResponse(data)

 

 

결론

Django CBV는 처음 배울 때는 복잡하지만, 각 메서드의 역할과 실행 순서를 이해하면 유용한 도구가 된다. Generic View는 일반적인 웹 개발 패턴을 쉽게 구현할 수 있게 해주고, 사용자 정의 뷰는 통해 복잡한 비즈니스 요구사항을 처리할 수 있게 해준다.

반응형

'Django' 카테고리의 다른 글

[Django] CreateView  (0) 2025.02.04
[Django] PostgreSQL 연동하기  (0) 2025.02.04
[Django] 템플릿에 Bootstrap 적용하기  (0) 2025.01.24
[Django] Messages Framework  (0) 2025.01.23
[Django] 사용자 모델 구현 방법 비교  (0) 2025.01.22
반응형

Django로 웹 애플리케이션을 개발할 때 중요한 부분 중 하나가 사용자 인터페이스이다.

Bootstrap은 반응형 웹 디자인을 쉽게 구현할 수 있게 해주는 프론트엔드 프레임워크이다. Django 템플릿에 Bootstrap을 효과적으로 적용하는 방법을 단계별로 알아본다.

 

1. Bootstrap 설정하기

먼저 프로젝트의 기본 템플릿(일반적으로 base.html)에 Bootstrap의 필수 파일들을 추가해야 한다. CDN을 통해 Bootstrap 파일을 가져오는 것이 가장 간단한 방법이다.

<!DOCTYPE html>
<html>
<head>
    <!-- Bootstrap CSS -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
    
    <!-- 선택사항: Bootstrap 아이콘 -->
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.0/font/bootstrap-icons.css">
    
    <title>{% block title %}{% endblock %}</title>
</head>
<body>
    {% block content %}
    {% endblock %}

    <!-- Bootstrap JS와 Popper.js -->
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>

 

2. Django 정적 파일 처리 설정

Django에서 정적 파일을 올바르게 처리하기 위해 settings.py 파일에 다음 설정을 추가한다.

STATIC_URL = 'static/'
STATICFILES_DIRS = [
    BASE_DIR / 'static',
]

이 설정은 프로젝트의 정적 파일(CSS, JavaScript, 이미지 등)을 관리하는 데 필요하다.

CDN을 통해 Bootstrap을 가져오는 경우에도, Bootstrap 관련 static 파일이 필요한 경우가 아래와 같이 있다:

  • 커스텀 Bootstrap 테마나 수정된 스타일
  • Bootstrap의 기본 스타일을 덮어쓰는 CSS
  • Bootstrap과 함께 사용할 추가 JavaScript

또한 CDN이 장애를 일으키는 경우를 대비해 로컬 Bootstrap 파일을 사용하는 경우에도 static 폴더를 사용할 수 있다.

 

3. Bootstrap 컴포넌트 활용하기

Bootstrap의 강력한 기능 중 하나는 미리 디자인된 다양한 컴포넌트를 제공한다는 것이다.

다음은 Bootstrap 컴포넌트를 활용한 템플릿 예시이다.

{% extends 'base.html' %}

{% block content %}
<div class="container mt-4">
    <div class="row">
        <div class="col-md-8">
            <div class="card">
                <div class="card-body">
                    <h5 class="card-title">게시글 제목</h5>
                    <p class="card-text">게시글 내용입니다.</p>
                    <a href="#" class="btn btn-primary">자세히 보기</a>
                </div>
            </div>
        </div>
        
        <div class="col-md-4">
            <div class="list-group">
                <a href="#" class="list-group-item list-group-item-action">메뉴 1</a>
                <a href="#" class="list-group-item list-group-item-action">메뉴 2</a>
            </div>
        </div>
    </div>
</div>
{% endblock %}

내비게이션 바 예시

<nav class="navbar navbar-expand-lg navbar-light bg-light">
    <div class="container-fluid">
        <a class="navbar-brand" href="#">로고</a>
        <div class="collapse navbar-collapse">
            <ul class="navbar-nav">
                <li class="nav-item">
                    <a class="nav-link" href="#">홈</a>
                </li>
            </ul>
        </div>
    </div>
</nav>

그리드 시스템 예시

<div class="container">
    <div class="row">
        <div class="col-md-8">메인 콘텐츠</div>
        <div class="col-md-4">사이드바</div>
    </div>
</div>

카드 예시

<div class="card">
    <img src="..." class="card-img-top" alt="...">
    <div class="card-body">
        <h5 class="card-title">제목</h5>
        <p class="card-text">내용</p>
    </div>
</div>

 

4. 폼 스타일링

Django 폼에 Bootstrap 스타일을 적용하는 것은 특히 중요하다. 사용자 입력을 받는 폼은 웹 애플리케이션의 핵심 부분이기 때문이다.

<form method="post" class="mt-3">
    {% csrf_token %}
    {% for field in form %}
    <div class="mb-3">
        <label for="{{ field.id_for_label }}" class="form-label">{{ field.label }}</label>
        {{ field|add_class:"form-control" }}
        {% if field.help_text %}
        <small class="form-text text-muted">{{ field.help_text }}</small>
        {% endif %}
        {% if field.errors %}
        <div class="alert alert-danger">
            {{ field.errors }}
        </div>
        {% endif %}
    </div>
    {% endfor %}
    <button type="submit" class="btn btn-primary">제출</button>
</form>

 

5. 추가 팁과 Best Practice

  1. 일관성 유지: 프로젝트 전체에서 동일한 Bootstrap 버전과 스타일링 패턴을 사용하기.
  2. 커스텀 스타일: Bootstrap의 기본 스타일을 커스터마이즈하려면 별도의 CSS 파일을 만들어 관리하기.
  3. 반응형 디자인: Bootstrap의 그리드 시스템을 활용하여 모바일 친화적인 레이아웃을 만들기.
  4. 성능 최적화: 프로덕션 환경에서는 Bootstrap 파일을 로컬에서 제공하고, 필요한 컴포넌트만 포함하기.

 

결론

Django와 Bootstrap의 조합은 강력하면서도 유지보수가 쉬운 웹 애플리케이션을 만들 수 있게 해준다. Bootstrap의 다양한 컴포넌트와 유틸리티 클래스를 활용하면 전문적인 디자인을 쉽게 구현할 수 있다.

반응형
반응형

https://www.acmicpc.net/problem/11725

트리의 각 노드 정보가 주어질 때, 각 노드의 부모가 무엇인지 알아내는 프로그램을 작성해야 한다.

 

트리의 자식 노드 정보를 저장하기 위해 defaultdict(list)를 사용했다. defaultdict는 key가 없는 경우 자동으로 기본값을 지정해주는 딕셔너리이다.

부모 노드의 정보를 저장하기 위해서는 일반적인 list를 사용했다. 루트인 1번 노드부터 시작해서, 자식 노드를 순회하는 DFS를 통해 부모 노드 정보를 해당 list에 저장하도록 했다.

 

정답 코드

import sys
from collections import defaultdict

sys.setrecursionlimit(10**6)
tree = defaultdict(list)

n = int(next(sys.stdin))
for line in sys.stdin:
    a, b = map(int, line.split())
    tree[a].append(b) # 키가 없어도 자동으로 빈 리스트를 생성
    tree[b].append(a) # 키가 없어도 자동으로 빈 리스트를 생성

parent = [0] * (n + 1)


def dfs(node):
    for child in tree[node]:
        if parent[child] == 0:
            parent[child] = node
            dfs(child)


dfs(1)
sys.stdout.write("\n".join(map(str, parent[2:])))

 

파이썬에서 재귀 호출의 깊이는 기본값인 1,000이고, 이를 초과하면 RecursionError가 발생한다. 해당 조건을 완화하기 위해 sys.setrecursionlimit(10**6)으로 재귀 호출의 깊이값을 변경해줘야 한다.

 

BFS(큐 사용)를 통해서도 문제를 해결할 수 있지만, 시도하지는 않았다.

반응형
반응형

Django Messages Framework는 사용자에게 일회성 알림 메시지를 표시할 수 있는 기능이다. 이 프레임워크를 사용하면 작업 완료, 오류 발생, 경고 등 다양한 상황에서 사용자에게 피드백을 제공할 수 있다.

 

설정하기

Messages Framework를 사용하기 위해서는 다음 설정이 필요하다:

# settings.py
INSTALLED_APPS = [
    'django.contrib.messages',
    # ...
]

MIDDLEWARE = [
    'django.contrib.messages.middleware.MessageMiddleware',
    # ...
]

 

메시지 레벨

Django는 5가지 종류의 메시지 레벨을 제공한다:

from django.contrib import messages

messages.success(request, '성공 메시지')  # 초록색 알림
messages.error(request, '오류 메시지')    # 빨간색 알림
messages.warning(request, '경고 메시지')  # 노란색 알림
messages.info(request, '정보 메시지')     # 파란색 알림
messages.debug(request, '디버그 메시지')  # 회색 알림

 

View에서 사용하기

실제 뷰에서는 다음과 같이 사용할 수 있다:

from django.shortcuts import render

def my_view(request):
    messages.info(request, '처리가 완료되었습니다.')
    return render(request, 'my_template.html')
from django.contrib import messages
from django.shortcuts import redirect

def user_profile(request):
    if request.method == 'POST':
        try:
            # 프로필 업데이트 로직
            user.save()
            messages.success(request, '프로필이 성공적으로 업데이트되었습니다.')
            return redirect('profile')
        except Exception as e:
            messages.error(request, f'오류가 발생했습니다: {str(e)}')
            return redirect('profile')
            
def create_post(request):
    form = PostForm(request.POST)
    if form.is_valid():
        form.save()
        messages.success(request, '포스트가 생성되었습니다.')
    else:
        messages.error(request, '입력 값을 확인해주세요.')
    return redirect('post-list')

redirect()의 URL을 처리하는 view함수가 반환하는 템플릿 파일 안에서, messages.sucess()messages.error() 등의 에러메시지가 messages로 접근 가능하다.

그 이유는 Messages framework는 한 view에서 설정한 메시지를 다음 요청의 템플릿에서도 접근할 수 있도록 설계되어 있기 때문이다. 이것이 가능한 이유는:

  1. Messages framework가 메시지를 세션에 저장하기 때문이다.
  2. 메시지는 한 번 표시되고 나면 자동으로 세션에서 삭제된다. (아래 내용 참고)

 

템플릿에서 표시하기

메시지를 템플릿에서 표시하는 방법이다:

{% if messages %}
<ul class="messages">
    {% for message in messages %}
    <div class="alert alert-{{ message.tags }}">
        {{ message }}
    </div>
    {% endfor %}
</ul>
{% endif %}

메시지는 한 번 표시된 후 자동으로 세션에서 삭제된다 (정확히는 템플릿에서 messages 변수를 iterate할 때 삭제된다).

따라서 동일한 요청 내에서 다시 messages를 iterate하면 메시지가 없다. 이는 같은 메시지가 여러 번 표시되는 것을 방지하기 위한 설계이다.

 

추가 기능

extra_tags: 추가 CSS 클래스 지정 가능.

messages.success(request, '저장되었습니다', extra_tags='custom-class')

 

실제 사용 팁

  1. 주요 CRUD 작업 후에는 피드백을 제공하는 것이 좋은데, 이때 messages는 좋은 도구가 될 수 있다.
  2. 오류 메시지는 구체적으로 작성하되, 보안에 민감한 정보는 제외해야 한다.
  3. Bootstrap이나 Tailwind CSS와 함께 사용하면 멋진 UI를 만들 수 있다.

 

마무리

Django Messages Framework를 활용하면 사용자 경험을 크게 향상시킬 수 있다. 적절한 피드백은 웹 애플리케이션의 사용성을 높이는 핵심 요소이기 때문이다.

반응형
반응형

https://www.acmicpc.net/problem/18258

최대 2,000,000개까지 입력되는 다양한 명령문에 대해, 큐 관련 동작을 수행하는 문제이다.

명령의 수가 매우 많기 때문에, 비효율적인 자료구조나 로직을 사용하면 페널티가 있을 수 있다.

 

먼저, 큐를 구현하기 위해 일반적인 list를 사용해보았다. 그러나 아래처럼 시간 초과가 발생하게 되었다.

시간 초과 발생 코드

import sys

queue = []
results = []
commands = sys.stdin.readlines()[1:]
for command in commands:
    cmd_x = command.split()
    cmd = cmd_x[0]
    if cmd == "push":
        queue.append(cmd_x[1])
    elif cmd == "pop":
        results.append(queue.pop(0) if queue else "-1")
    elif cmd == "size":
        results.append(str(len(queue)))
    elif cmd == "empty":
        results.append("0" if queue else "1")
    elif cmd == "front":
        results.append(queue[0] if queue else "-1")
    elif cmd == "back":
        results.append(queue[-1] if queue else "-1")

sys.stdout.write("\n".join(results))

시간 초과의 원인은 바로 queue.pop(0) 부분에 있다.

pop(0) 연산은 list의 첫 번째 요소를 제거할 때 O(n)의 시간 복잡도를 가지므로, 입력 데이터가 많을 경우 시간 초과가 발생할 수 있다.

List의 내부 동작 방식

파이선의 list는 동적 배열(dynamic array)로 구현되어 있다. 이는 요소들이 메모리상에 연속적으로 저장된다는 뜻이다.

pop(0)은 리스트의 맨 앞 요소를 제거한 뒤, 남은 요소들을 한 칸씩 앞으로 이동시킨다.

즉, 리스트의 길이가 n일 때,

  1. 첫 번째 요소를 제거.
  2. 모든 나머지 요소들을 왼쪽으로 한 칸씩 이동.

이러한 이동 과정은 요소 수에 비례하므로, 시간 복잡도가 O(n)이다.

 

List의 위와 같은 성능적 한계를 피하기 위해, collectionsdeque를 사용한다.

deque는 양쪽에서의 삽입과 삭제를 O(1)로 지원하도록 설계된 자료구조이다. 내부적으로는 이중 연결 리스트로 구현되어 있기 때문에 요소 이동이 필요하지 않다. 따라서 큐를 구현할 때 deque를 사용하는 것이 성능 면에서 훨씬 효율적이다.

queue에서의 pop(0)을 대신하여, deque에서는 popleft()를 사용하면 된다.

정답 코드

import sys
from collections import deque

queue = deque()
results = []
commands = sys.stdin.readlines()[1:]

for command in commands:
    cmd_x = command.split()
    cmd = cmd_x[0]
    if cmd == "push":
        queue.append(cmd_x[1])
    elif cmd == "pop":
        results.append(queue.popleft() if queue else "-1")
    elif cmd == "size":
        results.append(str(len(queue)))
    elif cmd == "empty":
        results.append("0" if queue else "1")
    elif cmd == "front":
        results.append(queue[0] if queue else "-1")
    elif cmd == "back":
        results.append(queue[-1] if queue else "-1")

sys.stdout.write("\n".join(results))

성능이 합격 조건에 충족된 것을 확인할 수 있다.

반응형
반응형

Django로 웹 서비스를 개발할 때 가장 중요한 결정 중 하나는 사용자 모델을 어떻게 구현할 것인가이다. Django는 세 가지 주요 방식을 제공하는데, 각 방식의 특징과 장단점을 살펴보고, 어떤 상황에서 어떤 방식을 선택해야 하는지 알아본다.

 

1. 기본 User 모델 사용하기

Django의 django.contrib.auth.models에 정의된 기본 User 모델을 사용하는 방식이다.

특징

  • username, password, email, first_name, last_name 등 기본적인 필드들이 미리 구현되어 있다.
  • 인증 관련 메서드들이 모두 구현되어 있어 즉시 사용 가능하다.
  • admin 페이지와의 통합이 즉시 가능하다.
  • UserManager가 이미 구현되어 있어 별도 처리가 불필요하다.

장점

  • 가장 빠르게 구현할 수 있다.
  • Django의 기본 인증 시스템과 완벽하게 호환된다.
  • 추가 설정 없이 바로 사용할 수 있다.

단점

  • 커스터마이징이 제한적이다.
  • 기본 필드를 수정하기 어렵다.
  • username을 필수로 사용해야 한다.

추가 정보 관리: User Profile 패턴

기본 User 모델을 사용하면서 추가 정보를 관리해야 할 때는 OneToOneField를 사용한 Profile 모델(모델명은 자유롭게 명명 가능)을 생성하는 것이 일반적이다. 이를 'User Profile' 패턴이라고 한다.

아래 예시와 같이, User에 대한 추가 정보를 별도의 Profile 모델에 저장할 수 있다. Profile은 새로운 User가 생성되면 자동으로 생성된다.

from django.contrib.auth.models import User
from django.db import models
from django.db.models.signals import post_save
from django.dispatch import receiver

class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    birth_date = models.DateField(null=True, blank=True)
    phone_number = models.CharField(max_length=15, blank=True)
    address = models.CharField(max_length=255, blank=True)
    
    def __str__(self):
        return f'{self.user.username} Profile'

# User 생성 시 자동으로 Profile 생성
@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
    if created:
        Profile.objects.create(user=instance)

@receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
    instance.profile.save()

이 패턴의 장단점은 다음과 같다:

장점

  • 기존 User 모델을 그대로 사용할 수 있다.
  • 추가 정보만 별도 테이블로 관리할 수 있다.
  • User 모델의 기본 기능을 그대로 활용할 수 있다.
  • Profile 모델의 수정이 용이하다.

단점

  • 추가 쿼리가 발생할 수 있다.
  • Profile 데이터 접근 시 user.profile과 같이 추가 참조가 필요하다.
  • 데이터 일관성을 위한 관리가 필요하다.

 

2. AbstractUser 상속하기

Django의 django.contrib.auth.models에 정의된 AbstractUser를 사용하는 방식이다.

특징

  • 기본 User 모델의 모든 필드와 메서드를 상속받는다.
  • 기존 필드를 수정하고 새로운 필드를 추가할 수 있다.
  • 기본 UserManager를 상속받아 사용하되, 필요한 경우 확장 가능하다.

장점

  • 기본 User 모델의 모든 기능을 유지하면서 확장할 수 있다.
  • admin 페이지와의 통합이 유지된다.
  • 기존 인증 시스템을 그대로 사용할 수 있다.

단점

  • username이 여전히 필수 필드이다.
  • 데이터베이스 구조가 기본 User 모델과 비슷하게 유지된다.
  • 인증 로직을 완전히 커스터마이징하기는 어렵다.
  • 프로젝트 시작 시점에 설정해야 한다.

구현 예시

from django.contrib.auth.models import AbstractUser

class CustomUser(AbstractUser):
	def create_user(self, username, email=None, password=None, **extra_fields):
       	# 커스텀 로직 추가
        return super().create_user(username, email, password, **extra_fields)

    birth_date = models.DateField(null=True, blank=True)
    phone_number = models.CharField(max_length=15, blank=True)

 

3. AbstractBaseUser 상속하기

가장 유연한 커스터마이징이 가능한 방식이다.

특징

  • 가장 기본적인 인증 기능만 제공한다.
  • 모든 필드와 메서드를 직접 정의해야 한다.
  • BaseUserManager도 함께 구현해야 한다.
    • create_user()create_superuser() 메서드를 반드시 구현 필요하다.
    • 비밀번호 해싱, 이메일 정규화 등을 직접 처리해야 한다.
    • 사용자 생성 로직을 완전히 제어 가능하다.

장점

  • 완전한 커스터마이징이 가능하다.
  • 원하는 필드를 자유롭게 정의할 수 있다.
  • username 대신 email 등 다른 필드를 인증 필드로 사용할 수 있다.

단점

  • 많은 세부 구현이 필요하다.
  • 인증 관련 모든 메서드를 직접 구현해야 한다.

구현 예시

from django.contrib.auth.models import AbstractBaseUser, BaseUserManager

class CustomUserManager(BaseUserManager):
    def create_user(self, email, password=None, **extra_fields):
        if not email:
            raise ValueError('이메일은 필수입니다')
        email = self.normalize_email(email)
        user = self.model(email=email, **extra_fields)
        user.set_password(password)
        user.save()
        return user

    def create_superuser(self, email, password=None, **extra_fields):
        extra_fields.setdefault('is_staff', True)
        extra_fields.setdefault('is_superuser', True)
        return self.create_user(email, password, **extra_fields)

class CustomUser(AbstractBaseUser):
    email = models.EmailField(unique=True)
    is_active = models.BooleanField(default=True)
    is_staff = models.BooleanField(default=False)
    
    objects = CustomUserManager()
    
    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = []

 

 

어떤 방식을 선택해야 할까?

각 방식의 선택 기준을 정리하면 다음과 같다:

1. 기본 User 모델

  • 빠른 개발이 필요할 때
  • 기본 인증 시스템으로 충분할 때
  • 커스터마이징이 거의 필요 없을 때
  • 추가 정보는 Profile 모델로 관리 가능할 때

2. AbstractUser

  • 기존 User 모델에 필드를 추가하고 싶을 때
  • 기본 인증 시스템을 유지하면서 확장이 필요할 때
  • username 기반 인증이 적합할 때

3. AbstractBaseUser

  • 완전히 다른 인증 체계가 필요할 때
  • email 기반 인증 등 특별한 인증 방식이 필요할 때
  • 기존 User 모델의 필드가 대부분 불필요할 때

 

결론

Django에서 사용자 모델을 구현할 때는 프로젝트의 요구사항과 미래의 확장을 고려하여 신중하게 선택해야 한다. 특히 이 결정은 프로젝트 초기에 이루어지며, 나중에 변경하기가 매우 어렵다는 점을 염두에 두어야 한다.

간단한 프로젝트라면 기본 User 모델에 Profile 모델을 추가하는 것으로 충분할 수 있다. 하지만 복잡한 사용자 관리가 필요하거나, 특별한 인증 요구사항이 있다면 AbstractUserAbstractBaseUser의 사용을 고려해봐야 한다.

특별한 요구사항이 없다면 AbstractUser의 사용이 추천된다. 대부분의 커스터마이징 요구사항을 충족하면서도 Django의 기본 기능들을 그대로 활용할 수 있기 때문이다.

 

참고 자료

https://simpleisbetterthancomplex.com/tutorial/2016/07/22/how-to-extend-django-user-model.html

 

How to Extend Django User Model

The Django’s built-in authentication system is great. For the most part we can use it out-of-the-box, saving a lot ofdevelopment and testing effort. It fits ...

simpleisbetterthancomplex.com

반응형
반응형

https://www.acmicpc.net/problem/4949

입력으로 주어지는 각 문자열들에 대해, 소괄호 또는 대괄호의 열고 닫는 쌍이 갖추어져 있는지(="균형잡혀 있는지") 묻는 문제이다.

문제는 stack을 해결하면 풀린다.

문자열의 각 문자를 순회하면서,

  • 여는 괄호일 때는 push하고
  • 닫는 괄호일 때는 stack 내부에서 top의 위치에 매칭되는 여는 괄호가 이미 있는지 확인 -> 없으면 균형잡혀 있지 않은 것이다.

순회가 끝난 뒤, stack에 여는 괄호가 남아 있다면 이것도 균형잡혀 있지 않은 것이다.

관건은 구현이다.

 

먼저 아래 방법을 썼다.

p라는 문자열은 닫는 괄호에 대해 매칭되는 여는 괄호를 찾기 위한 저장소다. 이를 위해 여는 괄호 2개와 닫는 괄호 2개를 이어붙였다. 그래서 p 문자열 상에서 index() 계산을 사용해서 매칭되는 괄호를 찾는다.

정답 코드 1

import sys


def is_balanced(s):
    p = "([)]"
    stack = []
    for c in s:
        if c in p[0:2]:
            stack.append(c)
        elif c in p[2:]:
            if not stack or (stack[-1] != p[p.index(c) - 2]):
                return False
            stack.pop()
    return not stack


sys.stdout.write(
    "\n".join(
        ("yes" if is_balanced(s) else "no") for s in sys.stdin if s.rstrip() != "."
    )
)

문자열 p의 길이가 4밖에 안되기 때문에, p.index()가 linear search긴 해도 사실상 O(1)으로 동작할 것으로 생각했다. 

그렇지만, 실제로는 O(4)라고 볼 수 있다.

만약 입력 문장의 갯수가 매우 많아지면, 이 미세한 차이가 누적되서 성능에 영향을 끼칠 수 있다.

 

매칭되는 여는 괄호를 한번에 찾을 수 있는 방법을 사용하면 성능을 좀 더 최적화할 수 있다.

이를 위해, 해싱 기반으로 동작하는 dict를 사용했다.

정답 코드 2 - dict를 사용한 해싱 탐색

import sys


def is_balanced(s):
    stack = []
    pairs = {")": "(", "]": "["}
    for c in s:
        if c in "([":
            stack.append(c)
        elif c in ")]":
            if not stack or stack[-1] != pairs[c]:
                return False
            stack.pop()
    return not stack


sys.stdout.write(
    "\n".join(
        ("yes" if is_balanced(s) else "no") for s in sys.stdin if s.rstrip() != "."
    )
)

성능이 좀 더 개선된 것을 확인할 수 있다.

반응형
반응형

Django를 사용시 as_view() 메서드를 자주 마주치게 된다. URL 설정에서 클래스 기반 뷰(Class-based View)를 연결할 때 항상 이 메서드를 호출한다. 이 메서드가 어떤 일을 하는지, 그리고 왜 필요한지 알아본다.

 

as_view()의 필요성

Django의 URL 라우팅 시스템은 기본적으로 함수를 기대한다. 하지만 코드를 더 체계적으로 구조화하기 위해,   클래스 기반 뷰를 사용한다. 바로 여기서 as_view()가 등장한다. as_view()는 클래스 기반 뷰를 URL 라우터가 이해할 수 있는 함수로 변환해주는 다리 역할을 한다.

내부 동작 원리

View 클레스의 as_view()의 내부 동작을 간략화된 형태로 살펴보자. 

class View:

	# ...생략...
    
    @classonlymethod
    def as_view(cls, **initkwargs):
        # ...생략...
        def view(request, *args, **kwargs):
            self = cls(**initkwargs)
            self.setup(request, *args, **kwargs)
            return self.dispatch(request, *args, **kwargs)
        # ...생략...
        return view
        
    # ...생략...

이 코드가 하는 일을 단계별로 살펴보면:

  1. 뷰 클래스의 새 인스턴스를 생성한다.
  2. (request 같은) 속성들을 초기화한다. 이는 뷰의 모든 메서드에 공유되는 속성이다.
  3. HTTP 메서드에 따라 적절한 핸들러로 요청을 전달한다.
    • dispatch 함수를 보면, request에서 HTTP 메서드를 알아낸 다음, 뷰가 해당 HTTP 메서드에 대해 구현하는 핸들러 함수(get()이나 post() 등)를 호출하는 것을 확인 가능하다.
    def dispatch(self, request, *args, **kwargs):
        # Try to dispatch to the right method; if a method doesn't exist,
        # defer to the error handler. Also defer to the error handler if the
        # request method isn't on the approved list.
        if request.method.lower() in self.http_method_names:
            handler = getattr(
                self, request.method.lower(), self.http_method_not_allowed
            )
        else:
            handler = self.http_method_not_allowed
        return handler(request, *args, **kwargs)

 

실제 사용 예시

# views.py
from django.views import View
from django.http import HttpResponse

class BlogPostView(View):
    def get(self, request, *args, **kwargs):
        return HttpResponse("블로그 포스트를 보여줍니다")
    
    def post(self, request, *args, **kwargs):
        return HttpResponse("새 포스트를 생성했습니다")

# urls.py
from django.urls import path
from .views import BlogPostView

urlpatterns = [
    path('post/', BlogPostView.as_view(), name='blog-post'),
]

고급 사용법 - 초기화 배개면수 전달

as_view()는 뷰 클래스에 초기 설정을 전달할 수 있는 기능도 제공한다:

path('post/', BlogPostView.as_view(template_name='custom_template.html'), name='blog-post')

이렇게 전달된 매개변수는 뷰 클래스의 인스턴스가 생성될 때 적용된다.

 

요약

as_view() 메서드는 Django의 클래스 기반 뷰 시스템을 가능하게 하는 핵심 요소이다. 이 메서드를 통해, 객체 지향적인 뷰를 작성하면서도 Django의 URL 시스템과 원활하게 통합할 수 있게 된다.

반응형

'Django' 카테고리의 다른 글

[Django] Messages Framework  (0) 2025.01.23
[Django] 사용자 모델 구현 방법 비교  (0) 2025.01.22
[Django] 정적 파일(Static Files) 관리  (0) 2025.01.17
[Django] urlpatterns의 작동 원리  (0) 2024.12.29
[Django] reverse 함수  (0) 2024.12.28

+ Recent posts