1. 这是我们在前一个教程绘制的线框图。我现在意识到这个可能是一个不好的例子,因为这个特殊的表单涉及到处理两个不同模型数据:Topic(subject)和 Post(message)。
  2.  
  3. GET 可能是最常见的请求类型了。它用于从服务器请求数据。每当你点击了一个链接或者直接在浏览器中输入了一个地址时,你就创建一个 GET 请求。
  4.  
  5. POST 用于当我们想更改服务器上的数据的时候。一般来说,每次我们发送数据给服务器都会导致资源状态的变化,我们应该使用 POST 请求发送数据。
  6.  
  7. Django 使用 CSRF Token(Cross-Site Request Forgery Token) 保护所有的POST 请求。
  8. 这是一个避免外部站点或者应用程序向我们的应用程序提交数据的安全措施。
  9. 应用程序每次接收一个 POST 时,都会先检查 CSRFToken
  10. 如果这个 request 没有 token,或者这个 token是无效的,它就会抛弃提交的数据。
  11.  
  12. csrf_token 的模板标签:
  13. {% csrf_token %}
  14.  
  15. 下面是示范我们如何检索数据:
  16. subject = request.POST['subject']
  17. message = request.POST['message']
  18.  
  19. 创建表单正确的姿势
  20. 自从我们开始使用 Forms,我们已经走了很长一段路。终于,是时候使用Forms API 了。
  21. Forms API 可在模块 django.forms 中得到。
  22. Django 使用两种类型的form forms.Form forms.ModelForm
  23. Form 类是通用的表单实现。我们可以使用它来处理与应用程序 model 没有直接关联的数据。
  24. ModelForm Form 的子类,它与 model 类相关联。
  25.  
  26. 让我们去掉一些多余的部分,只看表单处理的核心部分:
  27. if request.method == 'POST':
  28. form = NewTopicForm(request.POST)
  29. if form.is_valid():
  30. topic = form.save()
  31. return redirect('board_topics', pk=board.pk)
  32. else:
  33. form = NewTopicForm()
  34. return render(request, 'new_topic.html', {'form': form})
  35. 首先我们判断请求是 POST 还是 GET
  36. 如果请求是 POST,这意味着用户向服务器提交了一些数据。
  37. 所以我们实例化一个将 POST 数据传递给 form form 实例: form = NewTopicForm(request.POST)
  38.  
  39. 然后,我们让 Django 验证数据,检查 form 是否有效,我们能否将其存入数据库: if form.is_valid():
  40. 如果表单有效,我们使用 form.save()将数据存入数据库。
  41. save() 方法返回一个存入数据库的 Model 实例。
  42. 所以,因为这是一个 Topic form, 所以它会返回 topic = form.save() 创建的 Topic
  43. 然后,通用的路径是把用户重定向到其他位置,以避免用户通过按 F5 重新提交表单,并且保证应用程序的流程走向。
  44.  
  45. 现在,如果数据是⽆效的,Django 会给 form 添加错误列表。
  46. 然后,视图函数不会做任何处理并且返回最后一句: return render(request,'new_topic.html', {'form': form})
  47. 这意味着我们需要更新new_topic.html 以显示错误。
  48.  
  49. 如果请求是 GET,我们只需要使用 form = NewTopicForm() 初始化一个新的空表单。
  50.  
  51. 这个 form 有三个渲染选项: form.as_table form.as_ul form.as_p
  52. 这是一个快速的渲染表单所有字段的方法。
  53. 顾名思义, as_table 使用 table 标签来格式化输入, as_ul 使用 li 标签。
  54.  
  55. 当使⽤ Bootstrap 或者其他的前端库时,我比较喜欢使用一个叫做 djangowidget-tweaks Django 库。
  56. 它可以让我们更好地控制渲染的处理,在保证默认值的情况下,只需在上面添加额外的自定义设置。
  57.  
  58. 一些 render_field 模板标签的例子:
  59. {% render_field form.subject class="form-control" %}
  60. {% render_field form.message class="form-control" placeholder=form.message.label %}
  61. {% render_field field class="form-control" placeholder="Writea message!" %}
  62. {% render_field field style="font-size: 20px" %}
  1. #myproject/urls.py
  2. from django.conf.urls import url
  3. from django.contrib import admin
  4. from boards import views
  5.  
  6. urlpatterns = [
  7. url(r'^$', views.home, name='home'),
  8. url(r'^boards/(?P<pk>\d+)/$', views.board_topics, name='board_topics'),
  9. url(r'^boards/(?P<pk>\d+)/new/$', views.new_topic, name='new_topic'),
  10. url(r'^admin/', admin.site.urls),
  11. ]
  1. #boards/views.py
  2. from django.shortcuts import render, get_object_or_404
  3. from .models import Board
  4.  
  5. def new_topic(request, pk):
  6. board = get_object_or_404(Board, pk=pk)
  7. return render(request, 'new_topic.html', {'board': board})
  1. <!--templates/new_topic.html-->
  2.  
  3. {% extends 'base.html' %}
  4. {% block title %}Start a New Topic{% endblock %}
  5.  
  6. {% block breadcrumb %}
  7. <li class="breadcrumb-item"><a href="{% url 'home' %}">Boards</a></li>
  8. <li class="breadcrumb-item"><a href="{% url 'board_topics' board.pk %}">{{ board.name }}</a></li>
  9. <li class="breadcrumb-item active">New topic</li>
  10. {% endblock %}
  11.  
  12. {% block content %}
  13. {% endblock %}
  1. <!--templates/new_topic.html-->
  2.  
  3. {% extends 'base.html' %}
  4. {% block title %}Start a New Topic{% endblock %}
  5.  
  6. {% block breadcrumb %}
  7. <li class="breadcrumb-item"><a href="{% url 'home' %}">Boards</a></li>
  8. <li class="breadcrumb-item"><a href="{% url 'board_topics' board.pk %}">{{ board.name }}</a></li>
  9. <li class="breadcrumb-item active">New topic</li>
  10. {% endblock %}
  11.  
  12. {% block content %}
  13. <form method="post">
  14. {% csrf_token %}
  15. <div class="form-group">
  16. <label for="id_subject">Subject</label>
  17. <input type="text" class="form-control" id="id_subject"name="subject">
  18. </div>
  19. <div class="form-group">
  20. <label for="id_message">Message</label>
  21. <textarea class="form-control" id="id_message" name="message" rows="5"></textarea>
  22. </div>
  23. <button type="submit" class="btn btn-success">Post</button>
  24. </form>
  25. {% endblock %}
  1. #boards/views.py
  2. from django.contrib.auth.models import User
  3. from django.shortcuts import render, redirect, get_object_or_404
  4. from .models import Board, Topic, Post
  5.  
  6. def new_topic(request, pk):
  7. board = get_object_or_404(Board, pk=pk)
  8.  
  9. if request.method == 'POST':
  10. subject = request.POST['subject']
  11. message = request.POST['message']
  12.  
  13. user = User.objects.first() # TODO: 临时使??个账号作为登录?户
  14.  
  15. topic = Topic.objects.create(
  16. subject=subject,
  17. board=board,
  18. starter=user
  19. )
  20.  
  21. post = Post.objects.create(
  22. message=message,
  23. topic=topic,
  24. created_by=user
  25. )
  26.  
  27. return redirect('board_topics', pk=board.pk) # TODO:redirect to the created topic page
  28. return render(request, 'new_topic.html', {'board': board})
  1. <!--templates/topics.html-->
  2.  
  3. {% extends 'base.html' %}
  4. {% block title %}
  5. {{ board.name }} - {{ block.super }}
  6. {% endblock %}
  7.  
  8. {% block breadcrumb %}
  9. <li class="breadcrumb-item"><a href="{% url 'home' %}">Boards</a></li>
  10. <li class="breadcrumb-item active">{{ board.name }}</li>
  11. {% endblock %}
  12.  
  13. {% block content %}
  14. <div class="mb-4"> <!--我们已经修改了topics.html模板,让我们创建?个能让我们转到new topic页?的按钮:-->
  15. <a href="{% url 'new_topic' board.pk %}" class="btn btn-primary">New topic</a>
  16. </div>
  17. <table class="table">
  18. <thead class="thead-inverse">
  19. <tr>
  20. <th>Topic</th>
  21. <th>Starter</th>
  22. <th>Replies</th>
  23. <th>Views</th>
  24. <th>Last Update</th>
  25. </tr>
  26. </thead>
  27. <tbody>
  28.   {% for topic in board.topics.all %}
  29.   <tr>
  30.   <td>{{ topic.subject }}</td>
  31.   <td>{{ topic.starter.username }}</td>
  32.   <td>0</td>
  33.   <td>0</td>
  34.   <td>{{ topic.last_updated }}</td>
  35.   </tr>
  36.   {% endfor %}
  37. </tbody>
  38. </table>
  39. {% endblock %}
  1. # boards/forms.py
  2. from django import forms
  3. from .models import Topic
  4. class NewTopicForm(forms.ModelForm):
  5. message = forms.CharField(widget=forms.Textarea(), max_length=4000)
  6. class Meta:
  7. model = Topic
  8. fields = ['subject', 'message']
  1. # boards/views.py
  2. from django.contrib.auth.models import User
  3. from django.shortcuts import render, redirect, get_object_or_404
  4. from .forms import NewTopicForm
  5. from .models import Board, Topic, Post
  6.  
  7. def new_topic(request, pk):
  8. board = get_object_or_404(Board, pk=pk)
  9. user = User.objects.first() # TODO: get the currently logged in user
  10. if request.method == 'POST':
  11. form = NewTopicForm(request.POST)
  12. if form.is_valid():
  13. topic = form.save(commit=False)
  14. topic.board = board
  15. topic.starter = user
  16. topic.save()
  17. post = Post.objects.create(
  18. message=form.cleaned_data.get('message'),
  19. topic=topic,
  20. created_by=user
  21. )
  22. return redirect('board_topics', pk=board.pk) # TODO: redirect to the created topic page
  23. else:
  24. form = NewTopicForm()
  25. return render(request, 'new_topic.html', {'board': board,'form': form})
  1. <!--我们甚至修复了最后两个测试。-->
  2. <!--Django Forms API 不仅仅是处理和验证数据。它还为我们生成 HTML。-->
  3. <!--templates/new_topic.html-->
  4.  
  5. {% extends 'base.html' %}
  6. {% block title %}Start a New Topic{% endblock %}
  7.  
  8. {% block breadcrumb %}
  9. <li class="breadcrumb-item"><a href="{% url 'home' %}">Boards</a></li>
  10. <li class="breadcrumb-item"><a href="{% url 'board_topics' board.pk %}">{{ board.name }}</a></li>
  11. <li class="breadcrumb-item active">New topic</li>
  12. {% endblock %}
  13.  
  14. {% block content %}
  15.   <form method="post">
  16.   {% csrf_token %}
  17.   {{ form.as_p }}
  18.   <button type="submit" class="btn btn-success">Post</button>
  19. </form>
  20. {% endblock %}
  1. # boards/forms.py
  2. from django import forms
  3. from .models import Topic
  4.  
  5. class NewTopicForm(forms.ModelForm):
  6. message = forms.CharField(
  7. widget=forms.Textarea(),
  8. max_length=4000,
  9. help_text='The max length of the text is 4000.'
  10. )
  11.  
  12. class Meta:
  13. model = Topic
  14. fields = ['subject', 'message']
  1. # 我们也可以为表单字段设置额外的属性:
  2. # boards/forms.py
  3.  
  4. from django import forms
  5. from .models import Topic
  6.  
  7. class NewTopicForm(forms.ModelForm):
  8. message = forms.CharField(
  9. widget=forms.Textarea(
  10. attrs={'rows': 5, 'placeholder': 'What is on your mind?'}
  11. ),
  12. max_length=4000,
  13. help_text='The max length of the text is 4000.'
  14. )
  15. class Meta:
  16. model = Topic
  17. fields = ['subject', 'message']
  1. # 用BootStrap 表单渲染
  2. # pip install django-widget-tweaks
  3. # myproject/settings.py
  4. INSTALLED_APPS = [
  5. 'widget_tweaks',
  6. ]
  1. # templates/new_topic.html
  2.  
  3. {% extends 'base.html' %}
  4. {% load widget_tweaks %}
  5. {% block title %}Start a New Topic{% endblock %}
  6.  
  7. {% block breadcrumb %}
  8. <li class="breadcrumb-item"><a href="{% url 'home' %}">Boar ds</a></li>
  9. <li class="breadcrumb-item"><a href="{% url 'board_topics' board.pk %}">{{ board.name }}</a></li>
  10. <li class="breadcrumb-item active">New topic</li>
  11. {% endblock %}
  12.  
  13. {% block content %}
  14. <form method="post" novalidate>
  15. {% csrf_token %}
  16. {% for field in form %}
  17.   <div class="form-group">
  18.   {{ field.label_tag }}
  19.   {% render_field field class="form-control" %}
  20.   {% if field.help_text %}
  21.     <small class="form-text text-muted">
  22.     {{ field.help_text }}
  23.     </small>
  24.   {% endif %}
  25.   </div>
  26. {% endfor %}
  27. <button type="submit" class="btn btn-success">Post</button>
  28. </form>
  29. {% endblock %}
  1. # 现在要实现 Bootstrap 4 验证标签,我们可以修改 new_topic.html 模板。
  2. # templates/new_topic.html
  3.  
  4. {% extends 'base.html' %}
  5. {% load widget_tweaks %}
  6. {% block title %}Start a New Topic{% endblock %}
  7.  
  8. {% block breadcrumb %}
  9. <li class="breadcrumb-item"><a href="{% url 'home' %}">Boar ds</a></li>
  10. <li class="breadcrumb-item"><a href="{% url 'board_topics' board.pk %}">{{ board.name }}</a></li>
  11. <li class="breadcrumb-item active">New topic</li>
  12. {% endblock %}
  13.  
  14. {% block content %}
  15. <form method="post" novalidate>
  16. {% csrf_token %}
  17.  
  18. {% for field in form %}
  19.   <div class="form-group">
  20.   {{ field.label_tag }}
  21.  
  22.   {% if form.is_bound %}
  23.    {% if field.errors %}
  24.    {% render_field field class="form-control is-invalid" %}
  25.    {% for error in field.errors %}
  26.      <div class="invalid-feedback">
  27.      {{ error }}
  28.      </div>
  29.    {% endfor %}
  30.    {% else %}
  31.      {% render_field field class="form-control is-valid" %}
  32.    {% endif %}
  33.    {% else %}
  34.    {% render_field field class="form-control" %}
  35.    {% endif %}
  36.  
  37.    {% if field.help_text %}
  38.    <small class="form-text text-muted">
  39.    {{ field.help_text }}
  40.    </small>
  41. {% endif %}
  42. </div>
  43. {% endfor %}
  44. <button type="submit" class="btn btn-success">Post</button>
  45.   </form>
  46. {% endblock %}
  1. # 复用表单模板
  2. # 模板看起来有点复杂,是吧?有个好消息是我们可以在项目中重复使用它。
  3. # 在 templates 文件夹中,创建一个新的文件夹命名为 includes:
  4. # templates/includes/form.html
  5.  
  6. {% load widget_tweaks %}
  7.  
  8. {% for field in form %}
  9. <div class="form-group">
  10. {{ field.label_tag }}
  11.  
  12. {% if form.is_bound %}
  13. {% if field.errors %}
  14. {% render_field field class="form-control is-invalid" %}
  15. {% for error in field.errors %}
  16. <div class="invalid-feedback">
  17. {{ error }}
  18. </div>
  19. {% endfor %}
  20. {% else %}
  21. {% render_field field class="form-control is-valid" % }
  22. {% endif %}
  23. {% else %}
  24. {% render_field field class="form-control" %}
  25. {% endif %}
  26.  
  27. {% if field.help_text %}
  28. <small class="form-text text-muted">
  29. {{ field.help_text }}
  30. </small>
  31. {% endif %}
  32. </div>
  33. {% endfor %}
  1. <!--templates/new_topic.html-->
  2.  
  3. {% extends 'base.html' %}
  4. {% block title %}Start a New Topic{% endblock %}
  5.  
  6. {% block breadcrumb %}
  7. <li class="breadcrumb-item"><a href="{% url 'home' %}">Boards</a></li>
  8. <li class="breadcrumb-item"><a href="{% url 'board_topics' board.pk %}">{{ board.name }}</a></li>
  9. <li class="breadcrumb-item active">New topic</li>
  10. {% endblock %}
  11.  
  12. {% block content %}
  13. <form method="post" novalidate>
  14. {% csrf_token %}
  15. {% include 'includes/form.html' %}
  16. <button type="submit" class="btn btn-success">Post</button>
  17. </form>
  18. {% endblock %}

Django入门与实践-第13章:表单处理(完结)的更多相关文章

  1. Django入门与实践-第16章:用户登录(完结)

    # myproject/settings.py LOGIN_REDIRECT_URL = 'home' EMAIL_BACKEND = 'django.core.mail.backends.conso ...

  2. Django入门与实践-第14章:用户注册(完结)

    http://127.0.0.1:8000/signup/ django-admin startapp accounts INSTALLED_APPS = [ 'accounts', ] # mypr ...

  3. Django入门与实践-第17章:保护视图(完结)

    http://127.0.0.1:8000/boards/1/ #boards/views.py from django.contrib.auth.decorators import login_re ...

  4. Django入门与实践-第21章:迁移(完结)

    http://127.0.0.1:8000/boards/1/ python manage.py migrate #boards/models.py class Topic(models.Model) ...

  5. Django入门与实践-第22章:基于类的视图

    http://127.0.0.1:8000/boards/1/topics/2/posts/2/edit/ http://127.0.0.1:8000/ #boards/views.py from d ...

  6. Django入门与实践-第19章:主题回复(完结)

    http://127.0.0.1:8000/boards/1/topics/1/reply/ http://127.0.0.1:8000/boards/1/topics/1/ #myproject/u ...

  7. Django入门与实践-第26章:个性化工具(完结)

    http://127.0.0.1:8000/boards/1/topics/62/reply/ 我觉得只添加内置的个性化(humanize)包就会很不错. 它包含一组为数据添加“人性化(human t ...

  8. Django入门与实践-第12章:复用模板(完结)

    http://127.0.0.1:8000/http://127.0.0.1:8000/boards/1/http://127.0.0.1:8000/boards/2/http://127.0.0.1 ...

  9. Django入门与实践-第11章:URL 分发(完结)

    http://127.0.0.1:8000http://127.0.0.1:8000/boards/1/http://127.0.0.1:8000/boards/2/http://127.0.0.1: ...

随机推荐

  1. HTML 表格标签

    <table border="1"> <tr> <td>row 1, cell 1</td> <td>row 1, ce ...

  2. 关闭IPV6

    [root@bgw-t ~]# cat > /etc/modprobe.d/ipv6.conf << EOF alias net-pf-10 off options ipv6 dis ...

  3. Haskell语言学习笔记(61)Distributive

    Distributive class Functor g => Distributive g where distribute :: Functor f => f (g a) -> ...

  4. hadoop 集群安装配置 【转】

    http://www.cnblogs.com/ejiyuan/p/5557061.html 注意:要把master 上所有的配置文件(主要是配置的那四个 xxxx-site.xml 和 xxx-env ...

  5. 面向对象三大特性一一封装(encapsulation)

    为什么要封装? 我们看电视,只要按一下开关和换台就行了.有必要了解电视的内部结构吗?有必要了解显像管吗? 封装是为了隐藏对象内部的复杂性,只对外公开简单的接口.便于外界调用,从而提高系统的可扩展性,可 ...

  6. vmstat工具

    vmstat vmstat是Virtual Meomory Statistics(虚拟内存统计)的缩写, 是实时系统监控工具.该命令通过使用knlist子程序和/dev/kmen伪设备驱动器访问这些数 ...

  7. poj1661 (DP)

    题目链接:http://poj.org/problem?id=1661 思路: 把初始位置看成左,右端点均为x0,即长度为0,高度为y0的一个平台,按照平台高度从低到高排序.用dp[i][0],dp[ ...

  8. Openvpn 日常问题解决

    一.Openven的在windows系统下的使用: 1.Openven客户端2.2.0:http://pan.baidu.com/s/1sjJij4T 安装好客户端软件后,将服务器下发的证书和配置文件 ...

  9. Median(二分+二分)

    Median http://poj.org/problem?id=3579 Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 1 ...

  10. 使用DW工具给图片添加热点MAP

    一.准备一张图片.     准备一张需要给不同区域添加不同热点的图片. 二.插入图片: 打开Dreamweaver,新建一个网页,将图片插入到页面中. 三.找到地图工具: 单击鼠标左键点击图片,这时候 ...