Django Was Rude But Now Seems Friendlier!

The last time I praised Flask over Django, I decided to tinker with Django a lot more. Lately, I have become warmer to Django by a lot. Now, I see Django is quite fun to program with. Although I could see Django is scary to beginner Python programmers, it’s not that hard at all if you tinker with it long enough. For example, Django could look scary to new Python programmers because they have to learn a whole new mature framework like Django – which means they have to know a whole new set of rules. Personally, at first, I hated how Django used different files for routing URLs. Nowadays, I think this is brilliant! I mean, nowadays, I instinctively know in the core project’s folder, I can include other apps’ urls.py in the urls.py that reside in the core project’s folder.

urlpatterns = [
    path('accounts/', include('account.urls')),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

The code above is a snippet of the example code of urls.py in Django’s core project folder. The ‘accounts/’ part is how you navigate to your http://www.example.com/accounts/. The include(‘accounts.urls’) part is where you tell Django, hey there are other url parts that you must join them with the accounts/ part to make a whole new URL that would route to a specific view that perform something for the app that uses ‘accounts/’ part. In my project, I named the app as account; in the main project folder’s urls.py I used path(‘accounts/’… to send visitors to account app, but I also told Django that it must look inside the urls.py inside the account app – this is why I used the part that said include(‘account.urls.’).

urlpatterns = [
    path('register/', views.register, name='register'),
    path('login/', views.login, name='login'),
]

The code above is a snippet of the example code of urls.py inside the Account app. By now, if you don’t know Django, you may get confused about why I keep saying app this app that. Basically, Django allows you to start a project which you can name however you want. Inside this project, you can create multiple apps. Each app should focus on a specific task that allows your whole project to perform brilliantly. For example, the account app in my Django project should have codes that focus on allowing visitors that come to my Django website to register, log in, visit Dashboard, and do a whole lot of things that are related to the meaning of having an account.

The snippet code of the urls.py inside the account app clearly shows that I created path parts for register and login. Meaning, a visitor who visits my Django website can register for an account by going to example.com/accounts/register/. Same goes for login. The views.register or views.login part tells Django, hey you – you need to use the views from the views.py inside the account app that got function based views with names like register and login. Of course, you can also use class based views inside views.py, but it’s outside the scope of what I want to talk about in this post. Anyhow, the name=’register’ and name=’login’ parts tell Django, hey – whenever I return render(request, register.html, context) for the function-based view register (same goes for login) – if I use the register name inside any other template pages and doing something like {{ url ‘register’ }} or fully like:

<a href="{% url 'register' %}" class="s-btn s-btn-2 w-100">Register Now</a>

…this means Django should redirect or render the register.html page so the visitor could sign up for an account with my website. The same logic goes for login. Based on the examples above, you could basically see how simple it is to route requests to any HTML page as long you set the views to render the correct HTML pages – and then use the correct views’ names inside any HTML templated page.

Django is all about Model, View, and Controller setup (MVC). By this, I mean the structure of the Django project folder emphasizes a project folder first, app folder second, inside the app folder you got models.py, views.py, urls.py, forms.py, and whatnot. The important files are models.py, views.py, and urls.py – this should form the MVC pattern nicely.

The models.py is responsible for allowing you to create models for the app. The views.py allows you to create views for the app. The examples above show you that views.py can render pages like register.html and login.html. More than just rendering HTML pages, the views can perform all sorts of logic such as calculating something, then allowing the calculation results to show up inside the rendered page such as — if you write a view for the cart.html page, you want to show the result of grand total which calculates the total cost of each item in the shopping cart including the shipping fee and sale tax. The urls.py allows you to route the requests to all sorts of places – for example, urls.py would allow the views to render HTML pages.

More about the models.py. Although you can create logic inside views.py, some people prefer to keep the views.py thin and create more logic inside the models.py which makes the models.py fat. This means the models.py will contain more logic for the app than the views.py. For example, a Product model contains fields such as product_name, price, and other product-related fields. Yet, you can create a custom method inside the model to return whatever. This is a quick and easy way to allow any query to your model can also get a specific result back by also calling the method inside the model.

class Product(models.Model):
    product_name = models.CharField(max_length=255, unique=True)
    slug = models.SlugField(max_length=255, unique=True)
    product_description = models.TextField(max_length=2500, blank=True)
    stock = models.IntegerField()
    is_available = models.BooleanField(default=True)
    category = models.ForeignKey(Category, on_delete=models.CASCADE)
    created_date = models.DateTimeField(auto_now_add=True)
    modified_date = models.DateTimeField(auto_now=True)
    homepage_display = models.BooleanField(default=False)
    user_wishlist = models.ManyToManyField(Account, related_name='user_wishlist', blank=True)
    brand = models.CharField(max_length=255, blank=True, null=True)
    count_sold = models.IntegerField(default=0, null=True, blank=True)
    sku = models.CharField(max_length=100, blank=True, null=True)

    def get_url(self):
        return reverse('product_detail', args=(self.category.slug, self.slug))
	
    def __str__(self):
        return self.product_name

The snippet code of models.py above is for a Product model in one of my Django’s projects. This model got a lot more custom methods and codes – but I just take a small snippet of the model to show you the example of creating a custom method get_url. This get_url method returns a product’s URL easily. For example, inside a store page (shop.html), you can:

{% for product in products %}
    <a href="{{ product.get_url }}">
    {% if product.image_1 %}
        <img src="{{ product.image_1.url }}" alt="{{ product.product_name }} image {{ product.id }}">
    {% else %}
        {% if product.get_image_links_for_product_home %}
            <img src="{{ product.get_image_links_for_product_home.0 }}" alt="{{ product.product_name }} image {{ product.id }}">
        {% endif %}
    {% endif %}
    {% if product.image_2 %}
         <img src="{{ product.image_2.url }}" alt="{{ product.product_name }} image {{ product.id }}">
    {% else %}
         {% if product.get_image_links_for_product_home %}
             <img src="{{ product.get_image_links_for_product_home.1 }}" alt="{{ product.product_name }} image {{ product.id }}">
         {% endif %}
    {% endif %}
    </a>
{% endfor %}

You don’t have to get confused by the code above because what matters right now is the part where it says <a href=”{{ product.get_url }}”>. This is where I begin to create a link for the product’s images — I use <a href=””>images go here</a>, and inside <a href=””> I have {{ product.get_url }}. Remember? I had shown the example above where a method get_url got created inside the Product model.

def get_url(self):
        return reverse('product_detail', args=(self.category.slug, self.slug))

The line of code above specifically! You don’t need to understand every detail of this code because right now it’s more important for us to take note of what the code does. The code above returns a URL for a product. So, whenever you query the Product model to show a product, you can conveniently call the get_url along with it to get the URL of a product easily. This is why in the template of shop.html I can just do <a href=”{{ product.get_url }}”>product images go here</a> to allow a visitor to click on the images to go to a product’s detail page easily. I don’t need to go find the correct URL for each product and write a long URL out inside the <a href=”#”></a>part. This is why a lot of people are writing logic inside the models.py to get things going their way. They prefer to write logic inside models.py over views.py because they can interact with the model inside the same .py file.

In summary, I think I rant on long enough, I think Django is scary for beginners, but Django can be rather safe for the beginners too — because Django would constantly deny the beginners from making mistakes — if a beginner makes a mistake Django won’t render anything but just errors. Nonetheless, this could be a source of frustration for some beginners as they see that they got too many errors that crash their Django project/apps. I think as long you tinker with Django long enough, you get familiar with how Django wants you to write your codes and smooths out the errors — you’ll be OK and have fun with coding with Django!

By the way, I just finished a Django project which you can now visit at https://sassigen.com. Also, I made an advertisement for the website which you can check out right after the break. Enjoy!