Django入门2

2018-04-12  本文已影响0人  蜘蛛的梦呓

今天本来想把这本书看完的,可是被几个小错误耽误了好多时间,其中一个错误重启服务竟然能运行成功了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<topic_id>\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<topic_id>\d+)捕获一个数字值,并将其存储到变量 topic_id 中
    # 请求的 URL 与这个模式匹配时, Django 将请求和主题 ID 发送给函数 new_entry()
    url(r'^new_entry/(?P<topic_id>\d+)/$', views.new_entry, name='new_entry'),
    # 用于编辑条目的页面
    url(r'^edit_entry/(?P<entry_id>\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)
  1. 编写模板(html 文件)

base.html

<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 }}.
    <a href="{% url 'users:logout' %}">log out</a>
    {% else %}
    <a href="{% url 'users:login' %}">log in</a>
    {% endif %}
</p>

{% block content %}{% endblock %}

edit_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 %}

new_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>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_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 %}

topic.html

{% extends 'learning_logs/base.html' %}

{% block content %}

  <p>Topic: {{ topic }}</p>

  <p>Entries:</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 %}

topics.html

{% extends "learning_logs/base.html" %}

{% block content %}

  <p>Topics</p>

  <ul>
    {% for topic in topics %}
      <li>
        <a href="{% url 'learning_logs:topic' topic.id %}">{{ topic }}</a>
     </li>
    {% empty %}
      <li>No topics have been added yet.</li>
    {% endfor %}
  </ul>

{% 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

<!--login.html-->
{% extends "learning_logs/base.html" %}

{% block content %}

<!--如果表单的 errors 属性被设置,我们将显示一条错误信息-->
{% 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>
    <!--隐藏表单元素—— next,其中的实参 value 告诉 Django 在用户成功登陆后将其重定向到主页-->
    <input type="hidden" name="next" value="{% url 'learning_logs:index' %}"/>
</form>

{% endblock content %}

因为登录页面是使用 Django 的默认视图login,所以可以不用写视图函数,只需要告诉 Django 去哪里查找我们编写的模板。

今天就这样了,我觉得这样写下来能更好的把握 Django 的整体架构,不会那么容易被书不断重复的内容弄晕,具体细节请看书上的详细内容,就不一步步写了(会把新人弄晕的),好了今天就到这里了(看得好少),谢谢大家了。

上一篇下一篇

猜你喜欢

热点阅读