美文网首页
Django Web应用程序(四)

Django Web应用程序(四)

作者: Blue_Eye | 来源:发表于2018-02-04 17:52 被阅读0次

    19.1 让用户能够输入数据

    19.1.1 添加新主题

    创建基于表单的页面的方法几乎与前面创建网页一样: 定义URL,编写一个视图函数并编写一个模板。一个主要差别是,需要导入包含表单的模块 forms.py

    1. 用于添加主题的表单
    让用户输入并提交信息的页面都是表单,表单的很多工作都是由Django自动完成的,比如:

    • 用户输入信息时,我们需要进行验证,确认提供的信息是正确的数据类型,且不是恶意的信息。
    • 对这些有效信息进行处理,并将其保存到数据库的合适地方

    在Django中,创建表单的最简单方式是使用ModelForm, 它根据我们定义的模型中的信息自动创建表单。创建一个名为forms.py文件,并将其存储到models.py所在的目录中, 并在其中编写第一个表单

    # forms.py
    from django import forms
    
    from .models import Topic
    
    class TopicForm(forms.ModelForm):
        class Meta:
            model = Topic
            fields = ['text']
            labels = {'text': ''}
    

    首先导入了模块forms以及要使用的模型Topic,我们定义了一个名为TopicForm的类,它继承了forms.ModelForm。
    最简单的ModelForm版本只包含一个内嵌的 Meta 类,它告诉Django根据哪个模型创建表单,以及在表单中包含哪些字段。根据模型Topic创建一个表单,该表单只包含字段text,labels代码让Django不要为字段text生成标签。

    2. URL 模式 new_topic
    当用户要添加新主题时,我们将切换到http://localhost:8000/new_topic/,添加URL模式到learning_logs/urls.py

    # urls.py
    from django.conf.urls import url
    
    from . import views
    
    app_name = 'learning_logs'
    
    urlpatterns = [
        # index
        url(r'^$', views.index, name='index'),
        
        # show all topics
        url(r'^topics/$', views.topics, name='topics'),
        
        # show detail info for specific topic
        url(r'^topics/(?P<topic_id>\d+)/$', views.topic, name='topic'),
        
        # add new topic page
        url(r'^new_topic/$', views.new_topic, name='new_topic'),
    ]
    

    3.视图函数new_topic()
    函数new_topic()需要处理两种情况:刚进入new_topic网页(在这种情况下,它应显示一个空表单);对提交的表单数据进行处理,并将用户重定向到网页topics

    # views.py
    from django.shortcuts import render
    from django.http import HttpResponseRedirect
    from django.urls import reverse
    
    from .models import Topic
    from .forms import TopicForm
    
    # Create your views here.
    
    def index(request):
        return render(request, 'learning_logs/index.html')
        
    def topics(request):
        """show all topics"""
        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 = {'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(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)
    

    如果请求方法是POST, 对提交的表单数据进行处理。我们使用用户输入的数据(它们存储在request.POST中)创建一个TopicForm实例,这样对象form将包含用户提交的信息。
    要将提交的信息保存到数据库,必须通过检查确定它们是有效的。函数is_valid()自动验证避免了我们去做大量的工作。如果所有字段都有效,我们就可调用save(),将表单中的数据写入数据库。保存数据后,就可离开这个页面,使用reverse()获取topics的URL。

    4. 模板 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()。
    Django使用模板标签{% csrf_token %}来防止攻击者利用表单来获取对服务器未经授权的访问。 为了显示表单,我们只需要包含模板变量{{ form.as_p }},就可让Django自动创建显示表单所需的全部字段。修饰符as_p让Django以段落格式渲染所有表单元素,这是一种整洁地显示表单的简单方式。
    另外,Django 不会为表单创建提交按钮。

    5. 链接到页面 new_topic
    接下来,我们在页面topics中添加一个到页面new_topic的链接

    # 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>
    
    <a href="{% url 'learning_logs:new_topic' %}">Add a new topic:</a>
    
    {% endblock content %}
    
    用于添加新主题的页面

    19.1.2 添加新条目

    现在用户可以添加新主题了,但他们还想添加新条目。我们将再次定义URL,编写视图和模板,并了解到添加新条目的网页。但在此之前,我们需要在forms.py中再添加一个类。
    ** 1. 用于添加新条目的表单**

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

    我们定义了属性widgets, widget是HTML表单元素,如单行文本框,多行文本趋于或下拉了表。通过设置属性widgets,可覆盖Django选择的默认小部件。通过让Django使用forms.Textarea,我们定制了'text'的输入小部件,将文本区域的宽度设置为80列,而不是默认的40列。

    2. URL模式new_entry
    在用于添加新条目的页面的URL模式中,需要包含实参topic_id, 因此条目必须与特定的主题相关联。我们将它添加到learning_logs/urls.py中

    from django.conf.urls import url
    
    from . import views
    
    app_name = 'learning_logs'
    
    urlpatterns = [
        # index
        url(r'^$', views.index, name='index'),
        
        # show all topics
        url(r'^topics/$', views.topics, name='topics'),
        
        # show detail info for specific topic
        url(r'^topics/(?P<topic_id>\d+)/$', views.topic, name='topic'),
        
        # add new topic page
        url(r'^new_topic/$', views.new_topic, name='new_topic'),
        
        # add new entry page
        url(r'new_entry/(?P<topic_id>\d+)/$', views.new_entry, name='new_entry'),
    ]
    

    代码(?P<topic_id>\d+)捕获一个数字值,并将其存储在变量topic_id中。 请求的URL与这个模式匹配时,Django将请求和主题ID发送给函数new_entry()

    ** 3. 视图函数new_entry()**

    from django.shortcuts import render
    from django.http import HttpResponseRedirect
    from django.urls import reverse
    
    from .models import Topic
    from .forms import TopicForm, EntryForm
    
    # Create your views here.
    
    def index(request):
        return render(request, 'learning_logs/index.html')
        
    def topics(request):
        """show all topics"""
        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 = {'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(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提交的数据,对数据进行处理
            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)
    

    调用save()时,我们传递了实参commit=False,让Django创建一个新的条目对象,并将其存储到ew_entry中,但不将它保存到数据库中。我们将new_entry的属性topic设置为在这个函数开头从数据库中获取的主题,然后调用save()。

    4. 模板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 %}
    

    5. 链接到页面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 %}
    
    添加新条目new_entry页面

    19.1.3 编辑条目

    下面创建一个页面,让用户能够编辑既有条目
    1. URL模式edit_entry
    修改后的learning_logs/urls.py

    from django.conf.urls import url
    
    from . import views
    
    app_name = 'learning_logs'
    
    urlpatterns = [
        # index
        url(r'^$', views.index, name='index'),
        
        # show all topics
        url(r'^topics/$', views.topics, name='topics'),
        
        # show detail info for specific topic
        url(r'^topics/(?P<topic_id>\d+)/$', views.topic, name='topic'),
        
        # add new topic page
        url(r'^new_topic/$', views.new_topic, name='new_topic'),
        
        # add new entry page
        url(r'new_entry/(?P<topic_id>\d+)/$', views.new_entry, name='new_entry'),
        
        # edit entry page
        url(r'edit_entry/(?P<entry_id>\d+)/$', views.edit_entry, name='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.urls import reverse
    
    from .models import Topic, Entry
    from .forms import TopicForm, EntryForm
    
    # Create your views here.
    
    def index(request):
        return render(request, 'learning_logs/index.html')
        
    def topics(request):
        """show all topics"""
        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 = {'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(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提交的数据,对数据进行处理
            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 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创建一个EntryForm实例。这个实参让Django创建一个表达,并使用既有条目对象中的信息填充它。处理POST请求时,我们传递实参instance=entry和data=request.POST,让Django根据既有条目对象创建一个表单实例,并根据request.POST中的相关数据对其进行修改。

    3. 模板 edit_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 %}
    

    4.链接到页面edit_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>
        <p>
            <a href="{% url 'learning_logs:edit_entry' entry.id %}">edit entry</a>
        </p>
      </li>
      
      {% empty %}
      <li>
        There are no entries for this topic yet.
      </li>
      {% endfor %}
    </ul>
    
    {% endblock content %}
    
    每个条目都有一个用于对其进行编辑的链接

    相关文章

      网友评论

          本文标题:Django Web应用程序(四)

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