summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRussell Keith-Magee <russell@keith-magee.com>2010-04-15 12:41:08 +0000
committerRussell Keith-Magee <russell@keith-magee.com>2010-04-15 12:41:08 +0000
commit2faa3acb4bb55f1830d517473c4bfb1616f92726 (patch)
tree0d39b2c702f6cc6e5cb898f6c07cceb0116beb27
parentd9aaad4e36ba2ebba13fd1c36da9eced4f7688ad (diff)
Fixed #13328 -- Added a __getstate__/__setstate__ pair to fields so that callable default values aren't pickled. Thanks to bkonkle for the report, and Vitaly Babiy for the patch.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@12977 bcc190cf-cafb-0310-a4f2-bffc1f526a37
-rw-r--r--AUTHORS1
-rw-r--r--django/db/models/fields/__init__.py14
-rw-r--r--django/db/models/fields/proxy.py9
-rw-r--r--django/db/models/options.py4
-rw-r--r--tests/regressiontests/queryset_pickle/models.py12
-rw-r--r--tests/regressiontests/queryset_pickle/tests.py15
6 files changed, 49 insertions, 6 deletions
diff --git a/AUTHORS b/AUTHORS
index b06bbd6977..34260573b2 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -57,6 +57,7 @@ answer newbie questions, and generally made Django that much better:
David Avsajanishvili <avsd05@gmail.com>
Mike Axiak <axiak@mit.edu>
Niran Babalola <niran@niran.org>
+ Vitaly Babiy <vbabiy86@gmail.com>
Morten Bagai <m@bagai.com>
Jeff Balogh <jbalogh@mozilla.com>
Mikaƫl Barbero <mikael.barbero nospam at nospam free.fr>
diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py
index 281963f3f5..1dc8dfe858 100644
--- a/django/db/models/fields/__init__.py
+++ b/django/db/models/fields/__init__.py
@@ -132,6 +132,19 @@ class Field(object):
memodict[id(self)] = obj
return obj
+ def __getstate__(self):
+ "Don't try to pickle a callable default value"
+ obj_dict = self.__dict__.copy()
+ del obj_dict['default']
+ return obj_dict
+
+ def __setstate__(self, data):
+ "When unpickling, restore the callable default"
+ self.__dict__.update(data)
+
+ # Restore the default
+ self.default = self.model._meta.get_field_by_name(self.name)[0].default
+
def to_python(self, value):
"""
Converts the input value into the expected Python data type, raising
@@ -233,6 +246,7 @@ class Field(object):
def contribute_to_class(self, cls, name):
self.set_attributes_from_name(name)
+ self.model = cls
cls._meta.add_field(self)
if self.choices:
setattr(cls, 'get_%s_display' % self.name, curry(cls._get_FIELD_display, field=self))
diff --git a/django/db/models/fields/proxy.py b/django/db/models/fields/proxy.py
index 31a31e3c3c..10da0dd431 100644
--- a/django/db/models/fields/proxy.py
+++ b/django/db/models/fields/proxy.py
@@ -10,7 +10,10 @@ class OrderWrt(fields.IntegerField):
A proxy for the _order database field that is used when
Meta.order_with_respect_to is specified.
"""
- name = '_order'
- attname = '_order'
- column = '_order'
+ def __init__(self, model, *args, **kwargs):
+ super(OrderWrt, self).__init__(*args, **kwargs)
+ self.model = model
+ self.attname = '_order'
+ self.column = '_order'
+ self.name = '_order'
diff --git a/django/db/models/options.py b/django/db/models/options.py
index 01a13b4ac3..f9cfeb0f04 100644
--- a/django/db/models/options.py
+++ b/django/db/models/options.py
@@ -104,11 +104,11 @@ class Options(object):
self.db_table = "%s_%s" % (self.app_label, self.module_name)
self.db_table = truncate_name(self.db_table, connection.ops.max_name_length())
-
def _prepare(self, model):
if self.order_with_respect_to:
self.order_with_respect_to = self.get_field(self.order_with_respect_to)
self.ordering = ('_order',)
+ self._order = OrderWrt(model)
else:
self.order_with_respect_to = None
@@ -331,7 +331,7 @@ class Options(object):
for f, model in self.get_fields_with_model():
cache[f.name] = (f, model, True, False)
if self.order_with_respect_to:
- cache['_order'] = OrderWrt(), None, True, False
+ cache['_order'] = self._order, None, True, False
if app_cache_ready():
self._name_map = cache
return cache
diff --git a/tests/regressiontests/queryset_pickle/models.py b/tests/regressiontests/queryset_pickle/models.py
index ec4bbed096..b0cae0a41f 100644
--- a/tests/regressiontests/queryset_pickle/models.py
+++ b/tests/regressiontests/queryset_pickle/models.py
@@ -1,8 +1,20 @@
+import datetime
from django.db import models
from django.utils.translation import ugettext_lazy as _
+class Numbers(object):
+
+ @classmethod
+ def get_number(self):
+ return 2
+
class Group(models.Model):
name = models.CharField(_('name'), max_length=100)
class Event(models.Model):
group = models.ForeignKey(Group)
+
+class Happening(models.Model):
+ when = models.DateTimeField(blank=True, default=datetime.datetime.now)
+ name = models.CharField(blank=True, max_length=100, default=lambda:"test")
+ number = models.IntegerField(blank=True, default=Numbers.get_number)
diff --git a/tests/regressiontests/queryset_pickle/tests.py b/tests/regressiontests/queryset_pickle/tests.py
index 8191403be7..8384df5647 100644
--- a/tests/regressiontests/queryset_pickle/tests.py
+++ b/tests/regressiontests/queryset_pickle/tests.py
@@ -1,8 +1,9 @@
import pickle
+import datetime
from django.test import TestCase
-from models import Group, Event
+from models import Group, Event, Happening
class PickleabilityTestCase(TestCase):
@@ -12,3 +13,15 @@ class PickleabilityTestCase(TestCase):
def test_related_field(self):
g = Group.objects.create(name="Ponies Who Own Maybachs")
self.assert_pickles(Event.objects.filter(group=g.id))
+
+ def test_datetime_callable_default_all(self):
+ self.assert_pickles(Happening.objects.all())
+
+ def test_datetime_callable_default_filter(self):
+ self.assert_pickles(Happening.objects.filter(when=datetime.datetime.now()))
+
+ def test_lambda_as_default(self):
+ self.assert_pickles(Happening.objects.filter(name="test"))
+
+ def test_callable_as_default(self):
+ self.assert_pickles(Happening.objects.filter(number=1))