【问题标题】:passing args and kwargs to parent class with extra content in django CreateView在 django CreateView 中将 args 和 kwargs 传递给具有额外内容的父类
【发布时间】:2018-06-16 16:15:09
【问题描述】:

我制作了一个 django 表单,我想在其中传递一些我需要显示的上下文(主要是标签中的数据库条目,以便用户可以从中选择)。因此,我创建了一个get_context_data function,将上下文添加到现有上下文中,如下所示:

def get_context_data(self, **kwargs):
    context = super(UploadView, self).get_context_data(**kwargs)
    context['categories'] = Category.objects.all()
    context['form'] = VideoForm
    return context

但是,表单并没有保存传递给数据库的信息。为什么那行不通?

这是我的代码的一部分!

forms.py:

class VideoForm(forms.ModelForm):
    category = forms.ModelChoiceField(queryset=Category.objects.all(), empty_label=None)
    class Meta:
        model = Video
        fields = [
            'title',
            'description',
            'description_short',
            'category',
            'time',
            'thumbnail',
            'type',
        ]

    def clean_thumbnail(self):
        picture = self.cleaned_data.get("thumbnail")
        if not picture:
            raise forms.ValidationError("No Image")
        else:
            w, h = get_image_dimensions(picture)
            if w/h != (16/9):
                raise forms.ValidationError("Image in wrong aspect ratio (should be 16:9)")
        return picture

upload.html(比较长,最好上传到Pastebin)

views.py:

class UploadView(LoginRequiredMixin, CreateView):
   form_class = VideoForm
   template_name= 'upload.html'

   def form_valid(self, form):
       instance = form.save(commit=False)
       instance.uploader=self.request.user
       return super(UploadView, self).form_valid(form)

   def get_context_data(self, **kwargs):
       context = super(UploadView, self).get_context_data(**kwargs)
       context['categories'] = Category.objects.all()
       context['form'] = VideoForm
       return context

我正在使用自定义表单,因此我可以设置用于编辑 CSS 的类(而不是仅使用 form.as_p 并从那里获得一个非常丑陋的...)

编辑:

经过更多测试,我发现如果我将print(instance) 放在def form_valid(self, form): 函数中,它不会打印出任何内容,表明实例为空。怎么会这样?另外,我尝试删除:context['form'] = VideoForm 并没有出现任何错误,但如果我正确填写表格,它仍然无法正常工作!

编辑 2:

我创建了一个这样的“form_invalid”函数:

def form_invalid(self, form):
    print(form.instance)
    return super(UploadView, self).form_invalid()

导致:

TypeError: form_invalid() missing 1 required positional argument: 'form'

这让我想到,当我在提交后被重定向回表单时,我没有收到任何错误。这是我写的表格:https://pastebin.com/3H6VRZR1

我还尝试使用 form.as_p 对其进行测试,这会导致同样的问题

编辑 3:

在测试了一些答案后,我们发现 HTML 页面本身的表单可能是原因,因为表单到达 form_invalid() 时完全是空的。我决定再次尝试使用form.as_p,看看它是否仍然导致与我的custom form 相同的问题。现在我收到一个新错误:

null value in column "category_id" violates not-null constraint
DETAIL:  Failing row contains (8, test new fom reg, test-new-fom-reg, null, test, test, 2018-01-10 13:44:58.81876+00, 2018-01-10 13:44:58.818789+00, 1, thumbnails/test-new-fom-reg.png, 2, 1, /home/trie/Desktop/django/vidmiotest/media/videos/test.mp4).

与:

USER
admin

GET
No GET data

POST
Variable Value
title 'test new fom reg'
category '8'
type '1'
time '1'
description 'test'
csrfmiddlewaretoken `BeizxWHU5KDbixit9vpxKoxEeBxgU9MNITaNlkM1qtI0Aq6kIThHrtjfUsQXjxON'
description_short 'test'

FILES
Variable Value
thumbnail <TemporaryUploadedFile: sixteentonineratio.png (image/jpeg)>
videoFile <TemporaryUploadedFile: test 3.mp4 (video/mp4)>

作为数据从表单发送的数据表明(基于thiscategory_id 不在我的表单模型中。它是什么(该字段只是称为category),但它为什么认为它应该在那里?

我刚刚检查了 phppgadmin 以查看数据库的外观,那里的字段名为 id_category 而在我的模型中它被称为类别,为什么?

编辑 4:我从未为上述错误添加 Traceback:

内部服务器错误:/upload/ 回溯(最近一次通话最后): _execute 中的文件“/home/trie/Desktop/django/venv/lib/python3.5/site-packages/django/db/backends/utils.py”,第 85 行 返回 self.cursor.execute(sql, params) psycopg2.IntegrityError:“category_id”列中的空值违反非空约束 详细信息:失败行包含 (12, test, test, null, test, test, 2018-01-16 18:18:25.907513+00, 2018-01-16 18:18:25.907538+00, 6, thumbnails/test_d1MHjMX. png, 2, 1, /home/trie/Desktop/django/vidmiotest/media/videos/test.mp4)。

上述异常是以下异常的直接原因:

Traceback (most recent call last):
  File "/home/trie/Desktop/django/venv/lib/python3.5/site-packages/django/core/handlers/exception.py", line 35, in inner
    response = get_response(request)
  File "/home/trie/Desktop/django/venv/lib/python3.5/site-packages/django/core/handlers/base.py", line 128, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "/home/trie/Desktop/django/venv/lib/python3.5/site-packages/django/core/handlers/base.py", line 126, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/home/trie/Desktop/django/venv/lib/python3.5/site-packages/django/views/generic/base.py", line 69, in view
    return self.dispatch(request, *args, **kwargs)
  File "/home/trie/Desktop/django/venv/lib/python3.5/site-packages/django/contrib/auth/mixins.py", line 52, in dispatch
    return super().dispatch(request, *args, **kwargs)
  File "/home/trie/Desktop/django/venv/lib/python3.5/site-packages/django/views/generic/base.py", line 89, in dispatch
    return handler(request, *args, **kwargs)
  File "/home/trie/Desktop/django/venv/lib/python3.5/site-packages/django/views/generic/edit.py", line 172, in post
    return super().post(request, *args, **kwargs)
  File "/home/trie/Desktop/django/venv/lib/python3.5/site-packages/django/views/generic/edit.py", line 142, in post
    return self.form_valid(form)
  File "/home/trie/Desktop/django/vidmiotest/upload/views.py", line 21, in form_valid
    instance.save()
  File "/home/trie/Desktop/django/venv/lib/python3.5/site-packages/django/db/models/base.py", line 729, in save
    force_update=force_update, update_fields=update_fields)
  File "/home/trie/Desktop/django/venv/lib/python3.5/site-packages/django/db/models/base.py", line 759, in save_base
    updated = self._save_table(raw, cls, force_insert, force_update, using, update_fields)
  File "/home/trie/Desktop/django/venv/lib/python3.5/site-packages/django/db/models/base.py", line 842, in _save_table
    result = self._do_insert(cls._base_manager, using, fields, update_pk, raw)
  File "/home/trie/Desktop/django/venv/lib/python3.5/site-packages/django/db/models/base.py", line 880, in _do_insert
    using=using, raw=raw)
  File "/home/trie/Desktop/django/venv/lib/python3.5/site-packages/django/db/models/manager.py", line 82, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "/home/trie/Desktop/django/venv/lib/python3.5/site-packages/django/db/models/query.py", line 1125, in _insert
    return query.get_compiler(using=using).execute_sql(return_id)
  File "/home/trie/Desktop/django/venv/lib/python3.5/site-packages/django/db/models/sql/compiler.py", line 1280, in execute_sql
    cursor.execute(sql, params)
  File "/home/trie/Desktop/django/venv/lib/python3.5/site-packages/django/db/backends/utils.py", line 100, in execute
    return super().execute(sql, params)
  File "/home/trie/Desktop/django/venv/lib/python3.5/site-packages/django/db/backends/utils.py", line 68, in execute
    return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)
  File "/home/trie/Desktop/django/venv/lib/python3.5/site-packages/django/db/backends/utils.py", line 77, in _execute_with_wrappers
    return executor(sql, params, many, context)
  File "/home/trie/Desktop/django/venv/lib/python3.5/site-packages/django/db/backends/utils.py", line 85, in _execute
    return self.cursor.execute(sql, params)
  File "/home/trie/Desktop/django/venv/lib/python3.5/site-packages/django/db/utils.py", line 89, in __exit__
    raise dj_exc_value.with_traceback(traceback) from exc_value
  File "/home/trie/Desktop/django/venv/lib/python3.5/site-packages/django/db/backends/utils.py", line 85, in _execute
    return self.cursor.execute(sql, params)
django.db.utils.IntegrityError: null value in column "category_id" violates not-null constraint
DETAIL:  Failing row contains (12, test, test, null, test, test, 2018-01-16 18:18:25.907513+00, 2018-01-16 18:18:25.907538+00, 6, thumbnails/test_d1MHjMX.png, 2, 1, /home/trie/Desktop/django/vidmiotest/media/videos/test.mp4).

【问题讨论】:

  • 你需要保存你的实例变量instance.save()而不是调用super(UploadView, self).form_valid(form)。调用超类不会将self.request.user 保存到instance.uploader

标签: python html django forms


【解决方案1】:

问题中的问题是调用了 super().form_valid() 并用 context['form'] = VideoForm 覆盖了构造的表单。 让框架在使用 CreateView 时设置表单。

继承的 CreateView 提供设置表单、保存表单、在视图上设置 self.object 以及重定向到成功 url 的功能。

即 CreateView.form_valid 提供:

self.object = form.save()

解决方法是在UploadView中设置上传器是正确的,但是调用super.form_valid会再次尝试保存表单。

据我了解,期望的行为是:

  1. 设置上传者
  2. 保存对象
  3. 重定向到成功网址

在代码中:

instance = form.save(commit=False)
instance.uploader = self.request.user
instance.save()
return redirect(self.get_success_url()) # Skip the call to super

正如其他答案所指出的,context['form'] = VideoForm 将覆盖 CreateView 设置的表单。

我建议看看 CreateView 的执行流程是如何工作的,它会在 GET 和 POST 情况下为模板上下文设置表单。

另一种解决方法是让 VideoForm 在 init 中接受上传者:

class VideoForm(forms.ModelForm):
    def __init__(self, uploader, *args, **kwargs):
        self.uploader = uploader
        super().__init__(*args, **kwargs)

    def save(self, commit=True):
        instance = super().save(commit=False)
        instance.uploader = self.uploader
        if commit:
           instance.save()
        return instance

并将上传者提供给表单

 class UploadView(..., CreateView):
     def get_form_kwargs(self):
         kwargs= super().get_form_kwargs()
         kwargs['uploader'] = self.request.user
         return kwargs

希望对你有帮助。

查看EDIT 3

之所以说 'category_id' 是因为 django 模型中的外键会自动以 '_id' 为后缀作为数据库中的列名。 Documentation.

Video 模型可能有 Category 的外键。

如果您在数据库中找到 id_category,您可能与您的迁移/模型不同步了?您可能应该尝试清除数据库和/或重新运行 makemigrations/migrate

【讨论】:

  • 添加上传者的更好选择可能是在调用form.save()之前设置form.instance.uploader
  • 所以我尝试使用migrate 再次使数据库同步,但仍然无法正常工作。
  • 好吧奇怪,你测试过makemigrations吗?为了进一步提供帮助,我们需要查看视频和类别模型
【解决方案2】:

您当然不需要context['form'] = VideoForm 行。除此之外,它会覆盖现有的表单,这样您的模板就不会出现任何错误。

【讨论】:

  • 它有助于揭示错误,但没有解决问题
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-06
  • 2013-07-26
  • 2017-12-09
  • 2017-11-11
  • 2014-12-12
  • 1970-01-01
相关资源
最近更新 更多