Issue: Model with ManyToManyField throws NOT NULL constraint failed
Author: kpoman
State: closed
Created: 2018-06-08 19:13:04

Hello,
When creating an object of a Model that uses a ManyToManyField, one cannot set the property of the field before saving the object, otherwise it throws a NOT NULL constraint failed error.
For example:
obj = SomeModel()
obj.some_many2many_field = [1, 2, 3]
obj.save()

fails, but:

obj = SomeModel()
obj.save()
obj.some_many2many_field = [1, 2, 3]
obj.save()

works. No particular problem, just curious if there is something less ugly.

The error is:

> Traceback (most recent call last):
>   File "C:\Users\kpoman\PycharmProjects\theone-ai\venv\lib\site-packages\peewee.py", line 2576, in execute_sql
>     cursor.execute(sql, params or ())
> sqlite3.IntegrityError: NOT NULL constraint failed: jeweler_styles_through.jeweler_id
> 
> During handling of the above exception, another exception occurred:
> 
> Traceback (most recent call last):
>   File "C:\Users\kpoman\PycharmProjects\theone-ai\venv\lib\site-packages\flask\app.py", line 2292, in wsgi_app
>     response = self.full_dispatch_request()
>   File "C:\Users\kpoman\PycharmProjects\theone-ai\venv\lib\site-packages\flask\app.py", line 1815, in full_dispatch_request
>     rv = self.handle_user_exception(e)
>   File "C:\Users\kpoman\PycharmProjects\theone-ai\venv\lib\site-packages\flask\app.py", line 1718, in handle_user_exception
>     reraise(exc_type, exc_value, tb)
>   File "C:\Users\kpoman\PycharmProjects\theone-ai\venv\lib\site-packages\flask\_compat.py", line 35, in reraise
>     raise value
>   File "C:\Users\kpoman\PycharmProjects\theone-ai\venv\lib\site-packages\flask\app.py", line 1813, in full_dispatch_request
>     rv = self.dispatch_request()
>   File "C:\Users\kpoman\PycharmProjects\theone-ai\venv\lib\site-packages\flask\app.py", line 1799, in dispatch_request
>     return self.view_functions[rule.endpoint](**req.view_args)
>   File "C:\Users\kpoman\PycharmProjects\theone-ai\theone_ai\views\jeweler.py", line 47, in add
>     form.populate_obj(jeweler)
>   File "C:\Users\kpoman\PycharmProjects\theone-ai\venv\lib\site-packages\wtforms\form.py", line 96, in populate_obj
>     field.populate_obj(obj, name)
>   File "C:\Users\kpoman\PycharmProjects\theone-ai\venv\lib\site-packages\wtforms\fields\core.py", line 330, in populate_obj
>     setattr(obj, name, self.data)
>   File "C:\Users\kpoman\PycharmProjects\theone-ai\venv\lib\site-packages\peewee.py", line 4450, in __set__
>     query.add(value, clear_existing=True)
>   File "C:\Users\kpoman\PycharmProjects\theone-ai\venv\lib\site-packages\peewee.py", line 6089, in add
>     accessor.through_model.insert_many(inserts).execute()
>   File "C:\Users\kpoman\PycharmProjects\theone-ai\venv\lib\site-packages\peewee.py", line 1525, in inner
>     return method(self, database, *args, **kwargs)
>   File "C:\Users\kpoman\PycharmProjects\theone-ai\venv\lib\site-packages\peewee.py", line 1596, in execute
>     return self._execute(database)
>   File "C:\Users\kpoman\PycharmProjects\theone-ai\venv\lib\site-packages\peewee.py", line 2239, in _execute
>     return super(Insert, self)._execute(database)
>   File "C:\Users\kpoman\PycharmProjects\theone-ai\venv\lib\site-packages\peewee.py", line 2014, in _execute
>     cursor = database.execute(self)
>   File "C:\Users\kpoman\PycharmProjects\theone-ai\venv\lib\site-packages\peewee.py", line 2589, in execute
>     return self.execute_sql(sql, params, commit=commit)
>   File "C:\Users\kpoman\PycharmProjects\theone-ai\venv\lib\site-packages\peewee.py", line 2583, in execute_sql
>     self.commit()
>   File "C:\Users\kpoman\PycharmProjects\theone-ai\venv\lib\site-packages\peewee.py", line 2376, in __exit__
>     reraise(new_type, new_type(*exc_args), traceback)
>   File "C:\Users\kpoman\PycharmProjects\theone-ai\venv\lib\site-packages\peewee.py", line 175, in reraise
>     raise value.with_traceback(tb)
>   File "C:\Users\kpoman\PycharmProjects\theone-ai\venv\lib\site-packages\peewee.py", line 2576, in execute_sql
>     cursor.execute(sql, params or ())
> peewee.IntegrityError: NOT NULL constraint failed: jeweler_styles_through.jeweler_id
> 127.0.0.1 - - [08/Jun/2018 15:59:57] "POST /jeweler/add?product=wg10x HTTP/1.1" 500 -
> 

Yeah, this is expected behavior because how can you create a reference in a through table if the object you're referencing doesn't have a primary key yet? Added a note to the docs to hopefully clarify this a little.