今天本来想把这本书看完的,可是被几个小错误耽误了好多时间,其中一个错误重启服务竟然能运行成功了orz,真的烦躁。今天内容就383-397,明天继续加油。
19.1 让用户能够输入数据
19.1.1 添加新主题
创建基于表达的页面的方法几乎与前面创建网页一样:定义一个 URL,编写一个视图函数并编写一个模板,一个主要区别是,需要导入包含表单的模块,forms.py
1.在 Django 中,创建表单的最简单的方式是使用 ModelForm
创建一个名为 forms.py 的文件,将其存储到 models.py 所在的目录中。
from django import forms
from .models import Topic, Entry
class TopicForm(forms.ModelForm):
class Meta:
model = Topic
fields = ['text']
labels = {'text': ''}
class EntryForm(forms.ModelForm):
# Meta 存储用于管理模型的额外信息
# Meta 类指出了表单基于的模型以及表单包含哪些字段
class Meta:
model = Entry
fields = ['text']
labels = {'text': ''}
widgets = {'text': forms.Textarea(attrs={'cols': 80})}
2.URL 模式
from django.conf.urls import url
from . import views
'''定义 learning_logs 的 URL 模式'''
# 该模块定义了可在管理网站中请求的所有 URL
urlpatterns = [
# url() 的第一个参数是正则表达式,第二个是要调用的视图函数,第三个是这个 URL 模式的名称
# r:让 python 将接下来的字符串视为原始字符串
# ^:查看字符串开头
# $:查看字符串末尾
# (r'^$'):即表示头尾没有任何东西的 URL(python 默认忽略项目的基础 URL(http://localhost:8080/)),
# 所以这个正则表达式匹配基础 URL。
# 主页
url(r'^$', views.index, name='index'),
# 显示所有主题
url(r'^topics/$', views.topics, name='topics'),
# 特定主题的详细页面
url(r'^topics/(?P\d+)/$', views.topic, name='topic'),
# learning_logs/urls.py
# 用于添加新主题的网页
url(r'^new_topic/$', views.new_topic, name='new_topic'),
# 用于添加新条目的页面 http://localhost:8080/new_entry/id/ 的 URL 匹配
# (?P\d+)捕获一个数字值,并将其存储到变量 topic_id 中
# 请求的 URL 与这个模式匹配时, Django 将请求和主题 ID 发送给函数 new_entry()
url(r'^new_entry/(?P\d+)/$', views.new_entry, name='new_entry'),
# 用于编辑条目的页面
url(r'^edit_entry/(?P\d+)/$', views.edit_entry, name='edit_entry'),
]
app_name = "learning_logs"
3.编写视图函数
from django.shortcuts import render
from django.http import HttpResponseRedirect, Http404
# ModuleNotFoundError: No module named 'django.core.urlresolvers'
# from django.core.urlresolvers import reverse
from django.urls import reverse
from django.contrib.auth.decorators import login_required
from .models import Topic, Entry
from .forms import TopicForm, EntryForm
# Create your views here.
def index(request):
'''学习笔记的主页'''
return render(request, 'learning_logs/index.html')
# URL 请求与我们刚才定义的模式匹配时,Django 将在文件 views.py 中查找函数 index(),再将
# 请求对象传递给这个视图函数。
def topics(request):
'''显示所有主题'''
topics = Topic.objects.order_by('date_added')
context = {'topics': topics}
return render(request, 'learning_logs/topics.html', context)
def topic(request, topic_id):
'''显示单个主题以其所有条目'''
topic = Topic.objects.get(id=topic_id)
entries = topic.entry_set.order_by('-date_added')
context = {'topics': topics, 'entries': entries}
return render(request, 'learning_logs/topic.html', context)
def new_topic(request):
'''添加新主题'''
# 确定 GET or POST,如果不为 Post,返回一个空表单。
if request.method != 'POST':
# 未提交数据:创建一个新表单
form = TopicForm()
else:
# POST提交的数据,对数据进行处理,数据在 request.POST 中。
form = TopicForm(request.POST)
# 检查是否填写了所有必不可少的字段。(是否有效)
if form.is_valid():
form.save()
return HttpResponseRedirect(reverse('learning_logs: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提交的数据,对数据进行处理,数据在 request.POST 中。
form = EntryForm(data=request.POST)
if form.is_valid():
new_entry = form.save(commit=False)
new_entry.topic = topic
new_entry.save()
return HttpResponseRedirect(reverse('learning_logs:topic', args=[topic_id]))
context = {'topic': topic, 'form': form}
return render(request, 'learning_logs/new_entry.html', context)
def edit_entry(request, entry_id):
'''编辑既有条目'''
entry = Entry.objects.get(id=entry_id)
topic = entry.topic
if topic.owner != request.user:
raise Http404
if request.method != 'POST':
# 初次请求,使用当前条目填充表单
form = EntryForm(instance=entry)
else:
# POST提交的数据,对数据进行处理
form = EntryForm(instance=entry, data=request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect(reverse('learning_logs:topic',
args=[topic.id]))
context = {'entry': entry, 'topic': topic, 'form': form}
return render(request, 'learning_logs/edit_entry.html', context)
- 编写模板(html 文件)
base.html
Learning Log -
Topics
{% if user.is_authenticated %}
Hello, {{ user.username }}.
log out
{% else %}
log in
{% endif %}
{% block content %}{% endblock %}
edit_entry.html
{% extends "learning_logs/base.html" %}
{% block content %}
Edit entry:
{% endblock content %}
new_entry.html
{% extends "learning_logs/base.html" %}
{% block content %}
Add a new entry:
{% endblock content %}
new_topic.html
{% extends "learning_logs/base.html" %}
{% block content %}
Add a new topic:
{% endblock content %}
topic.html
{% extends 'learning_logs/base.html' %}
{% block content %}
Topic: {{ topic }}
Entries:
{% for entry in entries %}
-
{{ entry.date_added|date:'M d, Y H:i' }}
{{ entry.text|linebreaks }}
{% empty %}
-
There are no entries for this topic yet.
{% endfor %}
{% endblock content %}
topics.html
{% extends "learning_logs/base.html" %}
{% block content %}
Topics
{% for topic in topics %}
-
{{ topic }}
{% empty %}
- No topics have been added yet.
{% endfor %}
{% endblock content %}
书上基本都是按这几步走,大概对照一下就好了,我不想按着书上那样一步步写下去(其实是懒),需要注意的是:
1.ModuleNotFoundError: No module named 'django.core.urlresolvers'(按书上写会报这个错误,Django版本不同所致),解决方法:这样导入 from django.urls import reverse 即可;
2.还有 learning_logs 的 URL 模式 urls.py 按书上写会报 NameError: name 'include' is not defined 这个错误,添加一个 app_name = "learning_logs(应用的名称)"即可解决。
19.2 创建用户账户
19.2.1 创建应用程序 users
首先创建一个名为 users 的应用程序。
python manage.py startapp users
1.将应用程序 users 添加到 settings.py
#--snip--
INSTALLED_APPS = (
#--snip--
'learning_logs',
'users',
)
#--snip--
这样 Django 将把应用程序 users 包含到项目中。
2.包含应用程序 users 的 URL
根目录的 urls.py
from django.conf.urls import include, url
from django.contrib import admin
# 该模块定义了可在管理网站中请求的所有 URL
urlpatterns = [
# 去掉第一个url后的include(),不然报错
url(r'^admin/', admin.site.urls),
url(r'^users/', include('users.urls', namespace='users')),
# 实参 namespace,让我们能够将 learning_logs 的 URL 同项目中的其他 URL 区分开来。
url(r'', include('learning_logs.urls', namespace='learning_logs')),
]
3.users 的 URL 模式
在目录 learning_log/users 中,新建 urls.py 。
# learning_log/users/urls.py
'''为应用程序 users 定义 URL 模式'''
from django.conf.urls import url
from django.contrib.auth.views import login
from . import views
urlpatterns = [
# 登录页面
# 添加的代码与任何以 users 开头的URL(如http://localhost:8000/users/login/)都匹配。
# 默认视图实参为 login(不是views.login)告诉 Django 将请求发送给视默认视图 login。接着传递了一个字典指定要查找的模板。
url(r'^login/$', login, {'template_name': 'users/login.html'}, name='login'),
# 注销
url(r'^logout/$', views.logout_view, name='logout'),
# 注册
# url(r'^register/$', views.register, name='register'),
]
app_name = "users"
2.编写视图函数
#learning_log\users\views.py
from django.shortcuts import render
from django.http import HttpResponseRedirect
from django.urls import reverse
from django.contrib.auth import logout
def logout_view(request):
"""注销"""
logout(request)
return HttpResponseRedirect(reverse('learning_logs:index'))
3.编写模板(html)
按这样新建文件夹 learning_log\users\templates\users
login.html
{% extends "learning_logs/base.html" %}
{% block content %}
{% if form.errors %}
Your username and password didn't match. Please try again.
{% endif %}
{% endblock content %}
因为登录页面是使用 Django 的默认视图login,所以可以不用写视图函数,只需要告诉 Django 去哪里查找我们编写的模板。
今天就这样了,我觉得这样写下来能更好的把握 Django 的整体架构,不会那么容易被书不断重复的内容弄晕,具体细节请看书上的详细内容,就不一步步写了(会把新人弄晕的),好了今天就到这里了(看得好少),谢谢大家了。