【问题标题】:Models and ModelForms: needs to have a value for field "id" before this many-to-many relationship can be usedModels 和 ModelForms:在使用这种多对多关系之前,需要有一个字段“id”的值
【发布时间】:2020-09-10 15:55:50
【问题描述】:

我正在使用带有一些多对多字段的 Django 模型。我还使用 ModelForm 来生成关联的表单。我的理解是,只要不覆盖任何其他内容,Django 应该能够处理保存在 ModelForm 中的多对多字段?

对我来说,尝试这样做会导致此错误:

Internal Server Error: /cameramodel/create/
Traceback (most recent call last):
  File "/usr/local/lib/python3.8/site-packages/django/core/handlers/exception.py", line 34, in inner
    response = get_response(request)
  File "/usr/local/lib/python3.8/site-packages/django/core/handlers/base.py", line 115, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "/usr/local/lib/python3.8/site-packages/django/core/handlers/base.py", line 113, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/usr/local/lib/python3.8/site-packages/django/views/generic/base.py", line 71, in view
    return self.dispatch(request, *args, **kwargs)
  File "/usr/local/lib/python3.8/site-packages/django/contrib/auth/mixins.py", line 52, in dispatch
    return super().dispatch(request, *args, **kwargs)
  File "/usr/local/lib/python3.8/site-packages/django/views/generic/base.py", line 97, in dispatch
    return handler(request, *args, **kwargs)
  File "/usr/local/lib/python3.8/site-packages/django/views/generic/edit.py", line 172, in post
    return super().post(request, *args, **kwargs)
  File "/usr/local/lib/python3.8/site-packages/django/views/generic/edit.py", line 141, in post
    if form.is_valid():
  File "/usr/local/lib/python3.8/site-packages/django/forms/forms.py", line 185, in is_valid
    return self.is_bound and not self.errors
  File "/usr/local/lib/python3.8/site-packages/django/forms/forms.py", line 180, in errors
    self.full_clean()
  File "/usr/local/lib/python3.8/site-packages/django/forms/forms.py", line 383, in full_clean
    self._post_clean()
  File "/usr/local/lib/python3.8/site-packages/django/forms/models.py", line 403, in _post_clean
    self.instance.full_clean(exclude=exclude, validate_unique=False)
  File "/usr/local/lib/python3.8/site-packages/django/db/models/base.py", line 1188, in full_clean
    self.clean()
  File "./schema/models.py", line 1439, in clean
    if self.metering_modes is True:
  File "/usr/local/lib/python3.8/site-packages/django/db/models/fields/related_descriptors.py", line 527, in __get__
    return self.related_manager_cls(instance)
  File "/usr/local/lib/python3.8/site-packages/django/db/models/fields/related_descriptors.py", line 838, in __init__
    raise ValueError('"%r" needs to have a value for field "%s" before '
ValueError: "<CameraModel: Canon Canonflex R2000>" needs to have a value for field "id" before this many-to-many relationship can be used.

所以我查看了文档,似乎我需要覆盖ModelForm 中的save 方法。所以我这样做了:

class CameraModelForm(ModelForm):
    class Meta:
        model = CameraModel
        fields = '__all__'

    def save(self, commit=True):
        form = super(CameraModelForm, self).save(commit=False)
        if commit:
            form.save(commit=False)
            form.save_m2m()
        return form

相反,我得到了一个不同的错误:

TypeError at /cameramodel/create/
save() got an unexpected keyword argument 'commit'
Request Method: POST
Request URL:    http://localhost:8000/cameramodel/create/
Django Version: 2.2.12
Exception Type: TypeError
Exception Value:    
save() got an unexpected keyword argument 'commit'
Exception Location: /home/jonathan/git/camerahub/schema/models.py in save, line 1397

models.py:1397 实际上是一个重写的模型保存以添加一个 slug 字段:

class CameraModel(models.Model):
# other stuff here
    def save(self, *args, **kwargs):
        if not self.slug:
            custom_slugify_unique = UniqueSlugify(
                unique_check=cameramodel_check, to_lower=True)
            self.slug = custom_slugify_unique("{} {} {}".format(
                self.manufacturer.name, self.model, str(self.disambiguation or '')))
        super().save(*args, **kwargs)

对于它的价值,我在其他一些模型中使用多对多字段,我没有看到它们有问题。不过,我是一名 Python/Django 初学者,我非常坚持这一点,因为仅仅遵循类似这样的一百万个其他帖子的建议并没有帮助我。感谢任何人可以提供的任何建议或代码 sn-ps。

如果有人需要更多上下文,整个项目都是开源的,这个分支可以在这里找到:https://github.com/djjudas21/camerahub/tree/278c_m2m_error

【问题讨论】:

    标签: python django django-forms save django-orm


    【解决方案1】:

    如果您覆盖 save 方法,这意味着您希望在保存表单之前进行一些检查/更改。我会这样做:

    def save(self):
          form = super(CameraModelForm, self).save(commit=False)
          if ...: # some condition on form values
              form.save() # remove the commit here
              form.save_m2m()
          return form
    

    【讨论】:

    • 感谢您的回复。我试过这个,但它失败了AttributeError at /cameramodel/create/ 'CameraModel' object has no attribute 'save_m2m'。我相信这是因为 save_m2m 属性仅在 form 先前已与 commit=False 保存时才定义
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-07-20
    • 1970-01-01
    • 2020-08-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多