【问题标题】:Django class-based view processing form and adjusting context accordinglyDjango 基于类的视图处理表单并相应地调整上下文
【发布时间】:2020-12-21 06:26:36
【问题描述】:

总的来说,我对 Django 和 Python 还是很陌生。我目前正在构建一个 Django 应用程序,并试图坚持基于类的视图。

我有一个我想要处理的表单 (FormView),这意味着获取数据、清理它并将其存储在数据库中。处理后,我只想再次显示表单(因此不会重定向到另一个成功页面)并在表单上方显示处理结果。我该怎么做?我已经使用 get_context_data 为结果消息添加额外的上下文,但无法弄清楚如何以及在哪里处理数据以及如何将它与更新上下文数据联系在一起。任何帮助将不胜感激。

forms.py:

from django import forms

class URLsForm(forms.Form):
    list_of_urls = forms.CharField(label='One URL per line', widget=forms.Textarea)

views.py

from django.views.generic import FormView
from .models import URL
from .forms import URLsForm

class URLBatchCreateView(FormView):
    form_class = URLsForm
    template_name = 'bot/url_batch_create.html'
    success_url = reverse_lazy('url_batch_create')

    def form_valid(self, form):
        return super(URLBatchCreateView, self).form_valid(form)

    def get_context_data(self, **kwargs):
            context = super().get_context_data(**kwargs)
            context['created_urls'] = 'The result'
            return context

url_batch_create.html:

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

{% block content %}

{% if created_urls %}
    <div>The following URLs where created:<br>{{ created_urls }}</div>
{% endif %}

<form action="" method ="post">
    {% csrf_token %}
    <table>
        {{ form.as_table }}
    </table>
    <input type="submit" value="Create">
</form>

{% endblock content %}

urls.py:

from django.urls import path
from .views import URLBatchCreateView

urlpatterns = [
    path('url/batchcreate', URLBatchCreateView.as_view(), name='url_batch_create'),
]

【问题讨论】:

    标签: python django


    【解决方案1】:

    我已经使用 get_context_data 来为结果消息添加额外的上下文

    是的,get_context_data 非常适合将数据传递给模板。

    但不知道如何以及在何处处理数据

    您在这方面也走在了正确的轨道上。可以在 form_valid 中完成。

    以及如何将其与更新上下文数据联系在一起。

    为此,您需要引用存储数据的数据库对象。您当前的方法在没有任何参数的情况下重定向到同一页面。那是行不通的,因为当浏览器从重定向的 URL 加载页面时,这是另一个请求,如果您没有对创建的对象的引用,则无法找到创建的对象。

    您可能想看看 CreateView 和 UpdateView,它们可能会提供更优雅的解决方案 (https://docs.djangoproject.com/en/3.1/topics/class-based-views/generic-editing/),但我将提供一个示例如何完成您当前的方法。

    您没有指定数据的存储方式,因此我将提供 models.py 的示例,以便我的其他更改有意义:

    from django.db import models
    
    class URLSet(models.Model):
        pass
    
    class URL(models.Model):
        urlset = models.ForeignKey(URLSet, related_name="urls",
                                   on_delete=models.CASCADE)
        url = models.URLField()
    

    URLBatchCreateView 也可以处理编辑,所以我将它重命名为 URLBatchCreateEditView。它应该能够获得对创建的 URLSet 对象的引用,即它的 id。然后我们可以在此基础上继续工作:

    from django.shortcuts import get_object_or_404
    from django.urls import reverse
    from django.views.generic import FormView
    
    from .forms import URLsForm
    from .models import URL, URLSet
    
    
    class URLBatchCreateEditView(FormView):
        form_class = URLsForm
        template_name = 'bot/url_batch_create.html'
    
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            self.urlset = None
    
        def get(self, request, *args, urlset_id=None, **kwargs):
            if urlset_id:
                self.urlset = get_object_or_404(URLSet, id=urlset_id)
            return super().get(request, *args, **kwargs)
    
        def get_initial(self):
            data = super().get_initial()
            if self.urlset:
                data.update({'list_of_urls': '\n'.join(self.get_urls())})
            return data
    
        def get_urls(self):
            if self.urlset is None:
                return None
            return [x.url for x in self.urlset.urls.all()]
    
        def form_valid(self, form):
            urls_text = form.cleaned_data['list_of_urls']
            if not self.urlset:
                self.urlset = URLSet.objects.create()
            else:
                self.urlset.urls.all().delete()
            for url in urls_text.splitlines():
                URL.objects.create(url=url, urlset=self.urlset)
            return super().form_valid(form)
    
        def get_success_url(self):
            return reverse('url_batch_edit', kwargs={'urlset_id': self.urlset.id})
    
        def get_context_data(self, **kwargs):
            context = super().get_context_data(**kwargs)
            context['created_urls'] = self.get_urls()
            context['urlset'] = self.urlset
            return context
    

    你也需要新的网址:

    urlpatterns = [
        path('url/batchcreate', URLBatchCreateEditView.as_view(),
             name='url_batch_create'),
        path('url/batchedit/<int:urlset_id>', URLBatchCreateEditView.as_view(),
             name='url_batch_edit'),
    ]
    

    也许按钮在编辑模式下不应该说“创建”:

    {% if urlset %}
        <input type="submit" value="Save changes">
    {% else %}
        <input type="submit" value="Create">
    {% endif %}
    

    最后,向表单添加验证可能是个好主意:

    from django import forms
    from django.core import validators
    
    
    def validate_url_lines(value, schemes=('http', 'https')):
        validate_url = validators.URLValidator(schemes=schemes)
        for line in value.splitlines():
            validate_url(line)
    
    
    class URLsForm(forms.Form):
        list_of_urls = forms.CharField(label='One URL per line',
                                       widget=forms.Textarea,
                                       validators=[validate_url_lines])
    

    【讨论】:

    • 我完全错过了这样一个事实,即最后有一个重定向,成功页面对提交的数据一无所知。使用单独的 URLSet 模型的有趣方法。试试这个。非常感谢!
    猜你喜欢
    • 2016-12-05
    • 2022-01-10
    • 2017-11-07
    • 2012-03-29
    • 2015-07-16
    • 2015-07-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多