Skip to main content
 首页 » 编程设计

python之Django 通用 View form_valid 无法在指定中间模型的 ManyToManyField 上设置值

2024年08月22日27rubylouvre

我在多对多关系中有三个表,一个产品表,一个服务器表和一个将两个对象链接在一起的中间表。

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

这是我的模型

#/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') 

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

在 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 返回以下错误:

Cannot set values on a ManyToManyField which specifies an intermediary model. Use reports.ServerProduct's Manager instead.

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

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

知道如何解决这个问题吗? (最好还是使用Generic create view)

编辑:完整追溯

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. 

请您参考如下方法:

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

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

您已经在 form_valid 方法中保存了表单,因此无需调用 super()。只需重定向到成功 url。

    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