python编程:从入门到实践学习笔记-Django开发用户账户(一)

让用户能够输入数据(表单)

在创建用户账户身份验证系统之前,先添加几个页面,让用户能偶输入数据。添加新主题、添加新条目以及编辑既有条目。

添加新主题

1.用于添加主题的表单
创建一个forms.py文件与models.py放在同一目录下。

from django import forms
from .models import Topic

class TopicForm(forms.ModelForm):
    class Meta:
        model = Topic
        fields = ['text']
        labels = {'text': ''}

TopicForm类继承了forms.ModelForm,其包含一个内嵌的Meta类。Meta类指定了根据哪个模型创建表单,以及在表单中包含哪些字段。
在这里,我们根据模型Topic创建了一个表单,该表单只包含字段text,且不用为字段text生成标签。
2.URL模式new_topic

# learning_logs/urls.py
from django.conf.urls import url
from . import views

urlpatterns = [
    url(r'^$', views.index, name='index'),
    url(r'^topics/$', views.topics, name='topics'),
    url(r'^topics/(?P<topic_id>\d+)/$', views.topic, name='topic'),
    url(r'^new_topic/$', views.new_topic, name='new_topic'),
]

3.视图函数new_topic()

# learning_logs/views.py
from django.shortcuts import render
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
from .models import Topicfrom .forms import TopicForm

--snip--

def new_topic(request):
    if request.method != 'POST':        
        #未提交数据,创建一个新表单
        form = TopicForm()    
    else:        
        #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)

用户提交主题后使用HttpResponseRedirect类将用户重定向到网页topics。函数reverse()根据指定的URL模式确定URL,即django将在页面被请求时生成URL。
4.GET请求和POST请求
GET请求:从服务器读取数据;
POST请求:通过表单提交信息。
在上述代码的else部分中,我们将使用-存储在request.POST的用户输入数据-创建一个TopicForm实例并赋值给对象form。
将提交的信息保存到数据库之前,得检查其是否有效。函数is_valid()核实用户填写了所有必不可少的字段,且输入的数据与要求的字段类型一致。如果所有字段有效,调用函数save()将表单数据写入数据库。
最后使用函数reverse()获取页面topics的URL,并将其传递给HttpResponseRedirect(),后者将用户浏览器重定向到页面topics查看用户刚输入的主题。
5.模版new_topic

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

定义表单使的实参action指定了服务器将提交的表单数据发送的目的地。在这里我们将它发回给视图函数new_topic()实参method让浏览器以POST请求的方式提交数据。
模板标签{% csrf_token %}防止攻击者利用表单来获得对服务器未经授权的访问(跨站请求伪造)。
模板变量{{ form.as_p }}让django自动创建显示表单所需的全部字段。修饰符as_p表示以段落格式渲染所有表单元素。
6.链接到页面new_topic
在页面 topics中添加一个到页面new_topic的链接

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

{% block content %}
  <p>Topics</p>

    <ul>
      --snip--    
    </ul>

  <a href="{% url 'learning_logs:new_topic' %}">Add a new topic:</a>

{% endblock content %}

运行服务器可以看到

《python编程:从入门到实践学习笔记-Django开发用户账户(一)》
《python编程:从入门到实践学习笔记-Django开发用户账户(一)》

《python编程:从入门到实践学习笔记-Django开发用户账户(一)》
《python编程:从入门到实践学习笔记-Django开发用户账户(一)》

添加新条目

1.用于添加新条目放入表单
定制一个与模型Entry相关联的表单

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):
    class Meta:
        model = Entry
        fields = ['text']
        labels = {'text': ''}
        widgets = {'text': forms.Textarea(attrs={'cols': 80})}

同样导入Entry,新类继承forms.ModelForm,新类包含的Meta类指出表单基于的模型以及表单中包含的字段。
在Meta类中我们定义了属性widgets。小部件(widget)是一个HTML表单元素,比如单行文本框、多行文本区域或者下拉列表。通过设置这个属性覆盖django默认的小部件,并把文本区域的宽度设置为80列,而不是默认的40列。
2.URL模式new_entry
修改urls.py

#learning_logs/urls.py
from django.conf.urls import url
from . import views

urlpatterns = [    
    #--snip--
    url(r'^new_entry/(?P<topic_id>\d+)/$', views.new_entry, name='new_entry'),
]

这个URL模式与形式为http://127.0.0.1:8000/new_entry/id/的URL匹配,其中id是一个与主题id匹配的数字。(?P<topic_id>\d+)捕获一个数值存储在变量topic_id中。模式匹配时django把请求和主题id发给函数new_entry()
3.视图函数new_topic
修改views.py

from django.shortcuts import render
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
from .models import Topic
from .forms import TopicForm, EntryForm

#--snip--

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 HttpResponseRedirect(reverse('learning_logs:topic',args=[topic_id]))

    context = {'topic': topic, 'form': form}
    return render(request, 'learning_logs/new_entry.html', context)

new_entry = form.save(commit=False)表示创建一个新的条目对象并把它存储到new_entry中,但是不保存到数据库。接着把new_entry的topic设置为此函数开头从数据库中获取的主题,然后调用save()保存到数据库,这样才能确保与正确的主题相关联。
在调用reserve()时需要提供两个实参。第一个是根据它来生成URL的URL模式的名称。第二个是列表args,其中存储着要包含在URL中的所有实参。
4.模板new_entry
类似new_topic.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 %}

表单的实参action包含URL中的topic_id值,让视图函数能够把新条目关联到正确的主题。
5.链接到页面new_entry
在显示特定主题的页面中添加到页面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>
  #--snip--
  </ul>

{% endblock content %}

运行服务器可以看到

《python编程:从入门到实践学习笔记-Django开发用户账户(一)》
《python编程:从入门到实践学习笔记-Django开发用户账户(一)》

编辑条目

1.URL模式edit_entry
此页面的URL需要传递要编辑的条目的ID。

#learning_logs/urls.py
from django.conf.urls import url
from . import views

urlpatterns = [
    #--snip--
    url(r'^edit_entry/(?P<entry_id>\d+)/$', views.edit_entry,name='edit_entry'),
]

在URLhttp://127.0.0.1:8000/edit_entry/id/中传递的id存储在形参entry_id中。模式匹配时把请求发送给视图函数edit_entry()
2.视图函数edit_entry
页面edit_entry收到GET请求时,edit_entry()返回一个表单,让用户对条目进行编辑。该页面收到POST请求(条目文本经过修订)时,把修改后的文本保存到数据库中。
修改views.py

from django.shortcuts import render
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
from .models import Topic, Entry
from .forms import TopicForm, EntryForm

#--snip--

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:        
        # 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)

首先获取需要修改的条目对象以及该条目相关联的主题。当请求方法为GET时执行if代码块,实参instance=entry表示使用既有条目对象中的信息填充创建的表单。
处理POST请求时,传递实参instance=entry和data=request.POST让django根据既有条目对象创建表单实例并根据request.POST中的相关数据对其进行修改。
3.模板edit_entry
类似new_entry.html

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

在标签{% url %}中将条目id作为实参。
5.链接到页面edit_entry
在显示特定主题的页面中给每个条目添加到页面edit_entry的链接:

#topic.html
#--snip--

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

#--snip--

运行服务器可以看到

《python编程:从入门到实践学习笔记-Django开发用户账户(一)》
《python编程:从入门到实践学习笔记-Django开发用户账户(一)》

    原文作者:七月
    原文地址: https://zhuanlan.zhihu.com/p/48531399
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞