1

I have 3 models Clinic, Doctor, DoctorHours I want to create a dynamic form which will allow me to create those instances in one form something like this:

-ClinicForm

--add_doctor_button

--DoctorForm

----add_doctor_hours_button

----DoctorHoursForm

----DoctorHoursForm

--DoctorForm

----add_doctor_hours_button

----DoctorHoursForm

----DoctorHoursForm

----DoctorHoursForm

Please help

My best try:

view:

class CreatePracticeFormView(FormView):
    template_name = 'admin/practices/create_form.html'
    form_class = PracticeCreateForm
    success_url = '/admin/emr/practice/'

    def form_valid(self, form):

        print(self.request.POST)

        return super().form_valid(form)

forms:

class DoctorWorkingHoursForm(forms.Form):

    week_day = forms.ChoiceField(choices=DoctorWorkingHours.WeekDay.choices)
    start_time = forms.TimeField(required=True)
    end_time = forms.TimeField()


DoctorWorkingHoursFormSet = forms.formset_factory(DoctorWorkingHoursForm, extra=0)


class DoctorCreateForm(forms.Form):

    first_name = forms.CharField(required=True)
    last_name = forms.CharField()
    npi = forms.EmailField()
    specialty = forms.ModelChoiceField(queryset=Speciality.objects.all())
    credentials = forms.CharField()
    hours = DoctorWorkingHoursFormSet()

DoctorCreateFormSet = forms.formset_factory(DoctorCreateForm, extra=0)

class PracticeCreateForm(forms.Form):

    name = forms.CharField()
    type = forms.CharField()
    primary_contact_name = forms.CharField()
    ehr = forms.ModelChoiceField(queryset=EHR.objects.all())
    scheduling_extension = forms.ModelChoiceField(queryset=SchedulingExtension.objects.all())
    primary_visit_type = forms.ModelChoiceField(queryset=VisitType.objects.all())
    secondary_visit_type = forms.ModelChoiceField(queryset=VisitType.objects.all())
    doctors = DoctorCreateFormSet()

DoctorCreateFormSet = forms.formset_factory(DoctorCreateForm, extra=0, formset=BaseDoctorCreateFormset)

Here what I get is the forms in template where I can dynamically add DoctorForm and HourForm with jQuery and get that data in the view

but how to validate and assemble this data into objects it is the big question

Vlad Ivanyk
  • 57
  • 10

1 Answers1

1

This is a simple example of what you could do. It is not exactly nested. But it will provide most of the functionality you are looking for.

# admin.py
from django.contrib import admin
from .models import Clinic, Doctor, DoctorHours


class DoctorHoursInline(admin.TabularInline):
    model = DoctorHours


@admin.register(Doctor)
class DoctorAdmin(admin.ModelAdmin):
    # stuff
    inlines = [DoctorHoursInline,]
    # more stuff


class DoctorInline(admin.TabularInline):
    model = Doctor

    # This will show a link to edit the Doctor model
    # in the Doctor table of the Clinic change form.
    show_change_link = True 


@admin.register(Clinic)
class ClinicAdmin(admin.ModelAdmin):
    # stuff
    inlines = [DoctorInline,]
    # more stuff

You may of course want to swap out the forms on each of these ModelAdmin and TabularInline classes.

Docs: https://docs.djangoproject.com/en/4.0/ref/contrib/admin/#inlinemodeladmin-objects

Daniel Morell
  • 2,308
  • 20
  • 34
  • 2 classes ClinicAdmin is intended ? – Vlad Ivanyk Jan 06 '22 at 18:18
  • Oops! good catch! – Daniel Morell Jan 06 '22 at 18:19
  • hmmm I just see the TabularInline or StackedInline of the Doctors (which is 1st phase of what needed ) in the Clinic change view but no ability to edit hours from there – Vlad Ivanyk Jan 06 '22 at 18:29
  • There should be a link in the `DoctorInline` to edit the hours. You may need to save the Clinic before the link will be available. I know this is not the cleanest, but it is the best that is available without 3rd party code or JS. – Daniel Morell Jan 06 '22 at 18:33
  • yeah, that is why I was drafting the separate admin view with form with formset inside with formset inside anyway thank u for help and your time! – Vlad Ivanyk Jan 06 '22 at 18:41
  • If you need one form for creating and one for editing you can override the admin class `get_form` method. That keeps you from needing to create a separate view. – Daniel Morell Jan 06 '22 at 20:17