Разместим форму в forms.py:
from django import forms
from .models import Topic
class TopicForm(forms.ModelForm):
class Meta:
model = Topic
fields = ['text']
labels = {'text': ''}
Настроим URL:
urlpatterns = [
...
path('new_topic/', views.new_topic, name='new_topic'),
]
Напишем контроллер-функцию для формы:
from django.shortcuts import render, redirect
from .models import Topic
from .forms import TopicForm
...
def new_topic(request):
if request.method != 'POST':
form = TopicForm()
else:
form = TopicForm(data=request.POST)
if form.is_valid():
form.save()
return redirect('learning_logs:topics')
context = {'form': form}
return render(request, 'learning_logs/new_topic.html', context)
Создадим new_topic.html:
{% extends "learning_logs/base.html" %}
{% block content %}
<p>Add a new topic:</p>
<form action="{% url 'learning_logs:new_topic' %}" method='post'>
{% csrf_token %}
{{ form.as_p }}
<button name="submit">add topic</button>
</form>
{% endblock content %}
Далее ссылка на страницу new_topic создается на странице topics:
{% extends "learning_logs/base.html" %}
{% block content %}
<p>Topics</p>
<ul>
...
</ul>
<a href="{% url 'learning_logs:new_topic' %}">Add a new topic:</a>
{% endblock content %}
Мы должны создать форму, связанную с моделью Entry, но более специализированную по сравнению с TopicForm:
from django import forms
from .models import Topic, Entry
class TopicForm(forms.ModelForm):
...
class EntryForm(forms.ModelForm):
class Meta:
model = Entry
fields = ['text']
labels = {'text': 'Entry:'}
widgets = {'text': forms.Textarea(attrs={'cols': 80})}
Вот как выглядит параметрический URL, который мы добавляем в learning_logs/urls.py:
urlpatterns = [
...
path('new_entry/<int:topic_id>/', views.new_entry, name='new_entry'),
]
Функция представления new_entry очень похожа на функцию добавления новой темы:
from django.shortcuts import render, redirect
from .models import Topic
from .forms import TopicForm, EntryForm
...
def new_entry(request, topic_id):
topic = Topic.objects.get(id=topic_id)
if request.method != 'POST':
form = EntryForm()
else:
form = EntryForm(data=request.POST)
if form.is_valid():
new_entry = form.save(commit=False)
new_entry.topic = topic
new_entry.save()
return redirect('learning_logs:topic', topic_id=topic_id)
context = {'topic': topic, 'form': form}
return render(request, 'learning_logs/new_entry.html', context)
Как видно из следующего кода, шаблон new_entry похож на шаблон new_topic:
{% extends "learning_logs/base.html" %}
{% block content %}
<p><a href="{% url 'learning_logs:topic' topic.id %}">{{ topic }}</a></p>
<p>Add a new entry:</p>
<form action="{% url 'learning_logs:new_entry' topic.id %}" method='post'>
{% csrf_token %}
{{ form.as_p }}
<button name='submit'>add entry</button>
</form>
{% endblock content %}
Затем необходимо создать ссылку на страницу new_entry на каждой странице темы:
{% extends "learning_logs/base.html" %}
{% block content %}
<p>Topic: {{ topic }}</p>
<p>Entries:</p>
<p>
<a href="{% url 'learning_logs:new_entry' topic.id %}">add new entry</a>
</p>
<ul>
...
</ul>
{% endblock content %}
В URL-адресе страницы должен передаваться идентификатор редактируемой записи:
urlpatterns = [
...
path('edit_entry/<int:entry_id>/', views.edit_entry, name='edit_entry'),
]
Создадим функцию для измениения таблицы entry:
from django.shortcuts import render, redirect
from .models import Topic, Entry
from .forms import TopicForm, EntryForm
def edit_entry(request, entry_id):
entry = Entry.objects.get(id=entry_id)
topic = entry.topic
if request.method != 'POST':
form = EntryForm(instance=entry)
else:
form = EntryForm(instance=entry, data=request.POST)
if form.is_valid():
form.save()
return redirect('learning_logs:topic', topic_id=topic.id)
context = {'entry': entry, 'topic': topic, 'form': form}
return render(request, 'learning_logs/edit_entry.html', context)
Шаблон edit_entry.html очень похож на new_entry.html:
{% extends "learning_logs/base.html" %}
{% block content %}
<p><a href="{% url 'learning_logs:topic' topic.id %}">{{ topic }}</a></p>
<p>Edit entry:</p>
<form action="{% url 'learning_logs:edit_entry' entry.id %}" method='post'>
{% csrf_token %}
{{ form.as_p }}
<button name="submit">save changes</button>
</form>
{% endblock content %}
Теперь необходимо включить ссылку на страницу edit_entry в каждую тему на странице со списком тем:
{% for entry in entries %}
<li>
<p>{{ entry.date_added|date:'M d, Y H:i' }}</p>
<p>{{ entry.text|linebreaks }}</p>
<p>
<a href="{% url 'learning_logs:edit_entry' entry.id %}">Edit entry</a>
</p>
</li>
Начнем с создания нового приложения users командой startapp:
python manage.py startapp users
Новое приложение необходимо добавить в settings.py:
INSTALLED_APPS = [
...
'learning_logs',
'users',
]
Затем необходимо изменить корневой файл urls.py, чтобы он включал URL-адреса, написанные для приложения users:
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('users/', include('users.urls')),
path('', include('learning_logs.urls')),
]
Создайте новый файл urls.py в каталоге learning_log/users/ и добавьте в него следующий код:
from django.urls import path, include
app_name = 'users'
urlpatterns = [
path('', include('django.contrib.auth.urls')),
]
Вот как выглядит шаблон login.html, который должен находиться в learning_log/users/templates/registration/:
{% extends "learning_logs/base.html" %}
{% block content %}
{% if form.errors %}
<p>Your username and password didn't match. Please try again.</p>
{% endif %}
<form method="post" action="{% url 'users:login' %}">
{% csrf_token %}
{{ form.as_p }}
<button name="submit">log in</button>
<input type="hidden" name="next" value="{% url 'learning_logs:index' %}">
</form>
{% endblock content %}
Добавим ссылку на страницу входа в base.html, чтобы она присутствовала на каждой странице. Ссылка не должна отображаться, если пользователь уже прошел процедуру входа, поэтому она вкладывается в тег {% if %}:
<p>
<a href="{% url 'learning_logs:index' %}">Learning Log</a> -
<a href="{% url 'learning_logs:topics' %}">Topics</a> -
{% if user.is_authenticated %}
Hello, {{ user.username }}.
{% else %}
<a href="{% url 'users:login' %}">log in</a>
{% endif %}
</p>
{% block content %}{% endblock content %}
Теперь нужно создать ссылку для выхода:
{% if user.is_authenticated %}
Hello, {{ user.username }}.
<a href="{% url 'users:logout' %}">log out</a>
{% else %}
Сохраните файл logged_out.html в каталоге templates/registration — в том же каталоге, в котором был сохранен файл login.html:
{% extends "learning_logs/base.html" %}
{% block content %}
<p>You have been logged out. Thank you for visiting!</p>
{% endblock content %}
Следующий код предоставляет шаблон URL для страницы регистрации — также в файле users/urls.py:
from django.urls import path, include
from . import views
app_name = 'users'
urlpatterns = [
path('', include('django.contrib.auth.urls')),
path('register/', views.register, name='register'),
]
Функция представления register() должна вывести пустую форму регистрации при первом запросе страницы регистрации:
from django.shortcuts import render, redirect
from django.contrib.auth import login
from django.contrib.auth.forms import UserCreationForm
def register(request):
if request.method != 'POST':
form = UserCreationForm()
else:
form = UserCreationForm(data=request.POST)
if form.is_valid():
new_user = form.save()
login(request, new_user)
return redirect('learning_logs:index')
context = {'form': form}
return render(request, 'users/register.html', context)
Шаблон страницы регистрации похож на шаблон страницы входа. Проследите за тем, чтобы он был сохранен в одном каталоге с login.html:
{% extends "learning_logs/base.html" %}
{% block content %}
<form method="post" action="{% url 'users:register' %}">
{% csrf_token %}
{{ form.as_p }}
<button name="submit">register</button>
<input type="hidden" name="next" value="{% url 'learning_logs:index' %}" />
</form>
{% endblock content %}
Следующий шаг — добавление кода для вывода ссылки на страницу регистрации для любого пользователя, еще не выполнившего вход:
{% if user.is_authenticated %}
Hello, {{ user.username }}.
<a href="{% url 'users:logout' %}">log out</a>
{% else %}
<a href="{% url 'users:register' %}">Register</a> -
<a href="{% url 'users:login' %}">log in</a>
{% endif %}
Такая система регистрации позволяет любому пользователю создать сколько угодно учетных записей Learning Log. Однако некоторые системы требуют, чтобы пользователь подтвердил свою заявку, отправляя сообщение электронной почты, на которое пользователь должен ответить.
При таком подходе в системе будет создано меньше спамерских учетных записей, чем в простейшей системе из нашего примера. Но пока вы только учитесь строить приложения, вполне нормально тренироваться на упрощенной системе регистрации вроде используемой нами.
Блог: создайте новый проект Django с именем Blog. Создайте в проекте приложение с именем blogs и моделью BlogPost. Модель должна содержать такие поля, как title, text и date_added. Создайте суперпользователя для проекта и воспользуйтесь административным сайтом для создания пары коротких сообщений. Создайте домашнюю страницу, на которой выводятся все сообщения в хронологическом порядке.
Сделайте одну форму для создания новых сообщений, а другую форму для редактирования существующих сообщений. Заполните формы и убедитесь в том, что они работают.
Учетные записи в блоге: добавьте систему аутентификации и регистрации в проект Blog, работа над которым началась в упражнении 1. Проследите за тем, чтобы пользователь, выполнивший вход, видел свое имя где-то на экране, а незарегистрированные пользователи видели ссылку на страницу регистрации.