Django公寓预订系统开发咨询:模型设计与关联方法
Hey there! Since you already have your Apartment model and Django's built-in auth system up and running, let's break down how to add the booking feature step by step. I'll keep things clear and beginner-friendly so you can follow along easily.
1. Finalize Your Booking Model
First, let's make sure your Booking model is set up correctly to link users, apartments, and booking dates. Add this to your app's models.py:
from django.db import models from django.contrib.auth.models import User from .models import Apartment # Import your existing Apartment model from django.utils import timezone class Booking(models.Model): # Link to the logged-in user user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="bookings") # Link to the apartment being booked apartment = models.ForeignKey(Apartment, on_delete=models.CASCADE, related_name="bookings") # Booking dates start_date = models.DateField() end_date = models.DateField() # Optional: Track booking status (e.g., confirmed, pending) STATUS_CHOICES = [ ('P', 'Pending'), ('C', 'Confirmed'), ('CXL', 'Cancelled'), ] status = models.CharField(max_length=3, choices=STATUS_CHOICES, default='P') # Auto-set when the booking is created created_at = models.DateTimeField(default=timezone.now) def __str__(self): return f"{self.user.username} - {self.apartment.title} ({self.start_date} to {self.end_date})" # Optional: Add validation directly in the model def clean(self): from django.core.exceptions import ValidationError # Ensure start date isn't in the past if self.start_date < timezone.now().date(): raise ValidationError("Start date cannot be in the past.") # Ensure end date is after start date if self.end_date <= self.start_date: raise ValidationError("End date must be after start date.")
Don't forget to run migrations after updating the model:
python manage.py makemigrations python manage.py migrate
Also, register the Booking model in admin.py so you can manage bookings via the Django admin:
from django.contrib import admin from .models import Booking admin.site.register(Booking)
2. Create a Booking Form
Next, we'll build a form for users to enter their desired dates. We'll use ModelForm since most fields (user, apartment) will be set programmatically, not by the user.
Create a forms.py file in your app (if you don't have one already) and add:
from django import forms from .models import Booking from django.utils import timezone class BookingForm(forms.ModelForm): class Meta: model = Booking fields = ['start_date', 'end_date'] # Add date picker widgets for better UX widgets = { 'start_date': forms.DateInput(attrs={'type': 'date', 'min': timezone.now().date()}), 'end_date': forms.DateInput(attrs={'type': 'date'}), } # Add custom validation for dates def clean(self): cleaned_data = super().clean() start_date = cleaned_data.get('start_date') end_date = cleaned_data.get('end_date') if start_date and end_date: if start_date < timezone.now().date(): self.add_error('start_date', "Start date can't be in the past.") if end_date <= start_date: self.add_error('end_date', "End date must come after start date.") return cleaned_data
3. Build the Booking View
Now, let's create a view that handles the booking request. This view will:
- Require the user to be logged in
- Fetch the apartment being booked
- Validate the form data
- Check if the apartment is already booked for the selected dates
- Save the booking if everything checks out
Add this to your app's views.py:
from django.shortcuts import render, get_object_or_404, redirect from django.contrib.auth.decorators import login_required from .models import Apartment, Booking from .forms import BookingForm @login_required # Only logged-in users can access this def book_apartment(request, pk): apartment = get_object_or_404(Apartment, pk=pk) if request.method == 'POST': form = BookingForm(request.POST) if form.is_valid(): booking = form.save(commit=False) booking.user = request.user booking.apartment = apartment # Check for overlapping bookings overlapping_bookings = Booking.objects.filter( apartment=apartment, start_date__lt=booking.end_date, end_date__gt=booking.start_date ).exists() if overlapping_bookings: form.add_error(None, "This apartment is already booked for the selected dates.") else: booking.save() # Redirect to a success page or back to the apartment detail return redirect('apartment_detail', pk=apartment.pk) # Replace with your actual detail view name else: form = BookingForm() return render(request, 'book_apartment.html', {'form': form, 'apartment': apartment})
Note: Replace 'apartment_detail' with the actual name of your apartment detail view in the redirect.
4. Update Your URLs
Add a URL pattern for the booking view in your app's urls.py:
from django.urls import path from . import views urlpatterns = [ # Your existing URLs here (e.g., apartment list, detail) path('apartment/<int:pk>/book/', views.book_apartment, name='book_apartment'), ]
5. Update Templates
a. Add Booking Button to Apartment Detail Page
In your apartment detail template (e.g., apartment_detail.html), add a booking button/section that only logged-in users can see:
{% if user.is_authenticated %} <div class="booking-section"> <h3>Book This Apartment</h3> <a href="{% url 'book_apartment' apartment.pk %}" class="btn btn-primary">Start Booking</a> </div> {% else %} <p>Please <a href="{% url 'login' %}">log in</a> to book this apartment.</p> {% endif %}
b. Create the Booking Form Template
Create a book_apartment.html template to display the booking form and error messages:
{% extends 'base.html' %} <!-- Use your base template --> {% block content %} <h2>Book {{ apartment.title }}</h2> <p>Address: {{ apartment.address }}, {{ apartment.city }}</p> <p>Price: ${{ apartment.price }} per night</p> <form method="POST"> {% csrf_token %} {{ form.as_p }} <button type="submit" class="btn btn-success">Confirm Booking</button> <a href="{% url 'apartment_detail' apartment.pk %}" class="btn btn-secondary">Cancel</a> </form> {% if form.errors %} <div class="alert alert-danger mt-3"> {% for field in form %} {% for error in field.errors %} <p>{{ error }}</p> {% endfor %} {% endfor %} {% for error in form.non_field_errors %} <p>{{ error }}</p> {% endfor %} </div> {% endif %} {% endblock %}
6. Test the Flow
Now it's time to test everything out:
- Log in as a user
- Navigate to an apartment detail page
- Click "Start Booking"
- Try entering invalid dates (past start date, end date before start date) to see error messages
- Try booking dates that overlap with an existing booking to ensure the overlap check works
- Confirm a valid booking and check the Django admin to see if it was saved correctly
Optional Enhancements (If You Want to Go Further)
- Add email notifications to the user and admin when a booking is created
- Allow users to view and cancel their own bookings (create a "My Bookings" view)
- Update the
Apartmentmodel'sin_rentfield automatically when a booking is confirmed (use Django signals for this) - Add payment integration (more advanced, but possible with services like Stripe)
内容的提问来源于stack exchange,提问作者user12146567

