美文网首页Python学习日志python进阶Java-Python-Django社区
【day 14】python编程:从入门到实践学习笔记-基于Dj

【day 14】python编程:从入门到实践学习笔记-基于Dj

作者: 苍云横渡 | 来源:发表于2018-03-26 09:44 被阅读175次

    学习笔记目录
    【day 1】python编程:从入门到实践学习笔记-安装、变量和简单数据类型
    【day 2】python编程:从入门到实践学习笔记-列表以及其操作
    【day 3】python编程:从入门到实践学习笔记-if 语句(末附练习答案代码)
    【day 4】python编程:从入门到实践学习笔记-字典(末附练习答案代码)
    【day 5】python编程:从入门到实践学习笔记-用户输入和while循环(末附答案代码)
    【day 6】python编程:从入门到实践学习笔记-函数(末附练习答案代码)
    【day 7】python编程:从入门到实践学习笔记-类(末附练习答案代码)
    【day 8】python编程:从入门到实践学习笔记-文件和异常(末附练习答案代码)
    【day 9】python编程:从入门到实践学习笔记-测试代码(末附练习答案代码)
    【day 10】python编程:从入门到实践学习笔记-Django入门(一)
    【day 11】python编程:从入门到实践学习笔记-Django入门(二)
    【day 12】python编程:从入门到实践学习笔记-Django入门(三)
    【day 13】python编程:从入门到实践学习笔记-Django入门(四)
    【day 14】python编程:从入门到实践学习笔记-用户账户(一)
    【day 15】python编程:从入门到实践学习笔记-用户账户(二)
    【day 16】python编程:从入门到实践学习笔记-用户账户(三)
    【day 17】python编程:从入门到实践学习笔记-设计样式和部署(一)
    【day 18】python编程:从入门到实践学习笔记-设计样式和部署(二)& 补充

    第十九章 用户账户(一)

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

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

    添加新主题

    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 Topic
    from .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 %}
    

    运行服务器可以看到

    添加新条目

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

    运行服务器可以看到

    编辑条目

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

    运行服务器可以看到

    相关文章

      网友评论

      本文标题:【day 14】python编程:从入门到实践学习笔记-基于Dj

      本文链接:https://www.haomeiwen.com/subject/qyckcftx.html