Reputation: 1717
I have three Tables in a many-to-many-relationship, a Product table, a Server table and an intemediary table to link the two objects together.
Each Server can have many products, and each product can be associated with more than one server.
Here are my models
#/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')
In my create view I'm pointing to a form to allow users to create a Server, and select it's corresponding products...
Inside form_valid() I'm trying to link each Product to the new Server
#/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)
My form looks as follows..
class ServerForm(BlankToRequiredMixin):
class Meta:
model = Server
fields = '__all__'
widgets = {
'name': forms.TextInput(attrs={'autofocus': 'autofocus'}),
}
However when I submit the form django returns the following error:
Cannot set values on a ManyToManyField which specifies an intermediary model. Use reports.ServerProduct's Manager instead.
In place of ServerProduct.objects.create(server=server, product=product)
I've also tried the following (after reading the documentation here) but this returns the same error
prod = ServerProduct(server=server, product=product)
prod.save()
Any idea how I could solve this? (Preferably still using the Generic create view)
EDIT: Full Traceback
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.
Upvotes: 2
Views: 655
Reputation: 309009
The traceback shows that the error is occurring when you call super()
in the form_valid
method.
File "/home/jwe/piesup2/reports/views.py" in form_valid
182. return super(ServerCreateView, self).form_valid(form)
You are already saving the form in your form_valid
method, so there is no need to call super()
. Just redirect to the success url instead.
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())
Remember to add the import:
from django http import HttpResponseRedirect
Upvotes: 3