Lewis
Lewis

Reputation: 2798

Django: How to reduce size and increase cohesion of views

As my project is becoming bigger and bigger, I am starting to get very large CBVs because they are required to handle a lot of functionality especially live responses through AJAX (Single Page Application style).

For example I have class ScheduledBooking. It does everything from showing timelines of bookings, booking appointments and viewing/editing other appointments in one page.

I utilise a variety of model managers for complex filtering/aggregation but not sure if it's Pythonic to extend the role responsibilities these managers to handling booking actions such as allocating bookings, checking availability of bookings, broadcasting bookings changes (Even if they use other models)? This will aim to reduce size and increase cohesion of the view (although the model manager then will just take on the workload affecting it's own level of cohesion). Or is there a better way/alternative method for this?

Another problem is the Live Responses from AJAX calls. I use a large amount due to a single page application style although the action handling is clogging up a lot of the view. I was wondering if there is an alternative place or way this can be handled?

class ScheduledBooking(TemplateView, BetterFormsChoiceValidationMixin, SessionHandlerMixin, BookingMixin, AJAXFormSerialiserMixin):
    template_name = 'emissions_dashboard/booking_scheduled.html'

    def get_context_data(self):
        [... 20 lines..]
        return args


    def get(self, request, *args, **kwargs):    
        [... 2 lines ..]
        return render(request, self.template_name, self.get_context_data())


    def check_availability(self, start_datetime, end_datetime):
        ''' Checks if booking slot is still available and returns True
            if meets criteria
        '''
        [... 10 lines ...] 
        return False
        

    def allocate_booking(self, requested_start_datetime, requested_end_datetime, booking_id):
        ''' Allocates booking by changing status to 'Allocated'.
            Stops other users from using timeslot
        '''
        [... 10 lines ...]


    def live_responses(self, request, booking_id):

        if 'replication_form' in request.POST:
            ''' If a booking requires replicating it is handled here
            '''
            [... 30 lines ...]
                return JsonResponse({'form_validate':False,'form_errors':replicate_form.errors})
   
        if 'change_dates' in request.POST:
            ''' Allows users to change booking date range
            '''
            [... 20 lines ...]
            return JsonResponse({'valid_dates':False,'booking_html':None})

        [... 8 more live response handling (400+ lines) ...]


    def broadcast(self, booking, _type=None):
        ''' broadcasts change to other users via 'django-channels'
        '''
        [... 100 lines ...]


    def building_records(self, request, forms, booking_id):
        ''' Handles main booking form that requires a redirect after submit (non-ajax)
        '''
        [... 30 lines ...]


    def post(self, request, booking_id=None, room_name="", *args, **kwargs):
        ''' handles all post requests
        '''
        if request.is_ajax():
            live_response = self.live_responses(request, booking_id, *args, **kwargs)
            if live_response:
                return live_response
        [... 50 lines ...]
 

I understand this is fairly subjective question but happy to hear other ideas/suggestions to assist my learning.

Upvotes: 1

Views: 458

Answers (1)

LukasKlement
LukasKlement

Reputation: 527

The often quoted principle here is: "Fat models, skinny views". Add to this, as you rightly mentioned, fat managers.

In principle, all model methods should only have your database as their only dependency. When dealing with external APIs, bundle the functionality in separate modules. Much of the business logic can also be offloaded to utils.py files (utils_broadcast.py, ...).

Upvotes: 1

Related Questions