WeniVooks

검색

Django 베이스캠프

Reservations 관련 로직 구현

이번 시간엔 Reservations 관련 기능을 구현해보겠습니다.

1. Reservation Form 구현

먼저, 예약을 위한 Form을 구현해보겠습니다.

# books/forms.py
 
class ReservationForm(forms.ModelForm):
    class Meta:
        model = Reservation
        fields = []  # user와 book은 view에서 처리
 
    def clean(self):
        cleaned_data = super().clean()
        user = self.user
        book = self.book
 
        # 이미 동일한 도서에 대한 예약이 있는지 확인
        existing_reservation = Reservation.objects.filter(
            user=user,
            book=book,
            status='WAITING'
        ).exists()
        
        if existing_reservation:
            raise forms.ValidationError('이미 예약한 도서입니다.')
        
        # 현재 대출 가능한 도서가 있는 경우 예약 불가
        if book.is_available():
            raise forms.ValidationError('현재 대출 가능한 도서가 있어 예약할 수 없습니다.')
 
        return cleaned_data
 
    def __init__(self, *args, **kwargs):
        self.user = kwargs.pop('user', None)
        self.book = kwargs.pop('book', None)
        super().__init__(*args, **kwargs)
 
# books/forms.py
 
class ReservationForm(forms.ModelForm):
    class Meta:
        model = Reservation
        fields = []  # user와 book은 view에서 처리
 
    def clean(self):
        cleaned_data = super().clean()
        user = self.user
        book = self.book
 
        # 이미 동일한 도서에 대한 예약이 있는지 확인
        existing_reservation = Reservation.objects.filter(
            user=user,
            book=book,
            status='WAITING'
        ).exists()
        
        if existing_reservation:
            raise forms.ValidationError('이미 예약한 도서입니다.')
        
        # 현재 대출 가능한 도서가 있는 경우 예약 불가
        if book.is_available():
            raise forms.ValidationError('현재 대출 가능한 도서가 있어 예약할 수 없습니다.')
 
        return cleaned_data
 
    def __init__(self, *args, **kwargs):
        self.user = kwargs.pop('user', None)
        self.book = kwargs.pop('book', None)
        super().__init__(*args, **kwargs)
 

2. Reservation View 구현

2.1 예약 생성 (도서 예약)
# books/views.py
@login_required # 로그인 여부 확인
def reservation_create(request, book_id):
    """도서 예약"""
    book = get_object_or_404(Book, pk=book_id)
    
    if request.method == 'POST': # POST 요청인 경우
        form = ReservationForm(request.POST, user=request.user, book=book)
        if form.is_valid():
            reservation = form.save(commit=False)
            reservation.user = request.user
            reservation.book = book
            reservation.expiry_date = timezone.now() + timedelta(days=1)  # 1일간 예약 유효
            reservation.save()
            
            messages.success(request, f'{book.title} 도서가 예약되었습니다.')
            return redirect('books:reservation-list') # 예약 목록 페이지로 이동
    else:
        form = ReservationForm(user=request.user, book=book)
    
    return render(request, 'books/reservation_form.html', {
        'form': form,
        'book': book
    })
 
# books/views.py
@login_required # 로그인 여부 확인
def reservation_create(request, book_id):
    """도서 예약"""
    book = get_object_or_404(Book, pk=book_id)
    
    if request.method == 'POST': # POST 요청인 경우
        form = ReservationForm(request.POST, user=request.user, book=book)
        if form.is_valid():
            reservation = form.save(commit=False)
            reservation.user = request.user
            reservation.book = book
            reservation.expiry_date = timezone.now() + timedelta(days=1)  # 1일간 예약 유효
            reservation.save()
            
            messages.success(request, f'{book.title} 도서가 예약되었습니다.')
            return redirect('books:reservation-list') # 예약 목록 페이지로 이동
    else:
        form = ReservationForm(user=request.user, book=book)
    
    return render(request, 'books/reservation_form.html', {
        'form': form,
        'book': book
    })
 
2.2 예약 목록 조회
@login_required
def reservation_list(request):
    """예약 목록"""
    if request.user.is_librarian(): # 사서인 경우
        reservations = Reservation.objects.all().order_by('reserved_date') # 모든 예약 목록 조회
    else:
        reservations = Reservation.objects.filter(
            user=request.user,
            status__in=['WAITING', 'AVAILABLE'] # 대기 중, 대출 가능한 예약만 조회
        ).order_by('reserved_date')
    
    return render(request, 'books/reservation_list.html', {
        'reservations': reservations
    })
@login_required
def reservation_list(request):
    """예약 목록"""
    if request.user.is_librarian(): # 사서인 경우
        reservations = Reservation.objects.all().order_by('reserved_date') # 모든 예약 목록 조회
    else:
        reservations = Reservation.objects.filter(
            user=request.user,
            status__in=['WAITING', 'AVAILABLE'] # 대기 중, 대출 가능한 예약만 조회
        ).order_by('reserved_date')
    
    return render(request, 'books/reservation_list.html', {
        'reservations': reservations
    })
2.3 예약 취소
@login_required
def reservation_cancel(request, reservation_id):
    """예약 취소"""
    reservation = get_object_or_404(Reservation, pk=reservation_id)
    
    if request.user != reservation.user and not request.user.is_librarian(): # 본인의 예약이거나 사서만 취소 가능
        messages.error(request, '권한이 없습니다.')
        return redirect('books:reservation-list')
    
    if request.method == 'POST':
        if reservation.status in ['WAITING', 'AVAILABLE']: # 대기 중, 대출 가능한 경우에만 취소 가능
            reservation.status = 'CANCELLED' # 예약 취소
            reservation.save() # 예약 정보 저장
            messages.success(request, '예약이 취소되었습니다.')
        
        return redirect('books:reservation-list') # 예약 목록 페이지로 이동
    else:
        messages.error(request, '잘못된 접근입니다.')
        return redirect('books:reservation-list')
@login_required
def reservation_cancel(request, reservation_id):
    """예약 취소"""
    reservation = get_object_or_404(Reservation, pk=reservation_id)
    
    if request.user != reservation.user and not request.user.is_librarian(): # 본인의 예약이거나 사서만 취소 가능
        messages.error(request, '권한이 없습니다.')
        return redirect('books:reservation-list')
    
    if request.method == 'POST':
        if reservation.status in ['WAITING', 'AVAILABLE']: # 대기 중, 대출 가능한 경우에만 취소 가능
            reservation.status = 'CANCELLED' # 예약 취소
            reservation.save() # 예약 정보 저장
            messages.success(request, '예약이 취소되었습니다.')
        
        return redirect('books:reservation-list') # 예약 목록 페이지로 이동
    else:
        messages.error(request, '잘못된 접근입니다.')
        return redirect('books:reservation-list')
7.7 Loans 관련 로직 구현7.9 마무리