user7120561
user7120561

Reputation:

Django DRY - how to simplify similar views using same template?

Please note: Just to make clear '[app_name]' is a placeholder for the actual app name. Not Django substitution code. Just imagine it says 'Stuff' instead of [app_name], if it's confusing.

My question:

  1. How do I make this more DRY?

There is a lot of code repetition, and there must be a way of unifying some of it. If you do answer, I would be really grateful if you write out explicitly what and why. As a lot of answers assume quite a bit of knowledge and I am trying into good habits in Django coding style and practice. Thank you for your time.

[app_name]/urls.py

from django.conf.urls import url

from . import views

app_name = 'things'
urlpatterns = [
    url(r'^cars/$', views.CarThingIndexView.as_view(), name='Car_index'),
    url(r'^trees/$', views.TreeThingIndexView.as_view(), name='Tree_index'),
    ....
]

[app_name]/model.py

from django.db import models    
class Tree(models.Model):
        """
        Tree
        """
        name_text = models.CharField(max_length=200)

def __str__(self):
    return self.name_text

class Car(models.Model):
        """
        Car
        """
        name_text = models.CharField(max_length=200)

def __str__(self):
    return self.name_text

[app_name]/view.py

from django.views import generic

from inventory.models import Car, Tree


class CarThingIndexView(generic.ListView):
    template_name = '[app_name]/index.html'
    context_object_name = 'thing_list'

    def get_queryset(self):
        return Car.objects.values()


class TreeThingIndexView(generic.ListView):
    template_name = '[app_name]/index.html'
    context_object_name = 'thing_list'

    def get_queryset(self):
        return Tree.objects.values()

[app_name]/template/[app_name]/index.html

{% extends '[app_name]/base.html' %}
{% block content %}
    {% if thing_list %}

        <ul>
            {% for item in thing_list %}
                <li>
                    <p>
                        {{ item }}
                    </p>
                </li>
            {% endfor %}
        </ul>
    {% else %}
        <!-- I am pretty sure if there are no objects this will not work, please correct me if I am wrong {{ obj | get_class_name }}. I would like it to read "No Tree/Car are available." -->
        <p>No [class_name] are available.</p>
    {% endif %}
{% endblock content %}

Upvotes: 2

Views: 674

Answers (1)

dahrens
dahrens

Reputation: 3959

From my point of view everything is fine and there is no need abstract more in this case. At this point it looks like you can optimize it - but what you've scaffolded does not include any logic. Behind the scenes django already helps you a lot to not repeat yourself here!

When you now start implementing features for your cars and trees the views, models and templates will go in different directions. Next to the name they will have different properties. They act different and were displayed different. This is what usually happens in your application.

If you have a set of models that share a lot of properties and the representation django provides mechanisms like abstract base classes for models properties and methods or the include and extends template tags, if you need to share representations. Regarding view logic that should be shared you might write your own modules or even packages to do whatever you need to do and use them inside your views.

Without real use cases in mind you should not think about how to not repeat yourself at this point.

Upvotes: 2

Related Questions