1

I'm working on simple expense tracking app. Below you can find the view with all user's Operations (expense or income):

enter image description here

Based on this thread I implemented bootstrap modal window to display new operation form:

enter image description here

Below you can find ManageOperations view which is responsible for displaying views presented above:

class ManageOperations(ListView, FormView, OperationMixIn):

    model = Operation
    form_class = OperationForm
    template_name = "expenses/manage_operations.html"
    success_url = reverse_lazy('manage_operations')

    def get_context_data(self, **kwargs):
        context = super(ManageOperations, self).get_context_data(**kwargs)
        context['operations_list'] = Operation.objects.filter(user=self.request.user).order_by('-date')
        return context

    def get_form_kwargs(self):
        kwargs = super(ManageOperations, self).get_form_kwargs()
        kwargs.update(user=self.request.user,
                      initial={'account': Account.objects.get(user=self.request.user, default=True)})
        return kwargs

    def form_valid(self, form):
        operation = form.save(commit=False)
        operation.currency = Account.objects.get(pk=form.instance.account_id).currency
        self.update_account_balance(form)
        form.instance.user = self.request.user
        form.save()
        return super(ManageOperations, self).form_valid(form)

I'd like to implement same modal windows both for "edit" and "delete" actions. I assume that it will be quite simple for OperationDelete view:

class OperationDelete(DeleteView, OperationMixIn):

    model = Operation
    success_url = reverse_lazy('manage_operations')

    def delete(self, *args, **kwargs):
        self.restore_account_balance(self.get_object().pk)
        return super(OperationDelete, self).delete(*args, **kwargs)

I could just move delete method to my ManageOperations view and make it inherit from DeleteView.

Things are getting more complicated when it comes to editing existing Operation. Currently following code is responsible for handing an update of existing entry:

class OperationUpdate(UpdateView, OperationMixIn):

    model = Operation
    form_class = OperationForm
    success_url = reverse_lazy('manage_operations')

    def get_form_kwargs(self):
        kwargs = super(OperationUpdate, self).get_form_kwargs()
        kwargs.update({'user': self.request.user})
        return kwargs

    def form_valid(self, form):
        self.restore_account_balance(self.get_object().pk)
        self.update_account_balance(form)
        form.instance.user = self.request.user
        return super(OperationUpdate, self).form_valid(form)

If I tired to merge it into ManageOperations view I would have to deal with multiple implementation of get_form_kwargs and form_valid methods.

Could you please tell me if I'm going in right direction with this or there is better and more elegant way to solve my problem? Creating one big ManageOperations view which would be responsible for all Operations releated actions seems a little bit silly to me.

Arxas
  • 111
  • 7
  • 1
    I time ago, I had that problem with modalform to. Why not use function, function is much better when things get complicated. Also you could create a single model in the `.html` file without forms and use ajax to call the function you want. The problem rendering these modelforms is that it could render a modal for each item in the view – Mauricio Cortazar Dec 09 '17 at 18:05

1 Answers1

0

I believe your approach is fine, except I would make the UpdateView and DeleteView AJAX views instead: let them return JSON instead of an HTML template and call them using AJAX from your template.

  • Keep ManageOperations as is
  • In your Edit modal form, let AJAX use the form data to post it to your OperationUpdate view.
  • Change your OperationUpdate view to return a JSON response. You could go all the way and use Django REST Framework for this, but it's quite easy to adapt existing Django generic CBVs to return JSON: Override render_to_response() (for the case the form is not valid) and form_valid() methods. You just return the bound form fields (values) and the errors in your JSON. If the form is valid you return the saved object in your JSON so the javascript can update the corresponding values in the table.
  • Change your OperationDelete view to also return a JSON response.
  • Add processing of the JSON responses in your Javascript, to display form errors, close the modal, update the values in the table, etc...
dirkgroten
  • 20,112
  • 2
  • 29
  • 42