From aa26436926c4a56985e9a3cc08780ef7bf36bfe5 Mon Sep 17 00:00:00 2001 From: "staging-devin-ai-integration[bot]" <166158716+staging-devin-ai-integration[bot]@users.noreply.github.com> Date: Mon, 1 Jul 2024 20:04:59 +0000 Subject: [PATCH] Add models and appointment views (#6) * Add custom models for Doctor, Patient, and Appointment * Add URL routing for create_appointment view * Add URL pattern for list_appointments view * Add update and delete appointment view functions * Add URL patterns for update and delete appointment views * Update docker-compose with correct environment variables * Update logging configuration * Fix request data keys in create_appointment and update docker-compose * Update appointment views --------- Co-authored-by: staging-devin-ai-integration[bot] <166158716+staging-devin-ai-integration[bot]@users.noreply.github.com> --- appointments/__init__.py | 0 appointments/admin.py | 3 + appointments/apps.py | 6 ++ appointments/migrations/0001_initial.py | 47 +++++++++++++ appointments/migrations/__init__.py | 0 appointments/models.py | 29 ++++++++ appointments/tests.py | 3 + appointments/urls.py | 9 +++ appointments/views.py | 94 +++++++++++++++++++++++++ docker-compose.yaml | 12 ++-- railway_django_stack/settings.py | 36 ++++++++-- railway_django_stack/urls.py | 3 +- 12 files changed, 229 insertions(+), 13 deletions(-) create mode 100644 appointments/__init__.py create mode 100644 appointments/admin.py create mode 100644 appointments/apps.py create mode 100644 appointments/migrations/0001_initial.py create mode 100644 appointments/migrations/__init__.py create mode 100644 appointments/models.py create mode 100644 appointments/tests.py create mode 100644 appointments/urls.py create mode 100644 appointments/views.py diff --git a/appointments/__init__.py b/appointments/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/appointments/admin.py b/appointments/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/appointments/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/appointments/apps.py b/appointments/apps.py new file mode 100644 index 0000000..4531a32 --- /dev/null +++ b/appointments/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class AppointmentsConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'appointments' diff --git a/appointments/migrations/0001_initial.py b/appointments/migrations/0001_initial.py new file mode 100644 index 0000000..55ff678 --- /dev/null +++ b/appointments/migrations/0001_initial.py @@ -0,0 +1,47 @@ +# Generated by Django 5.0.6 on 2024-07-01 18:17 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Doctor', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('specialization', models.CharField(max_length=100)), + ('phone_number', models.CharField(max_length=15)), + ('address', models.TextField()), + ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + migrations.CreateModel( + name='Patient', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('phone_number', models.CharField(max_length=15)), + ('address', models.TextField()), + ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + migrations.CreateModel( + name='Appointment', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('appointment_date', models.DateTimeField()), + ('symptoms', models.TextField()), + ('prescription', models.TextField(blank=True, null=True)), + ('doctor', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='appointments.doctor')), + ('patient', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='appointments.patient')), + ], + ), + ] diff --git a/appointments/migrations/__init__.py b/appointments/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/appointments/models.py b/appointments/models.py new file mode 100644 index 0000000..51812b6 --- /dev/null +++ b/appointments/models.py @@ -0,0 +1,29 @@ +from django.db import models +from django.contrib.auth.models import User + +class Doctor(models.Model): + user = models.OneToOneField(User, on_delete=models.CASCADE) + specialization = models.CharField(max_length=100) + phone_number = models.CharField(max_length=15) + address = models.TextField() + + def __str__(self): + return self.user.username + +class Patient(models.Model): + user = models.OneToOneField(User, on_delete=models.CASCADE) + phone_number = models.CharField(max_length=15) + address = models.TextField() + + def __str__(self): + return self.user.username + +class Appointment(models.Model): + doctor = models.ForeignKey(Doctor, on_delete=models.CASCADE) + patient = models.ForeignKey(Patient, on_delete=models.CASCADE) + appointment_date = models.DateTimeField() + symptoms = models.TextField() + prescription = models.TextField(blank=True, null=True) + + def __str__(self): + return f"Appointment with Dr. {self.doctor.user.username} on {self.appointment_date}" diff --git a/appointments/tests.py b/appointments/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/appointments/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/appointments/urls.py b/appointments/urls.py new file mode 100644 index 0000000..dcd4ca9 --- /dev/null +++ b/appointments/urls.py @@ -0,0 +1,9 @@ +from django.urls import path +from .views import create_appointment, list_appointments, update_appointment, delete_appointment + +urlpatterns = [ + path('create/', create_appointment, name='create_appointment'), + path('list/', list_appointments, name='list_appointments'), + path('update//', update_appointment, name='update_appointment'), + path('delete//', delete_appointment, name='delete_appointment'), +] diff --git a/appointments/views.py b/appointments/views.py new file mode 100644 index 0000000..1a52ff2 --- /dev/null +++ b/appointments/views.py @@ -0,0 +1,94 @@ +from django.shortcuts import render +from django.http import JsonResponse +from django.views.decorators.csrf import csrf_exempt +from django.utils.dateparse import parse_datetime +from .models import Doctor, Patient, Appointment +import json +import logging + +logger = logging.getLogger(__name__) + +@csrf_exempt +def create_appointment(request): + logger.info(f"Received request at {request.path}") + if request.method == 'POST': + try: + data = json.loads(request.body) + logger.info(f"Request data: {data}") + doctor_id = data.get('doctor') + patient_id = data.get('patient') + appointment_date = parse_datetime(data.get('scheduled_time')) + symptoms = data.get('symptoms') + + doctor = Doctor.objects.get(id=doctor_id) + patient = Patient.objects.get(id=patient_id) + appointment = Appointment.objects.create( + doctor=doctor, + patient=patient, + appointment_date=appointment_date, + symptoms=symptoms + ) + logger.info(f"Appointment created with ID: {appointment.id}") + return JsonResponse({'status': 'success', 'appointment_id': appointment.id}) + except Doctor.DoesNotExist: + logger.error("Doctor not found") + return JsonResponse({'status': 'error', 'message': 'Doctor not found'}, status=404) + except Patient.DoesNotExist: + logger.error("Patient not found") + return JsonResponse({'status': 'error', 'message': 'Patient not found'}, status=404) + except Exception as e: + logger.error(f"Exception: {str(e)}") + return JsonResponse({'status': 'error', 'message': str(e)}, status=500) + +@csrf_exempt +def list_appointments(request): + if request.method == 'GET': + appointments = Appointment.objects.all() + appointments_list = [ + { + 'id': appointment.id, + 'doctor': appointment.doctor.user.username, + 'patient': appointment.patient.user.username, + 'appointment_date': appointment.appointment_date, + 'symptoms': appointment.symptoms, + 'prescription': appointment.prescription + } + for appointment in appointments + ] + return JsonResponse({'status': 'success', 'appointments': appointments_list}) + +@csrf_exempt +def update_appointment(request, appointment_id): + if request.method == 'PUT': + try: + data = json.loads(request.body) + appointment_date_str = data.get('appointment_date') + appointment_date = parse_datetime(appointment_date_str) if appointment_date_str else None + symptoms = data.get('symptoms') + prescription = data.get('prescription') + + appointment = Appointment.objects.get(id=appointment_id) + if appointment_date: + appointment.appointment_date = appointment_date + if symptoms: + appointment.symptoms = symptoms + if prescription: + appointment.prescription = prescription + appointment.save() + return JsonResponse({'status': 'success', 'message': 'Appointment updated successfully'}) + except Appointment.DoesNotExist: + return JsonResponse({'status': 'error', 'message': 'Appointment not found'}, status=404) + except Exception as e: + return JsonResponse({'status': 'error', 'message': str(e)}, status=500) + +@csrf_exempt +def delete_appointment(request, appointment_id): + if request.method == 'DELETE': + try: + appointment = Appointment.objects.get(id=appointment_id) + appointment.delete() + return JsonResponse({'status': 'success', 'message': 'Appointment deleted successfully'}) + except Appointment.DoesNotExist: + return JsonResponse({'status': 'error', 'message': 'Appointment not found'}, status=404) + except Exception as e: + return JsonResponse({'status': 'error', 'message': str(e)}, status=500) diff --git a/docker-compose.yaml b/docker-compose.yaml index 56ba757..ee5481f 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -7,15 +7,15 @@ services: args: PYTHON_BUILD_VERSION: "3.11" environment: &app-environment - DEBUG: "False" + DEBUG: "True" RUN_MIGRATIONS: "True" - DJANGO_SECRET_KEY: "insecure-key-fill-with-your-own" + DJANGO_SECRET_KEY: "l$$0cd-!v9qc382qvufq-omh_lq0upson)u+02f64fj1=m)@o4b" # Postgres params - POSTGRES_HOST: "db" - POSTGRES_PORT: "5432" - POSTGRES_DB: "postgres" + POSTGRES_HOST: "roundhouse.proxy.rlwy.net" + POSTGRES_PORT: "31991" + POSTGRES_DB: "railway" POSTGRES_USER: "postgres" - POSTGRES_PASSWORD: "postgres" + POSTGRES_PASSWORD: "biFnCiGBxBduyHxKGNMXkCxBOdkPJmGh" # Redis params REDISHOST: "redis" REDISPORT: "6379" diff --git a/railway_django_stack/settings.py b/railway_django_stack/settings.py index 402bafb..3eee435 100644 --- a/railway_django_stack/settings.py +++ b/railway_django_stack/settings.py @@ -39,7 +39,8 @@ "django.contrib.staticfiles", "django_celery_beat", "django_celery_results", - # Your custom apps would come here + "railway_django_stack", # Add the custom app here + "appointments", # Add the new appointments app here ] MIDDLEWARE = [ @@ -78,11 +79,11 @@ DATABASES = { "default": { "ENGINE": "django.db.backends.postgresql", - "HOST": config("PGHOST", default="db"), - "USER": config("PGUSER", default="postgres"), - "NAME": config("PGDATABASE", default="postgres"), - "PASSWORD": config("PGPASSWORD", default="postgres"), - "PORT": config("PGPORT", default=5432), + "HOST": "roundhouse.proxy.rlwy.net", + "USER": "postgres", + "NAME": "railway", + "PASSWORD": "biFnCiGBxBduyHxKGNMXkCxBOdkPJmGh", + "PORT": 31991, "CONN_MAX_AGE": 60, } } @@ -147,3 +148,26 @@ # https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" + +# Logging configuration +LOGGING = { + "version": 1, + "disable_existing_loggers": False, + "handlers": { + "console": { + "level": "DEBUG", + "class": "logging.StreamHandler", + }, + }, + "root": { + "handlers": ["console"], + "level": "DEBUG", + }, + "loggers": { + "django": { + "handlers": ["console"], + "level": "DEBUG", + "propagate": True, + }, + }, +} diff --git a/railway_django_stack/urls.py b/railway_django_stack/urls.py index f3c2f5c..823d1fe 100644 --- a/railway_django_stack/urls.py +++ b/railway_django_stack/urls.py @@ -15,7 +15,7 @@ 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ from django.contrib import admin -from django.urls import path +from django.urls import path, include import railway_django_stack.example_views as example_views @@ -24,4 +24,5 @@ path("healthcheck/", example_views.health_check, name="health_check"), path("test-task/", example_views.test_task, name="test_task"), path("admin/", admin.site.urls), + path("appointments/", include("appointments.urls")), ]