Django诊所管理系统:医生日程预约功能开发技术求助
Hey there! Let's work through implementing the doctor schedule and appointment booking feature for your Django clinic management system. I’ll break this down into actionable steps so you can get up and running quickly.
Instead of a simple Time model, we’ll create more robust models to track doctors, their available slots, and appointments. This structure gives you flexibility to manage availability and bookings clearly:
from django.db import models from django.contrib.auth.models import User from datetime import datetime class Doctor(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE) specialty = models.CharField(max_length=100) license_number = models.CharField(max_length=50, unique=True) def __str__(self): return f"{self.user.first_name} {self.user.last_name} - {self.specialty}" class ScheduleSlot(models.Model): AVAILABILITY_CHOICES = ( ('available', '空闲'), ('booked', '已占用'), ('unavailable', '不可预约'), # For doctor leave/breaks ) doctor = models.ForeignKey(Doctor, on_delete=models.CASCADE, related_name='schedule_slots') date = models.DateField() start_time = models.TimeField() end_time = models.TimeField() status = models.CharField(max_length=20, choices=AVAILABILITY_CHOICES, default='available') def __str__(self): return f"{self.doctor.user.get_full_name()} - {self.date} | {self.start_time} to {self.end_time} ({self.status})" class Appointment(models.Model): patient_name = models.CharField(max_length=100) patient_contact = models.CharField(max_length=20) patient_notes = models.TextField(blank=True) doctor = models.ForeignKey(Doctor, on_delete=models.CASCADE) schedule_slot = models.OneToOneField(ScheduleSlot, on_delete=models.CASCADE, related_name='linked_appointment') created_at = models.DateTimeField(auto_now_add=True) def __str__(self): return f"Appointment: {self.patient_name} with Dr. {self.doctor.user.last_name} on {self.schedule_slot.date}"
Admins need an easy way to create recurring or one-time slots. Add a custom action in the Django admin to batch generate slots for a specific date:
from django.contrib import admin from .models import Doctor, ScheduleSlot, Appointment from datetime import time, timedelta @admin.register(ScheduleSlot) class ScheduleSlotAdmin(admin.ModelAdmin): list_display = ('doctor', 'date', 'start_time', 'end_time', 'status') list_filter = ('doctor', 'date', 'status') actions = ['generate_30min_slots'] def generate_30min_slots(self, request, queryset): # Generate 30-minute slots from 9 AM to 5 PM for selected dates/doctors start_time = time(9, 0) end_time = time(17, 0) slot_duration = timedelta(minutes=30) for slot in queryset: current_time = start_time while current_time < end_time: next_time = (datetime.combine(datetime.today(), current_time) + slot_duration).time() ScheduleSlot.objects.get_or_create( doctor=slot.doctor, date=slot.date, start_time=current_time, end_time=next_time, defaults={'status': 'available'} ) current_time = next_time self.message_user(request, "Successfully generated 30-minute schedule slots!") generate_30min_slots.short_description = "Generate 30-minute slots for selected entries" admin.site.register(Doctor) admin.site.register(Appointment)
Create a view to handle booking, with validation to ensure slots are only booked if they’re available:
First, make an appointment form:
from django import forms from .models import Appointment class AppointmentForm(forms.ModelForm): class Meta: model = Appointment fields = ['patient_name', 'patient_contact', 'patient_notes']
Then the booking view (restricted to admins):
from django.shortcuts import render, get_object_or_404, redirect from django.contrib.auth.decorators import user_passes_test from .models import ScheduleSlot, Appointment from .forms import AppointmentForm def is_admin(user): return user.is_staff @user_passes_test(is_admin) def book_appointment(request, slot_id): slot = get_object_or_404(ScheduleSlot, id=slot_id) if slot.status != 'available': return render(request, 'clinic/error.html', {'message': "This slot is already booked or unavailable!"}) if request.method == 'POST': form = AppointmentForm(request.POST) if form.is_valid(): appointment = form.save(commit=False) appointment.doctor = slot.doctor appointment.schedule_slot = slot appointment.save() # Mark the slot as booked slot.status = 'booked' slot.save() return redirect('appointment_success') else: form = AppointmentForm() return render(request, 'clinic/book_appointment.html', { 'form': form, 'slot': slot, 'doctor': slot.doctor })
Create a view to show a doctor’s schedule for a selected date, splitting slots into available and booked groups:
from django.shortcuts import render, get_object_or_404 from .models import Doctor, ScheduleSlot from datetime import date def doctor_schedule(request, doctor_id): doctor = get_object_or_404(Doctor, id=doctor_id) selected_date = request.GET.get('date', str(date.today())) # Get all slots for the selected date, sorted by start time all_slots = ScheduleSlot.objects.filter(doctor=doctor, date=selected_date).order_by('start_time') available_slots = all_slots.filter(status='available') booked_slots = all_slots.filter(status='booked') return render(request, 'clinic/doctor_schedule.html', { 'doctor': doctor, 'selected_date': selected_date, 'available_slots': available_slots, 'booked_slots': booked_slots })
Create doctor_schedule.html to visualize the schedule:
<h2>Dr. {{ doctor.user.last_name }}'s Schedule ({{ selected_date }})</h2> <!-- Date picker to switch between dates --> <form method="get" class="mb-4"> <input type="date" name="date" value="{{ selected_date }}" required> <button type="submit" class="btn btn-primary">View Date</button> </form> <!-- Available Slots --> <div class="card mb-3"> <div class="card-header bg-success text-white"> <h3>Available Slots</h3> </div> <div class="card-body"> {% if available_slots %} <ul class="list-group"> {% for slot in available_slots %} <li class="list-group-item d-flex justify-content-between align-items-center"> {{ slot.start_time }} - {{ slot.end_time }} <a href="{% url 'book_appointment' slot.id %}" class="btn btn-sm btn-success">Book for Patient</a> </li> {% endfor %} </ul> {% else %} <p>No available slots for this date.</p> {% endif %} </div> </div> <!-- Booked Slots --> <div class="card"> <div class="card-header bg-warning text-white"> <h3>Booked Slots</h3> </div> <div class="card-body"> {% if booked_slots %} <ul class="list-group"> {% for slot in booked_slots %} <li class="list-group-item"> <strong>{{ slot.start_time }} - {{ slot.end_time }}</strong> <br>Patient: {{ slot.linked_appointment.patient_name }} <br>Contact: {{ slot.linked_appointment.patient_contact }} {% if slot.linked_appointment.patient_notes %} <br>Notes: {{ slot.linked_appointment.patient_notes }} {% endif %} </li> {% endfor %} </ul> {% else %} <p>No booked slots for this date.</p> {% endif %} </div> </div>
- Add timezone support in your Django settings to avoid time display issues across regions.
- Implement a cancel appointment feature that sets the slot status back to
available. - Add email notifications (using Django’s
send_mail) to alert patients and doctors when an appointment is booked or canceled. - Restrict access to schedule management views using Django’s permission system to ensure only admins can modify bookings.
内容的提问来源于stack exchange,提问作者Darya Shipitcyna

