Django Generic View form_valid无法在ManyToManyField上设置指定中间模型的值

时间:2016-07-13 08:32:36

标签: python django many-to-many

我在多对多关系中有三个表,一个Product表,一个Server表和一个将两个对象链接在一起的中间表。

每个服务器可以有许多产品,每个产品可以与多个服务器相关联。

以下是我的模特

#/myapp/models.py

class Server(TimeStampedModel):
    name = models.CharField(max_length=35)
    description = models.CharField(max_length=200)
    products = models.ManyToManyField('Product', through='ServerProduct',
                                      related_name='products')

class ServerProduct(TimeStampedModel):
    server = models.ForeignKey('Server', on_delete=models.CASCADE)
    product = models.ForeignKey('Product', on_delete=models.CASCADE)


class Product(TimeStampedModel):
    name = models.CharField(max_length=200)
    price = models.DecimalField(decimal_places=2, max_digits=11)
    servers = models.ManyToManyField(
        'Server', through='ServerProduct', related_name='servers')

在我的创建视图中,我指向一个表单,允许用户创建服务器,并选择它的相应产品......

在form_valid()内部我试图将每个产品链接到新服务器

#/myapp/views.py

class ServerCreateView(SuccessMessageMixin, CreateView):
        model = Server
        form_class = ServerForm
        ....

        def form_valid(self, form):
            server = form.save(False)
            server.save()
            for product in form.cleaned_data['products']:
                ServerProduct.objects.create(server=server, product=product)
            return super(ServerCreateView, self).form_valid(form)

我的表格如下......

class ServerForm(BlankToRequiredMixin):

    class Meta:
        model = Server
        fields = '__all__'
        widgets = {
            'name': forms.TextInput(attrs={'autofocus': 'autofocus'}),
        }

但是当我提交表单时,django会返回以下错误:

  

无法在指定中介的ManyToManyField上设置值   模型。请改用report.ServerProduct的管理器。

代替ServerProduct.objects.create(server=server, product=product)我还尝试了以下内容(阅读文档here后),但这会返回相同的错误

prod = ServerProduct(server=server, product=product)
prod.save()

知道如何解决这个问题吗? (最好还是使用Generic创建视图)

编辑:完全追溯

Environment:


Request Method: POST
Request URL: http://localhost:8000/server-create/

Django Version: 1.9.7
Python Version: 3.4.2
Installed Applications:
['django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'django_extensions',
 'auditlog',
 'rest_framework',
 'reports.apps.ReportsConfig']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware',
 'auditlog.middleware.AuditlogMiddleware']



Traceback:

File "/home/jwe/piesup2/venv/lib/python3.4/site-packages/django/core/handlers/base.py" in get_response
  149.                     response = self.process_exception_by_middleware(e, request)

File "/home/jwe/piesup2/venv/lib/python3.4/site-packages/django/core/handlers/base.py" in get_response
  147.                     response = wrapped_callback(request, *callback_args, **callback_kwargs)

File "/home/jwe/piesup2/venv/lib/python3.4/site-packages/django/views/generic/base.py" in view
  68.             return self.dispatch(request, *args, **kwargs)

File "/home/jwe/piesup2/venv/lib/python3.4/site-packages/django/views/generic/base.py" in dispatch
  88.         return handler(request, *args, **kwargs)

File "/home/jwe/piesup2/venv/lib/python3.4/site-packages/django/views/generic/edit.py" in post
  256.         return super(BaseCreateView, self).post(request, *args, **kwargs)

File "/home/jwe/piesup2/venv/lib/python3.4/site-packages/django/views/generic/edit.py" in post
  222.             return self.form_valid(form)

File "/home/jwe/piesup2/reports/views.py" in form_valid
  182.         return super(ServerCreateView, self).form_valid(form)

File "/home/jwe/piesup2/venv/lib/python3.4/site-packages/django/contrib/messages/views.py" in form_valid
  11.         response = super(SuccessMessageMixin, self).form_valid(form)

File "/home/jwe/piesup2/venv/lib/python3.4/site-packages/django/views/generic/edit.py" in form_valid
  201.         self.object = form.save()

File "/home/jwe/piesup2/venv/lib/python3.4/site-packages/django/forms/models.py" in save
  452.             self._save_m2m()

File "/home/jwe/piesup2/venv/lib/python3.4/site-packages/django/forms/models.py" in _save_m2m
  434.                 f.save_form_data(self.instance, cleaned_data[f.name])

File "/home/jwe/piesup2/venv/lib/python3.4/site-packages/django/db/models/fields/related.py" in save_form_data
  1618.         setattr(instance, self.attname, data)

File "/home/jwe/piesup2/venv/lib/python3.4/site-packages/django/db/models/fields/related_descriptors.py" in __set__
  481.         manager.set(value)

File "/home/jwe/piesup2/venv/lib/python3.4/site-packages/django/db/models/fields/related_descriptors.py" in set
  882.                     (opts.app_label, opts.object_name)

Exception Type: AttributeError at /server-create/
Exception Value: Cannot set values on a ManyToManyField which specifies an intermediary model. Use reports.ServerProduct's Manager instead.

1 个答案:

答案 0 :(得分:2)

回溯显示当您在super()方法中调用form_valid时发生错误。

File "/home/jwe/piesup2/reports/views.py" in form_valid
   182.         return super(ServerCreateView, self).form_valid(form)

您已在form_valid方法中保存表单,因此无需致电super()。只需重定向到成功网址即可。

    def form_valid(self, form):
        server = form.save(False)
        server.save()
        for product in form.cleaned_data['products']:
            ServerProduct.objects.create(server=server, product=product)

        return HttpResponseRedirect(self.get_success_url())

请记住添加导入:

from django http import HttpResponseRedirect