dev740
dev740

Reputation: 121

Is there a better way to write this code so DRY can be maintained?

I have 2 models

  1. Tour to save Tour

  2. TourImage to save images related to Tour

    class Tour(models.Model):
        name = models.CharField(max_length=50)
    
    class TourImage(models.Model):
        tour = models.ForeignKey(Tour, on_delete=models.CASCADE)
        image = models.FileField(upload_to='images/')
    

In my views.py file I have the following code to save the Tour and the tour images

class CreateTourView(CreateView):
    model = Tour
    template_name = "create_tour.html"
    fields = "__all__"

    def form_valid(self, form):
        tour = form.save()
        for image in self.request.FILES.getlist("extra_images"):
            TourImage.objects.create(tour=tour, image=image)
    return super().form_valid(form)

The HTML form looks like this

<form action="" method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form | crispy }}
<input type="file" name="extra_images" multiple />
<input type="submit" value="Save" />
</form>

This works fine, the images are saved the Database.

But I also want to add option to edit Tour and add extra images, so the UpdateView code is as follows

class TourUpdateView(UpdateView):
    model = Tour
    template_name = "update_tour.html"
    fields = "__all__"

    def form_valid(self, form):
        tour = form.save()
        for image in self.request.FILES.getlist("extra_images"):
            TourImage.objects.create(tour=tour, image=image)
        return super().form_valid(form)

The .form_valid() method is same for both CreateView and UpdateView.

Is there a better way to code this so as to avoid repetitive code?

Upvotes: 2

Views: 51

Answers (1)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 477240

You create a mixin:

class TourImageMixin:
    model = Tour

    def form_valid(self, form):
        tour = form.save()
        for image in self.request.FILES.getlist('extra_images'):
            TourImage.objects.create(tour=tour, image=image)
        return super().form_valid(form)

Then you mix it in the two views:

class CreateTourView(TourImageMixin, CreateView):
    template_name = 'create_tour.html'
    fields = '__all__'

class TourUpdateView(TourImageMixin, UpdateView):
    template_name = "update_tour.html"
    fields = '__all__'

In fact Django's views, like for example the ListView [classy CBV] are constructed with mixins that define certain behavior. For the ListView the MultipleObjectTemplateResponseMixin [Django-doc], TemplateResponseMixin [Django-doc] and MultipleObjectMixin [Django-doc] are used.

Upvotes: 1

Related Questions