Evgenii Legotckoi
Evgenii LegotckoiSept. 18, 2016, 3:41 a.m.

Django - Tutorial 003. Model, Template, View on Django

In Django uses a modular system of applications, where one application is composed of several applications, each responsible for its functionality. As you have noticed, at the time of this writing, the site has a section "Knowledge", in which there are several sections, which have divided the article.

When working with the previous site on Wordpress, mindlessly spend time on the addition of new articles to the list of lessons on Qt. On this same site the page is automatically generated and save a new article is published with the status, this article will automatically enters the relevant section of the list.

I suggest to understand how it is implemented in a minimal version of the example EVILEG COM.


Project structure

Specifically, this website uses two applications in the project:

  1. home - an application that is responsible for the main index page, error pages and basic templates
  2. knowledge - application which meets just for the articles and sections of articles

If you look in detail, the structure of the project will be as follows:

mysite/
    manage.py
    mysite/
        __init__.py
        settings.py
        urls.py
        wsgi.py
    home/
        __init__.py
        admin.py
        apps.py
        models.py
        tests.py
        urls.py
        views.py
        templates/
            home/
                base.html
    knowledge/
        __init__.py
        admin.py
        apps.py
        models.py
        tests.py
        urls.py
        views.py
        templates/
            knowledge/
                article.html
                index.html
                section.html

A few words about the project creation and application in the project. We used PyCharm development environment, which prepares the project with included core modules, including the admin, so I will talk about that was not included by default.

You should use the following command to create the application:

python manage.py startapp home
python manage.py startapp knowledge

Configuration the settings.py

In order to have available application modules, you should connect them in the configuration file of the project.

INSTALLED_APPS = [
    'home.apps.HomeConfig',
    'accounts.apps.AccountsConfig',
    ...
]

Model

The project uses two kinds of models:

  1. Section - Sections, which bring together all the articles one by one common feature, membership in a particular category
  2. Article - Articles

The model is described in the file models.py

For the development of these models have been used to inherit from the built-in Django Class Model. And use the model of the user User, as specified in the articles of the author of the number of registered users on the site.

from django.db import models
from django.contrib.auth.models import User

Section

Section model consists of:

  1. Title
  2. URL - is used for the formation of the addresses on the site, that is not stored absolute paths, as part of the path to the list
  3. Description - is displayed in the top of the page before the list of articles

Let's look at the implementation of the model code:

class Section(models.Model):
    class Meta:
        db_table = "section"

    section_title = models.CharField(max_length=200)
    section_url = models.CharField(max_length=50)
    section_description = TextField()

    def __str__(self):
        return self.section_title

Meta class allows you to override some of the parameters of the model, which are directly related to the tables in the database. In this case determined, as will be called the Table.

The model has three fields, two of them have type CharField , which implies small recording limited number of input characters.

TextField type implies that there will be introduced a large enough random array of characters, the maximum size of which is not known beforehand.

Override str , and this is an override and not the new method makes it possible to return the title of the article that will appear in the admin panel. The fact is that if this method is not overridden, then all records in admin page will look like Section Object, and to understand where and what is to be very problematic when a large number of sections.

Article

The model consists of the following fields:

  1. Name
  2. Section - a foreign key to the Section table, determines the articles belonging to a particular section
  3. Author - a foreign key to the Users table from which will choose the author
  4. Date - date and time of publication
  5. Content - text field, similar to the description like in the Section model
  6. Status - I am assuming several statuses for articles currently used only two:
    1. Draft - the value 0
    2. Posted - the value 1
class Article(models.Model):
    class Meta:
        db_table = "article"

    article_title = models.CharField(max_length=200)
    article_section = models.ForeignKey(Section)
    article_author = models.ForeignKey(User)
    article_date = models.DateTimeField('Дата публикации')
    article_content = TextField()
    article_status = models.IntegerField()

    def __str__(self):
        return self.article_title

Register models in the admin

In order to be able to edit articles and sections of the admin, you must register them in the admin module. This is done in admin.py relevant application file.

from django.contrib import admin

from .models import Section, Article

admin.site.register(Section)
admin.site.register(Article)

Migration

Wrote model, sure that the models have all the required fields? Then you need to make a database migration. To do this, execute the following commands.

python manage.py makemigrations
python manage.py migrate

Note

Primary Key in the general case is entered automatically and is auto-increment, so we do not indicate it.

Templates

Templates Django's just a wonderful thing, especially when you consider that they can be inherited, and certain blocks will be overridden.

The project created a basic template base.html home application, from which all the other pages were inherited. Conditional template structure is as follows:

{% block head %}
{% endblock %}
{% block content %}
    {% block page %}
    {% endblock page %}
    {% block sidebar %}
    {% endblock %}
{% endblock content %}
{% block footer %}
{% endblock %}

In this case, there are five units, which can be overridden during inheritance patterns in other pages.

index.html

This template application's main page displays a list of all the sections. Use the extends statement, we specify that inherit from the base application template home. A duplicated page block of the base template, and prescribing the contents of this block we redefine the basic pattern making the information we need for a particular page.

As you can see, in the Django template language used the following constructions: if, for, url. But where did the variables section_list and section ? - Section_list passed as context values in a template in preparing the data in the presentation (view). After ensuring that there is a list of sections, we go through all the items in the list by substituting values into the template. Since the model section corresponds to Section, the corresponding fields of the model name are picked up automatically.

With regard to the url , then the operator indicates that it is necessary to take the address of the template knowledge application named section called, and we know that this address has a variable pattern, which we assign url object section. These templates are described in the file urls.py. We look at them later.

{% extends 'home/base.html' %}
{% block page %}
    <article>
    <h1>Разделы</h1>
    {% if section_list %}
        <ul>
        {% for section in section_list %}
            <li>
            <a href="{% url 'knowledge:section' section.section_url %}">{{ section.section_title }}</a>
            </li>
        {% endfor %}
        </ul>
    {% endif %}
    </article>
{% endblock %}

section.html

In the Template list, there is the formation of articles that match this razdlu. The context into the template variable section is transmitted, which contains information about the object section. We substitute the section title and description. Note that description is substituted with special argument safe, which indicates the format preservation. This must be done to save the html markup, otherwise the user will see instead a beautifully designed layout html code descriptions.

Also here it is a variant with a getting of information about all the articles that refer to this list, and this is done with the help of section.article_set.all call, that is, we take all the articles that have a foreign key to this section. Well, sort articles using dictsort specifying the parameter on which they are sorted.

A block if is checked the status of the article, that is, those items which are not published, will not be displayed.

With regard to the url , then again used the address template, but with two arguments.

{% extends 'home/base.html' %}
{% block page %}
    <article>
    <h1>{{ section.section_title }}</h1>
        <p>{{ section.section_description|safe }}</p>
        <h2>Статьи</h2>
        <ul>
        {% for article in section.article_set.all|dictsort:'article_title' %}
            {% if article.article_status %}
            <li>
            <a href="{% url 'knowledge:article' section.section_url article.id %}">
                {{ article.article_title }}
            </a>
            </li>
            {% endif %}
        {% endfor %}
        </ul>
    </article>
{% endblock %} 

article.html

As you can see, the template for the article meager enough to add something about it.

{% extends 'home/base.html' %}
{% block page %}
    <article>
        <h1>{{ article.article_title }}</h1>
        <p>{{ article.article_content|safe }}</p>
    </article>
{% endblock %}

Note

If you look at the structure of the project, to see that the application contain more templates folder folders that have the same name as the application and page templates are already in them. This is done in order to accurately determine which template will be used. Django looks for templates in all folders and selects the first pattern that matches the name. And if the names are crossed, such as the index.html, the wrong template may be selected. Therefore namespace is used to determine what exactly the desired template.

View

In this case, the work with the presentation of sufficiently limited, so bring at once a full listing views.py file.

We inherit from the View class and override the method get, which is responsible for the execution of a GET request, that is, the user page request. We also import render_to_response methods, which will process the template in the required context, and get_object_or_404 , which will automatically return a 404 error if the object is found, the corresponding variable.

In EKnowledgeIndex we get everything Sections, which sorted by name and placed in the context of the name section_list, you remember that this variable was used in the template index.html .

In ESectionView already taken concrete section, the argument that is passed to the requested url. kwargs just responsible for variables that delaminate from the url of the template specified in the file urls.py.

In EArticleView everything is much more interesting. The fact that the two variables used url template, but for the article is enough to make a request for id, then have a Primary Key, which is passed to the url.

from django.views import View
from django.shortcuts import render_to_response, get_object_or_404

from .models import *


class EKnowledgeIndex(View):
    template_name = 'knowledge/index.html'

    def get(self, request, *args, **kwargs):
        context = {}
        context['section_list'] = Section.objects.all().order_by('section_title')

        return render_to_response(template_name=self.template_name, context=context)


class ESectionView(View):
    template_name = 'knowledge/section.html'

    def get(self, request, *args, **kwargs):
        context = {}
        section = get_object_or_404(Section, section_url=self.kwargs['section'])

        context['section'] = section

        return render_to_response(template_name=self.template_name, context=context)


class EArticleView(View):
    template_name = 'knowledge/article.html'

    def get(self, request, *args, **kwargs):
        context = {}
        article = get_object_or_404(Article, id=self.kwargs['article_id'])

        context['article'] = article

        return render_to_response(template_name=self.template_name, context=context)

URL templates

Well, all that you need to write, but there was quite a bit to make it work, namely to configure url patterns, requests will be processed on that.

A feature of Django is that these templates are checking on regular expressions, and are not derived from models of controllers. For me personally, this approach proved to be clear and transparent, and I like him. So let's see how to revitalize our pages.

mysite/mysite/urls.py

First we need to set patterns in mysite / mysite / urls.py file that will determine which application to send a request. Here you can see that there is a trend in home application, there is shown the main page of the site, but I will not go into a description of the parts because of it we do not speak in this article. There is also a trend in the admin site and application knowledge, which is responsible just for the sections and articles.

A include , connected urls.py files in the home and knowledge applications.

from django.conf.urls import url, include
from django.contrib import admin

urlpatterns = [
    url(r'^', include('home.urls')),
    url(r'^knowledge/', include('knowledge.urls')),
    url(r'^admin/', admin.site.urls),
]

mysite/knowledge/urls.py

app_name is responsible for the namespace in the templates. Remember? Just above the template was recording 'knowledge: section'
.

Well, regular expressions define what and where will be sent. With regard to records

and , then these are the variables that get processed in the method in the submissions and transmitted via kwargs .

Well, name specifies a URL template name, that is the second part in the 'knowledge: section' .

And finally, I would like to note is the ^ symbol, which is present in the template. With it has discarded the recognized part of the template. That is, in these url is also present in the early knowledge /, which was previously recognized in mysite / mysite / urls.py.

from django.conf.urls import url

from . import views

app_name = 'knowledge'
urlpatterns = [
    url(r'^$', views.EKnowledgeIndex.as_view(), name='index'),
    url(r'^(?P<section>[\w]+)/$', views.ESectionView.as_view(), name='section'),
    url(r'^(?P<section>[\w]+)/(?P<article_id>[0-9]+)/$', views.EArticleView.as_view(), name='article')
]

For Django I recommend VDS-server of Timeweb hoster .

We recommend hosting TIMEWEB
We recommend hosting TIMEWEB
Stable hosting, on which the social network EVILEG is located. For projects on Django we recommend VDS hosting.

Do you like it? Share on social networks!

ПК
  • March 3, 2018, 6:26 a.m.

Спасибо за ваши статьи. Очень понятно и качественно пишите. Есть пара моментов в  данной статье, которые мне кажутся спорными. Например, именование полей внутри моделей(article_title, article_date вместо просто title и date). Думаю добавлять в качестве префикса имя модели несколько избыточно - поля без модели не используются и без всяких префиксов всегда понятно откуда они. Второй момент это использование в шаблоне для ссылки на конкретный объект тег url. Гораздо удобнее реализовать для модели метод get_absolute_url и использовать его. Это даст возможность полностью менять схему урлов без поиска и переписывания всех шаблонов. К тому же этот метод используется стандартной админкой для формирования ссылок "посмотреть на сайте". Ну и ваши представления легче было наследовать от соответсвующих generic views - DetailView, ListView.
Хотя может это всё допущения чтобы не усложнять материал.

Evgenii Legotckoi
  • March 4, 2018, 3:14 p.m.

Спасибо за отзыв.

По факту согласен со всеми вашими примечаниями.
Но это действительно допущения, чтобы не перегружать материал всем подряд. А так да, активно пользуюсь get_absolute_url и дженериками . В одной статье есть и про дженереки информация.
Владислав Меленчук
  • April 27, 2020, 9:35 a.m.

Хотелось спросить, можно ли создать многоуровневые url из свойств модели? Я вот с часик лежал, искал как это сделать не нашел, вопрос на хабре оставил, никто не ответил. Оригинальная документация говорит только об одном слаге, а все примеры заканчиваются на том, что есть домен и к нему slug. Я просто хотел прикрепить запись к определенной категории, и еще одной субкатегории, т.е типо домен/категория/подкатегории/запись
я сделал подобное, но блин, доступ к записи осуществляется даже с др.категории и вообще с любимым текстом, т.е ссылка каноническая, могу перейти и по test/test/запись и по nowork/test/запись, передавал в модель свойства вот так: kwargs=("url":self.url, "cat":self.cat.url, "sub":self.sub.url)

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

Но там я формирую полный путь, укладываю его в slug, а вот url шаблон у меня сделан так

path('<path:slug>/', PageView.as_view(), name='page')

Но у меня реализация там сделана за счёт того, что я задаю частичный url, который собирает все parent страницы формирует уже итоговый url и кладёт его куда надо.

Ещё делал раньше как вы делаете, но я так полагаю, что у вас код смотреть нужно, наверняка у вас неправильно написан код где-то:

  • или метод get_absolute_url
  • или url диспетчера.
  • или не выкидываете ошибку 404 по View, если из сформированного url не удаётся найти объект.

К слову говоря, если делали по этой статье, то там тоже в EArticleView нужно ещё добавить проверку на slug раздела, и если не совпадаетЮ, то выкинуть ошибку 404. Так что да, косяк в статье.

Владислав Меленчук
  • April 27, 2020, 9:53 a.m.
  • (edited)

Я делаю вот так у себя в модели для получения ссылки:
Там где доработать это я закомментил, ибо получалось доступность по всем категориям, потом выяснил, что так вообще по всей ссылки.

models.py

# Формируем URL
    def get_absolute_url(self):
        #games = self.games.all()[0] доработь 'games': games.url, ->
        return reverse('article_detail', kwargs={'category': self.category.url, 'slug': self.url})

Вьюшка:

# Полная статья
class ArticleDetail(DetailView):
    model = Article
    slug_field = "url"

URLs

path('articles/<category>/<slug>/', views.ArticleDetail.as_view(), name="article_detail"),

Запись доступна по articles/blog/название статьи, но таким же образом она доступна к неподвязанной категории, т.е articles/files/название статьи
Также можно любой текст можно подставить, articles/131411414/название статьи и будет тоже доступно.

Ну я так и думал. Здесь нужно или обычный View использовать, или формировать slug так, чтобы он содержал slug категории, и как у меня использовать path, но тут тогда будет проблем в том, что тогда url категории скорее всего перестанет работать.

Так что или берите обычный View, добавляйте туда метод get, и проверяйте как slug статьи, так и slug категории, которая будет привязана к статье, либо переопределяйте метод get_object у DetailView, но там также нужно будет ковырять как slug статьи, так и slug категории

Хорошо, посмотрю что получится с простым View

МЗ
  • Jan. 8, 2021, 3:05 p.m.

Отлично. Спасибо. Вопрос, как мне теперь передать на индексную страницу(ту которая по умолчанию) содержание только статей, без секций? И вообще передать на дефолтную страницу? Что то не получается. PS: в джанго - недавно, неделю.

МЗ
  • Jan. 8, 2021, 3:18 p.m.

Я дура. Разобралась. Но, остаюсь вашим читателем)

МЗ
  • Jan. 9, 2021, 2:30 p.m.
from django.shortcuts import *
from django.http import *
from django.http import HttpResponseRedirect
from django.contrib.auth.forms import *
from django.urls import reverse_lazy
from django.views import generic
from django.views.generic import *
from .models import Post

# Create your views here.
def index(request):
    postview = Post.<- а object отсуствует?
    return render(request,'index.html')
def about(request):
    return render(request,'about.html')
def contact(request):
    return render(request,'contact.html')
def home (request):
    return render(request, 'home/index.html')
class SignUpView(generic.CreateView):
    form_class = UserCreationForm
    success_url = reverse_lazy('login')
    template_name = 'signup.html'


МЗ
  • Jan. 9, 2021, 2:31 p.m.

отсутствует object

Comments

Only authorized users can post comments.
Please, Log in or Sign up
B

C++ - Test 002. Constants

  • Result:16points,
  • Rating points-10
B

C++ - Test 001. The first program and data types

  • Result:46points,
  • Rating points-6
FL

C++ - Test 006. Enumerations

  • Result:80points,
  • Rating points4
Last comments
k
kmssrFeb. 9, 2024, 7:43 a.m.
Qt Linux - Lesson 001. Autorun Qt application under Linux как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
Qt WinAPI - Lesson 007. Working with ICMP Ping in Qt Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
EVA
EVADec. 25, 2023, 11:30 p.m.
Boost - static linking in CMake project under Windows Ошибка LNK1104 часто возникает, когда компоновщик не может найти или открыть файл библиотеки. В вашем случае, это файл libboost_locale-vc142-mt-gd-x64-1_74.lib из библиотеки Boost для C+…
J
JonnyJoDec. 25, 2023, 9:38 p.m.
Boost - static linking in CMake project under Windows Сделал всё по-как у вас, но выдаёт ошибку [build] LINK : fatal error LNK1104: не удается открыть файл "libboost_locale-vc142-mt-gd-x64-1_74.lib" Хоть убей, не могу понять в чём дел…
G
GvozdikDec. 19, 2023, 10:01 a.m.
Qt/C++ - Lesson 056. Connecting the Boost library in Qt for MinGW and MSVC compilers Для решения твой проблемы добавь в файл .pro строчку "LIBS += -lws2_32" она решит проблему , лично мне помогло.
Now discuss on the forum
AC
Alexandru CodreanuJan. 20, 2024, 12:57 a.m.
QML Обнулить значения SpinBox Доброго времени суток, не могу разобраться с обнулением значение SpinBox находящего в делегате. import QtQuickimport QtQuick.ControlsWindow { width: 640 height: 480 visible: tr…
BlinCT
BlinCTDec. 27, 2023, 9:57 p.m.
Растягивать Image на парент по высоте Ну и само собою дял включения scrollbar надо чтобы был Flickable. Так что выходит как то так Flickable{ id: root anchors.fill: parent clip: true property url linkFile p…
Дмитрий
ДмитрийJan. 10, 2024, 5:18 p.m.
Qt Creator загружает всю оперативную память Проблема решена. Удалось разобраться с помощью утилиты strace. Запустил ее: strace ./qtcreator Начал выводиться весь лог работы креатора. В один момент он начал считывать фай…
Evgenii Legotckoi
Evgenii LegotckoiDec. 12, 2023, 7:48 p.m.
Побуквенное сравнение двух строк Добрый день. Там случайно не высылается этот сигнал textChanged ещё и при форматировани текста? Если решиать в лоб, то можно просто отключать сигнал/слотовое соединение внутри слота и …

Follow us in social networks