Warn about mutable defaults with ArrayField
I found an issue when upgrading to Django 1.8 and using the new ArrayField and a model's instance methods.
This code will cause Model#array_field's data to bleed between different instances.
def add_to_array(self, item):
if item not in self.array_field:
self.array_field.append(item)
However, this code does the correct thing:
def add_to_array(self, item):
existing = self.array_field
if item not in self.array_field:
self.array_field = existing + [item]
I put together a django project/app with the code and tests that show the problems with self.array_field.append(). It also has a Vagrant file setup that should also exhibit the problems.
https://github.com/redbeard0x0a/django18bug
Change History
(11)
Severity: |
Normal → Release blocker
|
Triage Stage: |
Unreviewed → Accepted
|
Resolution: |
→ worksforme
|
Status: |
new → closed
|
Component: |
contrib.postgres → Documentation
|
Owner: |
set to nobody
|
Resolution: |
worksforme
|
Severity: |
Release blocker → Normal
|
Status: |
closed → new
|
Summary: |
ArrayField data bleeds between instances when using field.append(item) → Warn about mutable defaults with ArrayField
|
Type: |
Bug → Cleanup/optimization
|
Owner: |
changed from nobody to MZ
|
Status: |
new → assigned
|
Patch needs improvement: |
set
|
Patch needs improvement: |
unset
|
Patch needs improvement: |
set
|
Patch needs improvement: |
unset
|
Resolution: |
→ fixed
|
Status: |
assigned → closed
|
The issue in your example code is that you have used
default=[]
. This default is shared between all instances and in this case it is mutable, so you are modifying the default array.The correct code is to use
default=list
.I don't consider this a bug in Django - this is the same behaviour as you would get if you have code like:
The first call to
myfunc(1)
would return[1]
, the second[1, 1]
, etc.