Django  —  это очень интересный фреймворк, который позволяет создавать веб-приложения с использованием Python для бэкенда. При этом он также может обрабатывать большинство функций базы данных и позволяет при работе по крайней мере с небольшими приложениями сосредотачиваться на основном, не отвлекаясь на сопутствующие процессы. 

Несмотря на то, что Django очень эффективен, освоить его не столь просто, что может напугать начинающих. 

В текущей статье я постараюсь упростить знакомство с этим инструментом и представлю некоторые из важнейших его возможностей и приемов.

1. Переиспользование кода шаблонов

В Django есть множество способов повторно использовать код, а также повышать его эффективность и читаемость. Один из таких  —  теги и фильтры шаблонов.

С их помощью можно писать логику внутри HTML-файла и отображать релевантные данные. Существует много встроенных тегов и фильтров, но можно создавать и свои. 

Один из таких тегов, include, позволяет переиспользовать HTML-код. Вот, как я применил его на своем сайте:

Последние статьи на домашней странице
Все статьи на странице Articles

Я хотел отображать последние статьи на странице “Home”, а также на странице “Articles”.

Поскольку дизайн карточки статьи остается таким же, то проще всего создать общий HTML и использовать его повторно на обеих страницах с помощью include. В коде это выглядит так:

<div class="articles-div container">
    <div class="left-col">
        {% for article in left %}
        {% include "main/includes/article.html" with link=article.medium_link image=article.image.url title=article.title tags=article.tags date=article.date_created %}
        {% endfor %}
    </div>

    <div class="right-col">
        {% for article in right %}
        {% include "main/includes/article.html" with link=article.medium_link image=article.image.url title=article.title tags=article.tags date=article.date_created %}
        {% endfor %}
    </div>
</div>

Перед вами фрагмент кода из index.html, реализующий отображение статей. Данные для них получаются из файла views.py.

Как видите, в этом фрагменте перебираются все статьи, предоставляемые файлом views.py, и для каждой из них создается {% include %}, добавляющий нужный HTML. (В следующем примере мы посмотрим, как файл views.py передает эти данные). Синтаксис использования include выглядит так:

{% include “file_name” with argument_name=”some_argument” second_argument_name=”another_argument” %}

Ключевое слово with является необязательным и используется при необходимости передачи в HTML аргументов. Для передачи строковых аргументов их нужно заключать в "". При этом также можно передавать переменные.

article.html  —  общий HTML-файл для всех карточек статей:

{% load static %}
<link rel="stylesheet" href="{% static 'css/include/articles.css' %}">

<a href="{{ link }}" target="blank">
  <div class="article">
      <img class = "article-img" src="{{ image }}" alt="">
      <h4 class="article-title">{{ title }}</h4>
      <ul class="tags">
          <li class="{{ tags }}">{{ tags }}</li>
          <p class="date">{{ date }}</p>
      </ul>

  </div>
</a>

Код выше предназначен для карточки статьи. В первой строке с помощью {% load static %} происходит обращение к статическим файлам, т.е. ко всем CSS, JS и изображениям. Чтобы использовать теги, передаваемые из тега include, необходимо поместить имя аргумента в {{}} подобным образом: {{ argument name }}.

Мы разобрали переиспользование HTML. Теперь рассмотрим представления, основанные на классах, которыми зачастую пренебрегают.

2. Представления на основе функций

Для начала хочу прояснить заблуждение относительно того, что представления на базе классов (CBV) лучше представлений на базе функций (FBV). 

Все зависит от конкретного случая, и у обоих этих способов есть свои недостатки. Я добавил в статью CBV, потому что они позволяют удалять лишние элементы кода, которые зачастую присутствуют при использовании FBV. Так что знать о CBV желательно.

Если вы уже реализовывали какой-либо проект Django, то с FBV должны быть знакомы. Их удобно создавать и читать, но не так удобно переиспользовать.

Django предлагает общие варианты представлений, которые можно наследовать в собственный класс, переопределив их содержимое. Получается, что большая часть всего уже создана, и нужно лишь настроить представления согласно собственным нуждам. Вот как я делал это в своем блоге.

Фрагмент файла views.py:

from django.views.generic import ListView
class ArticlePage(ListView):
    model = Articles
    template_name = "main/articles.html"

    def get_context_data(self, **kwargs):
        article_data = super(ArticlePage, self).get_context_data(**kwargs)

        tag = self.kwargs.get('tag', None)
        if tag != None:
            if tag in "Tech Programming Productivity Crypto":
                articles = Articles.objects.filter(
                    tags=tag).order_by('-date_created')
        else:
            articles = Articles.objects.order_by('-date_created')

        left, middle, right = left_middle_right(articles)
        article_data['left'] = left
        article_data['middle'] = middle
        article_data['right'] = right
        return article_data

ListView является одним из наиболее распространенных общих классов, которые я использовал для перечисления всех элементов базы данных. Для его применения нужно просто создать класс в файле views.py и наследовать его из django.views.generic import ListView.

В самом простом случае потребуется лишь создать переменную model, а Django разберется с остальным. По умолчанию шаблон имеет имя "model_name"_list.html, которое можно изменить, как сделал я выше.

Дальнейшая настройка предполагает переопределение функций. В моем случае нужно было отсортировать статьи по дате или тегам, после чего разделить их на три части для трех столбцов в файле шаблона. Ниже показано, как можно использовать articles_data в этом файле.

Фрагмент из articles.html:

<div class="articles-div container">
    <div class="left-col">
        {% for article in left %}
        {% include "main/includes/article.html" with link=article.medium_link image=article.image.url title=article.title tags=article.tags date=article.date_created %}
        {% endfor %}
    </div>
    <div class="mid-col">
        {% for article in middle %}
        {% include "main/includes/article.html" with link=article.medium_link image=article.image.url title=article.title tags=article.tags date=article.date_created %}
        {% endfor %}
    </div>

    <div class="right-col">
        {% for article in right %}
        {% include "main/includes/article.html" with link=article.medium_link image=article.image.url title=article.title tags=article.tags date=article.date_created %}
        {% endfor %}
    </div>

</div>

В предыдущем примере показано, как повторно использовать шаблоны при помощи include. В этом случае шаблон получает данные из left, right и middle переменной articles_data. Но это не то, что нам нужно. Для использования CBV нужно кое-что проделать в файле urls.py

Я подредактировал urls.py, чтобы упростить пример.

from .views import ArticlePage

app_name = "main"

urlpatterns = [
    path('articles', ArticlePage.as_view(), name="articles"),
]

Сначала нужно импортировать класс, после чего использовать его в urlpatterns с помощью функции as_view(). Причина в том, что преобразователь URL ожидает отправки запроса и аргументов в функцию, а не класс. Поэтому нужно просто использовать функцию .as_view(), а остальное оставить Django.

3. Объемный файл views.py

Файл views.py содержит большую часть логики, в связи с чем может разрастаться до сотен строк. Это сильно усложняет отладку и чтение кода. Вот как можно разбить этот файл без осложнений.

Скриншот каталога views

Создаем каталог views, а внутри него файл _init_.py. Теперь можно разбить файл views.py и поместить его функции или классы в отдельные файлы.

В моем случае я использовал файл views_a.py для всех CBV и создал дополнительные файлы для каждой операции.

Если вы разделите функции и классы из исходного views.py по нескольким файлам, то импортируйте все содержимое этих файлов в _init_.py, как показано здесь:

from .medium_scraper import *
from .views_a import *
from .articles import *

В показанном выше случае мне нужно импортировать только views_a. Дело в том, что все мои объекты представлений, которые будут использоваться в файле urls.py, находятся во views_a.

Если же в вашем случае они окажутся разделенными по нескольким файлам, то потребуется импортировать каждый.

urls.py:

from django.contrib import admin
from django.urls import path
from .views import *

app_name = "main"

urlpatterns = [
    path('home', Homepage.as_view(), name="home"),
    path('articles', ArticlePage.as_view(), name="articles"),
    path('articles/<str:tag>/', ArticlePage.as_view(), name="articles"),
    path('about', AboutPage.as_view(), name="about"),
    path('courses', CoursePage.as_view(), name="courses"),
    path('resources', ResourcesPage.as_view(), name="resources"),
    path('projects', views.projects, name="projects"),

]

В завершении введите from .views import *, чтобы импортировать все объекты представлений.

Читайте также:

Читайте нас в Telegram, VK и Яндекс.Дзен


Перевод статьи Shubh Patni: 3 Huge Mistakes Django Developers Make

Предыдущая статьяRUID - уникальные 64-битные идентификаторы для распределенных баз данных
Следующая статьяЭлементы минималистичного дизайна