Author: jacob
Date: 2007-02-26 11:17:11 -0600 (Mon, 26 Feb 2007)
New Revision: 4609

Added:
   django/trunk/tests/regressiontests/bug639/
   django/trunk/tests/regressiontests/bug639/__init__.py
   django/trunk/tests/regressiontests/bug639/models.py
   django/trunk/tests/regressiontests/bug639/test.jpg
   django/trunk/tests/regressiontests/bug639/tests.py
Modified:
   django/trunk/django/db/models/base.py
   django/trunk/django/db/models/fields/__init__.py
   django/trunk/django/db/models/manipulators.py
Log:
Objects with FileFields no longer get save() called multiple times from the 
AutomaticManipulator! This fixes #639, #572, and likely others I don't know of. 
 

This may be slightly backwards-incompatible: if you've been relying on the 
multiple-save behavior (why?), then you'll no longer see that happen.


Modified: django/trunk/django/db/models/base.py
===================================================================
--- django/trunk/django/db/models/base.py       2007-02-26 12:52:01 UTC (rev 
4608)
+++ django/trunk/django/db/models/base.py       2007-02-26 17:17:11 UTC (rev 
4609)
@@ -356,7 +356,7 @@
     def _get_FIELD_size(self, field):
         return os.path.getsize(self._get_FIELD_filename(field))
 
-    def _save_FIELD_file(self, field, filename, raw_contents):
+    def _save_FIELD_file(self, field, filename, raw_contents, save=True):
         directory = field.get_directory_name()
         try: # Create the date-based directory if it doesn't exist.
             os.makedirs(os.path.join(settings.MEDIA_ROOT, directory))
@@ -391,8 +391,9 @@
             if field.height_field:
                 setattr(self, field.height_field, height)
 
-        # Save the object, because it has changed.
-        self.save()
+        # Save the object because it has changed unless save is False
+        if save:
+            self.save()
 
     _save_FIELD_file.alters_data = True
 

Modified: django/trunk/django/db/models/fields/__init__.py
===================================================================
--- django/trunk/django/db/models/fields/__init__.py    2007-02-26 12:52:01 UTC 
(rev 4608)
+++ django/trunk/django/db/models/fields/__init__.py    2007-02-26 17:17:11 UTC 
(rev 4609)
@@ -635,7 +635,7 @@
         setattr(cls, 'get_%s_filename' % self.name, 
curry(cls._get_FIELD_filename, field=self))
         setattr(cls, 'get_%s_url' % self.name, curry(cls._get_FIELD_url, 
field=self))
         setattr(cls, 'get_%s_size' % self.name, curry(cls._get_FIELD_size, 
field=self))
-        setattr(cls, 'save_%s_file' % self.name, lambda instance, filename, 
raw_contents: instance._save_FIELD_file(self, filename, raw_contents))
+        setattr(cls, 'save_%s_file' % self.name, lambda instance, filename, 
raw_contents, save=True: instance._save_FIELD_file(self, filename, 
raw_contents, save))
         dispatcher.connect(self.delete_file, signal=signals.post_delete, 
sender=cls)
 
     def delete_file(self, instance):
@@ -653,14 +653,14 @@
     def get_manipulator_field_names(self, name_prefix):
         return [name_prefix + self.name + '_file', name_prefix + self.name]
 
-    def save_file(self, new_data, new_object, original_object, change, rel):
+    def save_file(self, new_data, new_object, original_object, change, rel, 
save=True):
         upload_field_name = self.get_manipulator_field_names('')[0]
         if new_data.get(upload_field_name, False):
             func = getattr(new_object, 'save_%s_file' % self.name)
             if rel:
-                func(new_data[upload_field_name][0]["filename"], 
new_data[upload_field_name][0]["content"])
+                func(new_data[upload_field_name][0]["filename"], 
new_data[upload_field_name][0]["content"], save)
             else:
-                func(new_data[upload_field_name]["filename"], 
new_data[upload_field_name]["content"])
+                func(new_data[upload_field_name]["filename"], 
new_data[upload_field_name]["content"], save)
 
     def get_directory_name(self):
         return 
os.path.normpath(datetime.datetime.now().strftime(self.upload_to))
@@ -704,12 +704,12 @@
         if not self.height_field:
             setattr(cls, 'get_%s_height' % self.name, 
curry(cls._get_FIELD_height, field=self))
 
-    def save_file(self, new_data, new_object, original_object, change, rel):
-        FileField.save_file(self, new_data, new_object, original_object, 
change, rel)
+    def save_file(self, new_data, new_object, original_object, change, rel, 
save=True):
+        FileField.save_file(self, new_data, new_object, original_object, 
change, rel, save)
         # If the image has height and/or width field(s) and they haven't
         # changed, set the width and/or height field(s) back to their original
         # values.
-        if change and (self.width_field or self.height_field):
+        if change and (self.width_field or self.height_field) and save:
             if self.width_field:
                 setattr(new_object, self.width_field, getattr(original_object, 
self.width_field))
             if self.height_field:

Modified: django/trunk/django/db/models/manipulators.py
===================================================================
--- django/trunk/django/db/models/manipulators.py       2007-02-26 12:52:01 UTC 
(rev 4608)
+++ django/trunk/django/db/models/manipulators.py       2007-02-26 17:17:11 UTC 
(rev 4609)
@@ -96,15 +96,17 @@
         if self.change:
             params[self.opts.pk.attname] = self.obj_key
 
-        # First, save the basic object itself.
+        # First, create the basic object itself.
         new_object = self.model(**params)
-        new_object.save()
 
-        # Now that the object's been saved, save any uploaded files.
+        # Now that the object's been created, save any uploaded files.
         for f in self.opts.fields:
             if isinstance(f, FileField):
-                f.save_file(new_data, new_object, self.change and 
self.original_object or None, self.change, rel=False)
+                f.save_file(new_data, new_object, self.change and 
self.original_object or None, self.change, rel=False, save=False)
 
+        # Now save the object
+        new_object.save()
+
         # Calculate which primary fields have changed.
         if self.change:
             self.fields_added, self.fields_changed, self.fields_deleted = [], 
[], []

Added: django/trunk/tests/regressiontests/bug639/__init__.py
===================================================================

Added: django/trunk/tests/regressiontests/bug639/models.py
===================================================================
--- django/trunk/tests/regressiontests/bug639/models.py                         
(rev 0)
+++ django/trunk/tests/regressiontests/bug639/models.py 2007-02-26 17:17:11 UTC 
(rev 4609)
@@ -0,0 +1,16 @@
+import tempfile
+from django.db import models
+
+class Photo(models.Model):
+    title = models.CharField(maxlength=30)
+    image = models.ImageField(upload_to=tempfile.gettempdir())
+    
+    # Support code for the tests; this keeps track of how many times save() 
gets
+    # called on each instance.
+    def __init__(self, *args, **kwargs):
+       super(Photo, self).__init__(*args, **kwargs)
+       self._savecount = 0
+    
+    def save(self):
+        super(Photo, self).save()
+        self._savecount +=1
\ No newline at end of file

Added: django/trunk/tests/regressiontests/bug639/test.jpg
===================================================================
(Binary files differ)


Property changes on: django/trunk/tests/regressiontests/bug639/test.jpg
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: django/trunk/tests/regressiontests/bug639/tests.py
===================================================================
--- django/trunk/tests/regressiontests/bug639/tests.py                          
(rev 0)
+++ django/trunk/tests/regressiontests/bug639/tests.py  2007-02-26 17:17:11 UTC 
(rev 4609)
@@ -0,0 +1,35 @@
+"""
+Tests for file field behavior, and specifically #639, in which Model.save() 
gets
+called *again* for each FileField. This test will fail if calling an
+auto-manipulator's save() method causes Model.save() to be called more than 
once.
+"""
+
+import os
+import unittest
+from regressiontests.bug639.models import Photo
+from django.http import QueryDict
+from django.utils.datastructures import MultiValueDict
+
+class Bug639Test(unittest.TestCase):
+        
+    def testBug639(self):
+        """
+        Simulate a file upload and check how many times Model.save() gets 
called.
+        """
+        # Grab an image for testing
+        img = open(os.path.join(os.path.dirname(__file__), "test.jpg"), 
"rb").read()
+        
+        # Fake a request query dict with the file
+        qd = QueryDict("title=Testing&image=", mutable=True)
+        qd["image_file"] = {
+            "filename" : "test.jpg",
+            "content-type" : "image/jpeg",
+            "content" : img
+        }
+        
+        manip = Photo.AddManipulator()
+        manip.do_html2python(qd)
+        p = manip.save(qd)
+        
+        # Check the savecount stored on the object (see the model)
+        self.assertEqual(p._savecount, 1)
\ No newline at end of file


--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/django-updates?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to