6. 添加新条目
用于添加新条目的表单
创建一个与模型Entry相关联的表单
forms.py
from django import forms
from .models import Topic, Entry
class TopicForm(forms.ModelForm):
class Meta:
model = Topic # 根据模型Topic创建表单
fields = ['text'] # 只包含字段text
labels = {'text': ''} # 不要为text生成表单
class EntryForm(forms.ModelForm):
class Meta:
model = Entry
fields = ['text']
labels = {'text': ''} # 给字段'text'指定了标签'Entry:'
widgets = {'text': forms.Textarea(attrs={'cols': 80})}
小部件(widget)是一个HTML表单元素,如单行文本框、多行文本框区域或下拉列表。
使用forms.Textarea定制了字段text'的输入小部件,将文本框宽度设置为80列(默认40列)
URL模式 new_entry
urls.py
"""定义learning_logs的URL模式"""
from django.urls import path
from . import views # 句点让Python从当前urls.py模块所在的文件夹导入views.py
app_name = 'learning_logs' #区分其他应用程序中的同名文件
urlpatterns = [
# 主页
path('', views.index, name='index'),
# 显示所有的主题
path('topics/', views.topics, name='topics'),
# 特定主题的详细页面
path('topics/<int:topic_id>/', views.topic, name='topic'),
# 用于添加新主题的页面
path('new_topic/', views.new_topic, name='new_topic'),
# 用于添加新条目的页面。
path('new_entry/<int:topic_id>/', views.new_entry,name='new_entry'),
]
其中的id是一个与主题ID匹配的数。
<int:topic_id>捕获一个值,并将其赋值给变量topic_id。
请求的URL与这个模式匹配时,Django将请求和主题ID发送给函数new_entry()。
视图函数new_entry()
from django.shortcuts import render, redirect
from .models import Topic # 导入模型
from .forms import TopicForm, EntryForm
def index(request):
"""学习笔记的主页"""
return render(request, 'learning_logs/index.html')
def topics(request):
"""显示所有的主题"""
topics = Topic.objects.order_by('date_added') # 查询数据库————请求提供Topic对象,并根据属性date_added进行排序
comtext = {'topics':topics} # 定义一个将发送给模板的上下文
return render(request, 'learning_logs/topics.html', comtext)
def topic(request, topic_id):
"""显示单个主题及其所有的条目"""
topic = Topic.objects.get(id=topic_id)
entries = topic.entry_set.order_by('-date_added')
context = {'topic': topic, 'entries': entries}
return render(request, 'learning_logs/topic.html', context)
def new_topic(request):
"""添加新主题"""
if request.method != 'POST':
# 未提交数据:创建一个新表单
form = TopicForm()
else:
# POST提交的数据:对数据进行处理
form = TopicForm(data=request.POST) # 使用用户输入的数据(存储在resquest.POST中)创建一个TopicForm实例
if form.is_valid(): #方法is_valid()核实用户填写了所有必不可少的字段,且输入的数据与要求的字段类型一致。
form.save() # 将表单中的数据写入数据库
return redirect('learning_logs:topics') # 存完数据,将浏览器重定向到页面topics。
# 显示空表单或指出表单数据无效
context = {'form': form}
return render(request, 'learning_logs/new_topic.html', context)
def new_entry(request,topic_id):
"""在特定主题中添加新条目。"""
topic = Topic.objects.get(id=topic_id)
if request.method != 'POST':
# 未提交数据:创建一个空表单
form = EntryForm()
else:
# POST提交的数据:对数据进行处理
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)
调用save()时,传递实参commit=False,让Django创建一个新的条目对象,并将其赋值给new_entry,但不保存到数据库中。
将new_entry的属性topic设置为在这个函数开头从数据库中获取的主题,再调用save()且不指定任何实参。这将把条目保存到数据库,并将其与正确的主题相关联。
模板new_entry
new_entry.html
{% 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 %}
表单的实参action包含URL中的topic_id值,让视图函数能够将新条目关联到正确的主题。
链接到页面new_entry
topic.html
{% 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>
{% for entry in entries %}
<li>
<p>{{ entry.date_added|date:'M d, Y H:i' }}</p>
<p>{{ entry.text|linebreaks }}</p>
</li>
{% empty %}
<li>There are no entries for this topic yet.</li>
{% endfor %}
</ul>
{% endblock content %}
将这个链接放在条目列表前面。
完成效果如图: