A comprehensive web-based medical appointment system built with Django that connects patients with doctors, enabling easy appointment scheduling, patient history tracking, and doctor reviews.
-
π Role-based Authentication
- Doctor registration and verification
- Patient registration
- Admin dashboard
- Secure JWT authentication
- Password reset functionality
-
π€ Profile Management
- Personal information management
- Profile picture upload
- Contact information
- Location settings
- Specialization details (for doctors)
-
π Profile Management
- Specialization selection
- Consultation price setting
- Professional certificate upload
- Location management with GPS coordinates
- Professional bio
- Consultation hours
-
π Appointment Management
- Availability calendar
- Appointment scheduling
- Patient history tracking
- Consultation notes
- Payment tracking
-
π Search and Discovery
- Doctor search by specialization
- Location-based search
- Price filtering
- Rating-based sorting
- Availability checking
-
π± Appointment Management
- Online booking
- Appointment history
- Medical records
- Payment processing
- Appointment reminders
-
β Review System
- Doctor rating
- Written reviews
- Rating history
- Review management
-
π₯ User Management
- User verification
- Account management
- Role assignment
- Content moderation
-
βοΈ System Management
- Specialization management
- System configuration
- Analytics dashboard
- Report generation
- Framework: Django 5.1.6
- API: Django REST Framework
- Authentication: JWT (JSON Web Tokens)
- Database: SQLite (Development) / PostgreSQL (Production)
- Task Queue: Celery (for background tasks)
- Admin Interface: Django Material Admin
- API Documentation: Swagger/ReDoc
- File Storage: Local storage (Development) / Cloud storage (Production)
- CORS support for cross-origin requests
- API documentation with drf-yasg
- Material Design admin interface
- File upload handling
- Email notifications
- SMS notifications (optional)
- Payment gateway integration
# Never expose SECRET_KEY or use DEBUG=True in production!
DEBUG = False
SECRET_KEY = 'your-secure-secret-key' # Store in environment variables
# SSL/HTTPS Configuration
SECURE_SSL_REDIRECT = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
SECURE_HSTS_SECONDS = 31536000 # 1 year
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_HSTS_PRELOAD = True
# Security Headers
SECURE_BROWSER_XSS_FILTER = True
SECURE_CONTENT_TYPE_NOSNIFF = True
X_FRAME_OPTIONS = 'DENY'
REFERRER_POLICY = 'same-origin'
# Optional: Content Security Policy
CSP_DEFAULT_SRC = ("'self'",)
CSP_STYLE_SRC = ("'self'", "'unsafe-inline'")
CSP_SCRIPT_SRC = ("'self'",)
CSP_IMG_SRC = ("'self'", "data:", "https:")# Debug and Secret Key
DEBUG = False
SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY')
# Allowed Hosts
ALLOWED_HOSTS = ['yourdomain.com', 'www.yourdomain.com']
# Database Security
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': os.environ.get('DB_NAME'),
'USER': os.environ.get('DB_USER'),
'PASSWORD': os.environ.get('DB_PASSWORD'),
'HOST': os.environ.get('DB_HOST'),
'PORT': os.environ.get('DB_PORT'),
'CONN_MAX_AGE': 60,
'OPTIONS': {
'sslmode': 'require',
}
}
}# Session Configuration
SESSION_COOKIE_AGE = 3600 # 1 hour
SESSION_COOKIE_SECURE = True
SESSION_COOKIE_HTTPONLY = True
SESSION_COOKIE_SAMESITE = 'Lax'
SESSION_EXPIRE_AT_BROWSER_CLOSE = True
SESSION_SAVE_EVERY_REQUEST = True
# CSRF Protection
CSRF_COOKIE_SECURE = True
CSRF_COOKIE_HTTPONLY = True
CSRF_COOKIE_SAMESITE = 'Lax'
CSRF_TRUSTED_ORIGINS = ['https://yourdomain.com']
CSRF_USE_SESSIONS = True# Password Validation
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
'OPTIONS': {
'min_length': 12,
}
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# Password Hashing
PASSWORD_HASHERS = [
'django.contrib.auth.hashers.Argon2PasswordHasher',
'django.contrib.auth.hashers.PBKDF2PasswordHasher',
'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher',
'django.contrib.auth.hashers.BCryptSHA256PasswordHasher',
]# File Upload Settings
FILE_UPLOAD_MAX_MEMORY_SIZE = 5242880 # 5MB
FILE_UPLOAD_PERMISSIONS = 0o644
FILE_UPLOAD_DIRECTORY_PERMISSIONS = 0o755
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'# Email Configuration
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_HOST_USER = os.environ.get('EMAIL_HOST_USER')
EMAIL_HOST_PASSWORD = os.environ.get('EMAIL_HOST_PASSWORD')
DEFAULT_FROM_EMAIL = 'noreply@yourdomain.com'# Security Middleware
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'csp.middleware.CSPMiddleware',
]
# Content Security Policy
CSP_DEFAULT_SRC = ("'self'",)
CSP_STYLE_SRC = ("'self'", "'unsafe-inline'", "https://fonts.googleapis.com")
CSP_SCRIPT_SRC = ("'self'", "'unsafe-inline'", "'unsafe-eval'", "https://cdn.jsdelivr.net")
CSP_IMG_SRC = ("'self'", "data:", "https:", "blob:")
CSP_FONT_SRC = ("'self'", "https://fonts.gstatic.com")
CSP_CONNECT_SRC = ("'self'", "https://api.yourdomain.com")
CSP_MEDIA_SRC = ("'self'", "https://media.yourdomain.com")
CSP_OBJECT_SRC = ("'none'",)
CSP_FRAME_SRC = ("'self'", "https://trusted-frame.com")
CSP_REPORT_URI = '/csp-report/'# CORS Settings
CORS_ALLOWED_ORIGINS = [
"https://yourdomain.com",
"https://api.yourdomain.com",
]
CORS_ALLOW_CREDENTIALS = True
CORS_ALLOW_METHODS = [
'GET',
'POST',
'PUT',
'PATCH',
'DELETE',
'OPTIONS'
]
CORS_ALLOW_HEADERS = [
'accept',
'accept-encoding',
'authorization',
'content-type',
'dnt',
'origin',
'user-agent',
'x-csrftoken',
'x-requested-with',
]
# REST Framework Security
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework_simplejwt.authentication.JWTAuthentication',
],
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
],
'DEFAULT_THROTTLE_CLASSES': [
'rest_framework.throttling.AnonRateThrottle',
'rest_framework.throttling.UserRateThrottle'
],
'DEFAULT_THROTTLE_RATES': {
'anon': '100/day',
'user': '1000/day'
}
}# Logging Configuration
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'verbose': {
'format': '{levelname} {asctime} {module} {process:d} {thread:d} {message}',
'style': '{',
},
},
'handlers': {
'file': {
'level': 'ERROR',
'class': 'logging.FileHandler',
'filename': '/var/log/django/error.log',
'formatter': 'verbose',
},
'security_file': {
'level': 'WARNING',
'class': 'logging.FileHandler',
'filename': '/var/log/django/security.log',
'formatter': 'verbose',
},
},
'loggers': {
'django': {
'handlers': ['file'],
'level': 'ERROR',
'propagate': True,
},
'django.security': {
'handlers': ['security_file'],
'level': 'WARNING',
'propagate': True,
},
},
}-
Environment Variables
- Store all sensitive data in environment variables
- Never commit
.envfiles to version control - Use different environment variables for development and production
-
Regular Updates
- Keep Django and all dependencies updated
- Regularly check for security vulnerabilities
- Subscribe to Django security mailing list
-
Backup Strategy
- Implement regular database backups
- Store backups in secure, encrypted locations
- Test backup restoration regularly
-
Monitoring
- Set up error monitoring (e.g., Sentry)
- Monitor failed login attempts
- Track suspicious activities
- Set up alerts for security events
-
Server Security
- Use a reverse proxy (e.g., Nginx)
- Configure firewall rules
- Enable SSL/TLS
- Regular security audits
-
Application Security
- Implement rate limiting
- Use secure password hashing
- Enable two-factor authentication
- Regular security testing
-
Data Protection
- Encrypt sensitive data
- Implement data retention policies
- Regular data cleanup
- GDPR compliance measures
The system uses Django REST Framework's permission classes for access control:
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
]
}AllowAny: Allows unrestricted accessIsAuthenticated: Requires user authenticationIsAdminUser: Restricts access to admin users onlyIsAuthenticatedOrReadOnly: Allows read access to unauthenticated usersDjangoModelPermissions: Ties into Django's standarddjango.contrib.authmodel permissionsDjangoModelPermissionsOrAnonReadOnly: Similar to above but allows anonymous read accessDjangoObjectPermissions: Ties into Django's standard object-level permissions
from rest_framework import permissions
class IsDoctor(permissions.BasePermission):
def has_permission(self, request, view):
return request.user and request.user.is_authenticated and request.user.is_doctor
class IsPatient(permissions.BasePermission):
def has_permission(self, request, view):
return request.user and request.user.is_authenticated and request.user.is_patient
class IsAdminOrDoctor(permissions.BasePermission):
def has_permission(self, request, view):
return request.user and request.user.is_authenticated and (request.user.is_staff or request.user.is_doctor)class IsAppointmentOwner(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
return obj.patient == request.user or obj.doctor == request.user
class IsProfileOwner(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
return obj.user == request.user
class IsReviewOwner(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
return obj.patient == request.userfrom datetime import datetime
class IsWithinBusinessHours(permissions.BasePermission):
def has_permission(self, request, view):
current_hour = datetime.now().hour
return 9 <= current_hour <= 17 # Business hours 9 AM to 5 PMclass CanManageAppointments(permissions.BasePermission):
def has_permission(self, request, view):
if request.method in permissions.SAFE_METHODS:
return True
return request.user.is_authenticated and (request.user.is_doctor or request.user.is_staff)
class CanManageReviews(permissions.BasePermission):
def has_permission(self, request, view):
if request.method in permissions.SAFE_METHODS:
return True
return request.user.is_authenticated and request.user.is_patientfrom rest_framework import viewsets
from rest_framework.permissions import IsAuthenticated, IsAdminUser
class DoctorViewSet(viewsets.ModelViewSet):
permission_classes = [IsAuthenticated, IsDoctor]
# ... rest of the viewset
class AppointmentViewSet(viewsets.ModelViewSet):
permission_classes = [IsAuthenticated, IsAppointmentOwner]
# ... rest of the viewsetfrom rest_framework.decorators import permission_classes
@permission_classes([IsAuthenticated, IsDoctor])
def doctor_dashboard(request):
# ... view logic
@permission_classes([IsAuthenticated, IsPatient])
def patient_appointments(request):
# ... view logic- Always use the most restrictive permission that meets your requirements
- Combine multiple permissions when needed using lists
- Use object-level permissions for fine-grained access control
- Test permissions thoroughly, especially custom ones
- Document permission requirements in API documentation
- Consider caching permission results for performance
- Use permission classes in combination with authentication classes
- Python 3.8 or higher
- pip (Python package manager)
- Virtual environment (recommended)
- Git
- PostgreSQL (for production)
- Code editor (VS Code, PyCharm, etc.)
- Postman or similar API testing tool
- Git client
- π₯ Clone the repository:
git clone [repository-url]
cd [project-directory]- π§ Create and activate virtual environment:
# Create virtual environment
python -m venv .venv
# Activate on Windows
.venv\Scripts\activate
# Activate on Unix or MacOS
source .venv/bin/activate- π¦ Install dependencies:
pip install -r requirements.txt- βοΈ Environment Setup:
Create a
.envfile in the project root with the following variables:
DEBUG=True
SECRET_KEY=your-secret-key
DATABASE_URL=sqlite:///db.sqlite3
ALLOWED_HOSTS=localhost,127.0.0.1
CORS_ALLOWED_ORIGINS=http://localhost:3000,http://127.0.0.1:3000- ποΈ Database Setup:
# Run migrations
python manage.py migrate
# Create superuser
python manage.py createsuperuser- π Static Files:
python manage.py collectstaticβΆοΈ Run Development Server:
python manage.py runserverβββ appointments/ # Appointment management app
β βββ models.py # Appointment models
β βββ views.py # Appointment views
β βββ urls.py # Appointment URLs
β βββ serializers.py # Appointment serializers
βββ config/ # Project configuration
β βββ settings.py # Project settings
β βββ urls.py # Main URL configuration
β βββ wsgi.py # WSGI configuration
βββ media/ # User uploaded files
βββ model_ai/ # AI model integration
βββ rating/ # Doctor rating system
βββ register_user/ # User registration and management
βββ static/ # Static files
βββ manage.py # Django management script
The API documentation is available at:
- Swagger UI:
/swagger/ - ReDoc:
/redoc/
POST /api/auth/register/- Register new userPOST /api/auth/login/- User loginPOST /api/auth/refresh/- Refresh JWT tokenPOST /api/auth/logout/- User logoutPOST /api/auth/password-reset/- Request password resetPOST /api/auth/password-reset/confirm/- Confirm password reset
GET /api/users/- List all usersPOST /api/users/- Create new userGET /api/users/{id}/- Get user detailsPUT /api/users/{id}/- Update userDELETE /api/users/{id}/- Delete userGET /api/users/me/- Get current user profilePUT /api/users/me/- Update current user profileGET /api/users/doctors/- List all doctorsGET /api/users/patients/- List all patients
GET /api/appointments/- List all appointmentsPOST /api/appointments/- Create new appointmentGET /api/appointments/{id}/- Get appointment detailsPUT /api/appointments/{id}/- Update appointmentDELETE /api/appointments/{id}/- Delete appointmentGET /api/appointments/doctor/{doctor_id}/- Get doctor's appointmentsGET /api/appointments/patient/{patient_id}/- Get patient's appointmentsPUT /api/appointments/{id}/status/- Update appointment statusGET /api/appointments/available-slots/- Get available time slots
GET /api/ratings/- List all ratingsPOST /api/ratings/- Create new ratingGET /api/ratings/{id}/- Get rating detailsPUT /api/ratings/{id}/- Update ratingDELETE /api/ratings/{id}/- Delete ratingGET /api/ratings/doctor/{doctor_id}/- Get doctor's ratingsGET /api/ratings/patient/{patient_id}/- Get patient's ratings
GET /api/specializations/- List all specializationsPOST /api/specializations/- Create new specializationGET /api/specializations/{id}/- Get specialization detailsPUT /api/specializations/{id}/- Update specializationDELETE /api/specializations/{id}/- Delete specialization
GET /api/availability/- List all availability slotsPOST /api/availability/- Create new availability slotGET /api/availability/{id}/- Get availability detailsPUT /api/availability/{id}/- Update availabilityDELETE /api/availability/{id}/- Delete availabilityGET /api/availability/doctor/{doctor_id}/- Get doctor's availability
POST /api/payments/- Create new paymentGET /api/payments/{id}/- Get payment detailsGET /api/payments/appointment/{appointment_id}/- Get appointment paymentPOST /api/payments/verify/- Verify paymentGET /api/payments/history/- Get payment history
- Follow PEP 8 guidelines
- Use meaningful variable names
- Add comments for complex logic
- Write docstrings for functions and classes
# Run all tests
python manage.py test
# Run specific app tests
python manage.py test appointments- Create feature branch
- Make changes
- Write tests
- Run tests
- Create pull request
- Set DEBUG=False
- Configure production database
- Set up static file serving
- Configure email settings
- Set up SSL certificate
- Configure backup system
- Set up monitoring
- Update environment variables
- Run migrations
- Collect static files
- Configure web server
- Set up SSL
- Configure backup
- Fork the repository
- Create your feature branch (
git checkout -b feature/AmazingFeature) - Commit your changes (
git commit -m 'Add some AmazingFeature') - Push to the branch (
git push origin feature/AmazingFeature) - Open a Pull Request
- Update documentation
- Add tests if needed
- Ensure all tests pass
- Update the README.md if needed
This project is licensed under the MIT License - see the LICENSE file for details.
For any queries or support, please contact:
- π§ Email: mostafa.3mad.salah@gmail.com
- π» GitHub: @Mostafa3mad
- π LinkedIn: Mostafa Emad
- π¦ X (Twitter): @mostafa___emad
- Django Documentation
- Django REST Framework
- Material Design
- All contributors