Re: [Django] #15025: Different template rendering semantics since r14992

2011-01-08 Thread Django
#15025: Different template rendering semantics since r14992
--+-
  Reporter:  donspaulding | Owner:  nobody 
Status:  new  | Milestone:  1.3
 Component:  Template system  |   Version:  SVN
Resolution:   |  Keywords:  blocker, regression
 Stage:  Accepted | Has_patch:  1  
Needs_docs:  0|   Needs_tests:  0  
Needs_better_patch:  0|  
--+-
Comment (by anonymous):

 I can confirm that the patch fixed the problem for my case. Thank you :)

-- 
Ticket URL: 
Django 
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To post to this group, send email to django-upda...@googlegroups.com.
To unsubscribe from this group, send email to 
django-updates+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/django-updates?hl=en.



Re: [Django] #14801: Support for string methods with lazy translations

2011-01-08 Thread Django
#14801: Support for string methods with lazy translations
---+
  Reporter:  bronger   | Owner:  nobody
Status:  closed| Milestone:
 Component:  Internationalization  |   Version:  1.2   
Resolution:  wontfix   |  Keywords:
 Stage:  Unreviewed| Has_patch:  0 
Needs_docs:  0 |   Needs_tests:  0 
Needs_better_patch:  0 |  
---+
Comment (by bronger):

 Actually it's about applying transformations to a lazy object rather than
 gettext.  I solve this problem currently like this:

 {{{
 def format_lazy(string, *args, **kwargs):
 return string.format(*args, **kwargs)
 format_lazy = allow_lazy(format_lazy, unicode)
 }}}

 (BTW, it would be nice if you could use {{{allow_lazy}}} as a Python
 decorator.)

 and then in models.py:

 {{{
 class Meta:
 verbose_name = format_lazy(_(u"Raman {apparatus_number}
 measurement"), apparatus_number=1)
 }}}

 I found {{{allow_lazy}}} after I had wrote this issue report, which turns
 it into an enhancement request because I'd still prefer

 {{{
 class Meta:
 verbose_name = _(u"Raman {apparatus_number}
 measurement").format(apparatus_number=1)
 }}}

 i.e., if the lazy strings would implement some of the string methods.

-- 
Ticket URL: 
Django 
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To post to this group, send email to django-upda...@googlegroups.com.
To unsubscribe from this group, send email to 
django-updates+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/django-updates?hl=en.



Re: [Django] #15027: Updated RU translation

2011-01-08 Thread Django
#15027: Updated RU translation
---+
  Reporter:  blackraven| Owner:  blackraven 
Status:  new   | Milestone: 
 Component:  Translations  |   Version:  SVN
Resolution:|  Keywords:  russian translation
 Stage:  Accepted  | Has_patch:  1  
Needs_docs:  0 |   Needs_tests:  0  
Needs_better_patch:  0 |  
---+
Changes (by kmike):

 * cc: kmike (added)

Comment:

 Some notes:

 a) this string seems not be translated (or I've misread a patch): "Please
 either submit a file or check the clear checkbox, not both."

 b) 4959 msgstr "%.1f TБ"  - T is latin, Б is cyrillic, that can cause
 troubles

 c) Some code in the end of the patch is added but commented out. Is this
 intended?

 It'll be helpful if you will provide a full resulting po file and make a
 thread here: http://softwaremaniacs.org/forum/django/
 Russian translations for django 1.1 and django 1.2 were discussed that way
 (please look at http://softwaremaniacs.org/forum/django/20256/ and
 http://softwaremaniacs.org/forum/django/9674/ )

-- 
Ticket URL: 
Django 
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To post to this group, send email to django-upda...@googlegroups.com.
To unsubscribe from this group, send email to 
django-updates+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/django-updates?hl=en.



Re: [Django] #15013: Add Russian (ru) local flavour

2011-01-08 Thread Django
#15013: Add Russian (ru) local flavour
-+--
  Reporter:  blackraven  | Owner:  blackraven   
  
Status:  assigned| Milestone:   
  
 Component:  django.contrib.localflavor  |   Version:  SVN  
  
Resolution:  |  Keywords:  localflavor 
russian
 Stage:  Accepted| Has_patch:  1
  
Needs_docs:  0   |   Needs_tests:  0
  
Needs_better_patch:  0   |  
-+--
Comment (by kmike):

 Phone regexp is too restrictive.

 It, for example, does not support cities with 4-digit codes. More examples
 of valid but obscure phone numbers and different regexps that are trying
 to solve the problem can be found here:
 http://habrahabr.ru/blogs/regex/110731/

 I propose just to remove the phone validation - it is very hard to
 implement it properly and it doesn't provide much benefit, the simple min.
 length check is a proper solution in most cases.

-- 
Ticket URL: 
Django 
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To post to this group, send email to django-upda...@googlegroups.com.
To unsubscribe from this group, send email to 
django-updates+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/django-updates?hl=en.



Re: [Django] #15013: Add Russian (ru) local flavour

2011-01-08 Thread Django
#15013: Add Russian (ru) local flavour
-+--
  Reporter:  blackraven  | Owner:  blackraven   
  
Status:  assigned| Milestone:   
  
 Component:  django.contrib.localflavor  |   Version:  SVN  
  
Resolution:  |  Keywords:  localflavor 
russian
 Stage:  Accepted| Has_patch:  1
  
Needs_docs:  0   |   Needs_tests:  0
  
Needs_better_patch:  0   |  
-+--
Changes (by anonymous):

 * cc: kmike (added)

-- 
Ticket URL: 
Django 
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To post to this group, send email to django-upda...@googlegroups.com.
To unsubscribe from this group, send email to 
django-updates+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/django-updates?hl=en.



Re: [Django] #15030: ModelAdmin media docs don't mention STATIC_URL

2011-01-08 Thread Django
#15030: ModelAdmin media docs don't mention STATIC_URL
+---
  Reporter:  jezdez | Owner:  anonymous
Status:  assigned   | Milestone:  1.3  
 Component:  Documentation  |   Version:  SVN  
Resolution: |  Keywords:   
 Stage:  Accepted   | Has_patch:  1
Needs_docs:  0  |   Needs_tests:  0
Needs_better_patch:  0  |  
+---
Changes (by Silva):

  * owner:  nobody => anonymous
  * status:  new => assigned
  * has_patch:  0 => 1

Comment:

 Added the mentioned missing documentation, this being my first time
 helping out on the Django project and after following the rules mention on
 the wiki for contributing i hope it helps.

 If it does need any changes please let me know.

-- 
Ticket URL: 
Django 
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To post to this group, send email to django-upda...@googlegroups.com.
To unsubscribe from this group, send email to 
django-updates+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/django-updates?hl=en.



[Changeset] r15166 - django/trunk/docs/ref/contrib/admin

2011-01-08 Thread noreply
Author: timo
Date: 2011-01-08 15:15:00 -0600 (Sat, 08 Jan 2011)
New Revision: 15166

Modified:
   django/trunk/docs/ref/contrib/admin/index.txt
Log:
Fixed #15003 - assorted edits to admin docs; thanks adamv.

Modified: django/trunk/docs/ref/contrib/admin/index.txt
===
--- django/trunk/docs/ref/contrib/admin/index.txt   2011-01-08 16:13:58 UTC 
(rev 15165)
+++ django/trunk/docs/ref/contrib/admin/index.txt   2011-01-08 21:15:00 UTC 
(rev 15166)
@@ -11,13 +11,6 @@
 the site. In this document, we discuss how to activate, use and customize
 Django's admin interface.
 
-.. admonition:: Note
-
-The admin site has been refactored significantly since Django 0.96. This
-document describes the newest version of the admin site, which allows for
-much richer customization. If you follow the development of Django itself,
-you may have heard this described as "newforms-admin."
-
 Overview
 
 
@@ -26,8 +19,8 @@
 1. Add ``'django.contrib.admin'`` to your :setting:`INSTALLED_APPS`
setting.
 
-2. Admin has two dependencies - ``django.contrib.auth`` and
-   ``django.contrib.contenttypes``. If these applications are not
+2. Admin has two dependencies - :mod:`django.contrib.auth` and
+   :mod:`django.contrib.contenttypes`. If these applications are not
in your :setting:`INSTALLED_APPS` list, add them.
 
 3. Determine which of your application's models should be editable in the
@@ -87,7 +80,7 @@
 
 admin.site.register(Author)
 
-``ModelAdmin`` Options
+``ModelAdmin`` options
 --
 
 The ``ModelAdmin`` is very flexible. It has several options for dealing with
@@ -97,6 +90,26 @@
 class AuthorAdmin(admin.ModelAdmin):
 date_hierarchy = 'pub_date'
 
+.. attribute:: ModelAdmin.actions
+
+A list of actions to make available on the change list page. See
+:doc:`/ref/contrib/admin/actions` for details.
+
+.. attribute:: ModelAdmin.actions_on_top
+.. attribute:: ModelAdmin.actions_on_bottom
+
+Controls where on the page the actions bar appears. By default, the admin
+changelist displays actions at the top of the page (``actions_on_top = 
True;
+actions_on_bottom = False``).
+
+.. attribute:: ModelAdmin.actions_selection_counter
+
+.. versionadded:: 1.2
+
+Controls whether a selection counter is display next to the action 
dropdown.
+By default, the admin changelist will display it
+(``actions_selection_counter = True``).
+
 .. attribute:: ModelAdmin.date_hierarchy
 
 Set ``date_hierarchy`` to the name of a ``DateField`` or ``DateTimeField``
@@ -109,19 +122,60 @@
 
 .. versionadded:: 1.3
 
-This will intelligently populate itself based on available data,
-e.g. if all the dates are in one month, it'll show the day-level
-drill-down only.
+This will intelligently populate itself based on available data,
+e.g. if all the dates are in one month, it'll show the day-level
+drill-down only.
 
-.. attribute:: ModelAdmin.form
+.. attribute:: ModelAdmin.exclude
 
-By default a ``ModelForm`` is dynamically created for your model. It is
-used to create the form presented on both the add/change pages. You can
-easily provide your own ``ModelForm`` to override any default form behavior
-on the add/change pages.
+This attribute, if given, should be a list of field names to exclude from
+the form.
 
-For an example see the section `Adding custom validation to the admin`_.
+For example, let's consider the following model::
 
+class Author(models.Model):
+name = models.CharField(max_length=100)
+title = models.CharField(max_length=3)
+birth_date = models.DateField(blank=True, null=True)
+
+If you want a form for the ``Author`` model that includes only the ``name``
+and ``title`` fields, you would specify ``fields`` or ``exclude`` like
+this::
+
+class AuthorAdmin(admin.ModelAdmin):
+fields = ('name', 'title')
+
+class AuthorAdmin(admin.ModelAdmin):
+exclude = ('birth_date',)
+
+Since the Author model only has three fields, ``name``, ``title``, and
+``birth_date``, the forms resulting from the above declarations will
+contain exactly the same fields.
+
+.. attribute:: ModelAdmin.fields
+
+Use this option as an alternative to ``fieldsets`` if the layout does not
+matter and if you want to only show a subset of the available fields in the
+form. For example, you could define a simpler version of the admin form for
+the ``django.contrib.flatpages.FlatPage`` model as follows::
+
+class FlatPageAdmin(admin.ModelAdmin):
+fields = ('url', 'title', 'content')
+
+In the above example, only the fields 'url', 'title' and 'content' will be
+displayed, sequentially, in the form.
+
+.. versionadded:: 1.2
+
+``fields`` can contain 

Re: [Django] #13883: SelectBox.js with grouping (optgroup elements)

2011-01-08 Thread Django
#13883: SelectBox.js with grouping (optgroup elements)
---+
  Reporter:  SardarNL  | Owner:  nobody 
  
Status:  new   | Milestone:  1.3
  
 Component:  django.contrib.admin  |   Version:  1.2
  
Resolution:|  Keywords:  admin, SelectBox, 
optgroup, sprintdec2010
 Stage:  Accepted  | Has_patch:  1  
  
Needs_docs:  0 |   Needs_tests:  0  
  
Needs_better_patch:  0 |  
---+
Changes (by SardarNL):

  * needs_better_patch:  1 => 0

Comment:

 julien thanks for the test case.

 > except that the add popup (which appears after clicking the green cross
 icon) does not work properly.
 Fixed, but involves a little more changes than a thought first time.

 Drop-in replacement SelectBox.js has now fully compatible API as the
 original SlectBox.js, the group argument is optional. If there is no
 group, then option is added to 'not-grouped' option list.
 RelatedObjectLookups.js is updated to take optional group in account.

 A more painful update is needed for
 django.contrib.admin.options.ModelAdmin.response_add as it knows nothing
 about groups. Small patch looks for 'list_grouping' attribute, if it
 exists, then it is assumed to refer to the property returning the object's
 group. This assumes a group is a single property that can be turned into
 string.

 In short: if men needs just proper optgroup handling and doesn't mind if
 new objects will be added to 'no-group' list, then only SelectBox.js patch
 is needed.
 If men wants that new elements will be placed in the proper group, then
 RelatedObjectLookups.js and options.py patches are needed too. Of course
 this is only graphical issue.

 Updated test case:
 {{{
 from django.db import models

 class Sport(models.Model):
 name = models.CharField(max_length=100)
 is_team_sport = models.BooleanField(default=False)

 def __unicode__(self):
 return self.name

 @property
 def group(self):
 return 'Team Sports' if self.is_team_sport else 'Single Sports'

 class Profile(models.Model):
 sports = models.ManyToManyField(Sport)
 }}}

 Admin:
 {{{
 from django.contrib import admin
 from django.forms import ModelForm

 from .models import Sport, Profile

 class ProfileForm(ModelForm):
 def __init__(self, *args, **kwargs):
 super(ProfileForm, self).__init__(*args, **kwargs)

 choices = {}
 for sport in Sport.objects.all():
 choices.setdefault(sport.group, []).append(sport)
 self.fields['sports'].choices = choices.items()

 class ProfileAdmin(admin.ModelAdmin):
 form = ProfileForm
 filter_horizontal = ('sports',)

 class SportAdmin(admin.ModelAdmin):
 # currently is used only by response_add() but can be used by
 changelist_view() too
 list_grouping = 'group'


 admin.site.register(Profile, ProfileAdmin)
 admin.site.register(Sport, SportAdmin)
 }}}

 The ModelAdmin passes 'group' to RelatedObjectLookups.js, which passes it
 to SelectBox.js, which properly handles it.

-- 
Ticket URL: 
Django 
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To post to this group, send email to django-upda...@googlegroups.com.
To unsubscribe from this group, send email to 
django-updates+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/django-updates?hl=en.



[Changeset] r15165 - django/branches/releases/1.2.X/tests/regressiontests/fixtures_regress

2011-01-08 Thread noreply
Author: lukeplant
Date: 2011-01-08 10:13:58 -0600 (Sat, 08 Jan 2011)
New Revision: 15165

Modified:
   
django/branches/releases/1.2.X/tests/regressiontests/fixtures_regress/tests.py
Log:
[1.2.X] Fixed test failure when using Python 2.7

Backport of [14309] from trunk.

Fixed #14947

Modified: 
django/branches/releases/1.2.X/tests/regressiontests/fixtures_regress/tests.py
===
--- 
django/branches/releases/1.2.X/tests/regressiontests/fixtures_regress/tests.py  
2011-01-08 15:14:24 UTC (rev 15164)
+++ 
django/branches/releases/1.2.X/tests/regressiontests/fixtures_regress/tests.py  
2011-01-08 16:13:58 UTC (rev 15165)
@@ -1,6 +1,7 @@
 # -*- coding: utf-8 -*-
 # Unittests for fixtures.
 import os
+import re
 import sys
 try:
 from cStringIO import StringIO
@@ -327,9 +328,14 @@
 
 # Output order isn't guaranteed, so check for parts
 data = stdout.getvalue()
+
+# Get rid of artifacts like '2' to eliminate the differences
+# between different Python versions.
+data = re.sub('0{6,}\d', '', data)
+
 lion_json = '{"pk": 1, "model": "fixtures_regress.animal", "fields": 
{"count": 3, "weight": 1.2, "name": "Lion", "latin_name": "Panthera leo"}}'
 emu_json = '{"pk": 10, "model": "fixtures_regress.animal", "fields": 
{"count": 42, "weight": 1.2, "name": "Emu", "latin_name": "Dromaius 
novaehollandiae"}}'
-platypus_json = '{"pk": %d, "model": "fixtures_regress.animal", 
"fields": {"count": 2, "weight": 2.2002, "name": "Platypus", 
"latin_name": "Ornithorhynchus anatinus"}}'
+platypus_json = '{"pk": %d, "model": "fixtures_regress.animal", 
"fields": {"count": 2, "weight": 2.2, "name": "Platypus", "latin_name": 
"Ornithorhynchus anatinus"}}'
 platypus_json = platypus_json % animal.pk
 
 self.assertEqual(len(data), len('[%s]' % ', '.join([lion_json, 
emu_json, platypus_json])))

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To post to this group, send email to django-upda...@googlegroups.com.
To unsubscribe from this group, send email to 
django-updates+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/django-updates?hl=en.



Re: [Django] #15039: The current download link redirection breaks wget making Linux download inconvenient

2011-01-08 Thread Django
#15039: The current download link redirection breaks wget making Linux download
inconvenient
-+--
  Reporter:  jonathanberger  | Owner:  nobody
Status:  new | Milestone:
 Component:  Uncategorized   |   Version:  1.2   
Resolution:  |  Keywords:
 Stage:  Unreviewed  | Has_patch:  0 
Needs_docs:  0   |   Needs_tests:  0 
Needs_better_patch:  0   |  
-+--
Changes (by lukeplant):

  * needs_better_patch:  => 0
  * needs_tests:  => 0
  * needs_docs:  => 0

Comment:

 wget correctly follows the redirection and downloads the file.  The only
 problem is that it decides to call the file 'index.html', not
 'Django-1.2.4.tar.gz', which is what browsers seem to do.

 In theory it should be easy to fix, by adding a header like `Content-
 Disposition: attachment; filename=django-1.2.4.tar.gz`. However, I don't
 know how easy it will be to get lighttpd (which is serving
 media.djangoproject.com) to do this.

-- 
Ticket URL: 
Django 
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To post to this group, send email to django-upda...@googlegroups.com.
To unsubscribe from this group, send email to 
django-updates+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/django-updates?hl=en.



[Changeset] r15164 - django/branches/releases/1.2.X/django/core/serializers

2011-01-08 Thread noreply
Author: andrewgodwin
Date: 2011-01-08 09:14:24 -0600 (Sat, 08 Jan 2011)
New Revision: 15164

Modified:
   django/branches/releases/1.2.X/django/core/serializers/base.py
   django/branches/releases/1.2.X/django/core/serializers/json.py
   django/branches/releases/1.2.X/django/core/serializers/pyyaml.py
Log:
[1.2.X] Fixed #14888 -- Removing duplicated code in serialisers. Thanks to 
eric.fortin.

Backport of [15163] from trunk

Modified: django/branches/releases/1.2.X/django/core/serializers/base.py
===
--- django/branches/releases/1.2.X/django/core/serializers/base.py  
2011-01-08 15:07:45 UTC (rev 15163)
+++ django/branches/releases/1.2.X/django/core/serializers/base.py  
2011-01-08 15:14:24 UTC (rev 15164)
@@ -31,9 +31,9 @@
 """
 self.options = options
 
-self.stream = options.get("stream", StringIO())
-self.selected_fields = options.get("fields")
-self.use_natural_keys = options.get("use_natural_keys", False)
+self.stream = options.pop("stream", StringIO())
+self.selected_fields = options.pop("fields", None)
+self.use_natural_keys = options.pop("use_natural_keys", False)
 
 self.start_serialization()
 for obj in queryset:

Modified: django/branches/releases/1.2.X/django/core/serializers/json.py
===
--- django/branches/releases/1.2.X/django/core/serializers/json.py  
2011-01-08 15:07:45 UTC (rev 15163)
+++ django/branches/releases/1.2.X/django/core/serializers/json.py  
2011-01-08 15:14:24 UTC (rev 15164)
@@ -18,9 +18,6 @@
 internal_use_only = False
 
 def end_serialization(self):
-self.options.pop('stream', None)
-self.options.pop('fields', None)
-self.options.pop('use_natural_keys', None)
 simplejson.dump(self.objects, self.stream, cls=DjangoJSONEncoder, 
**self.options)
 
 def getvalue(self):

Modified: django/branches/releases/1.2.X/django/core/serializers/pyyaml.py
===
--- django/branches/releases/1.2.X/django/core/serializers/pyyaml.py
2011-01-08 15:07:45 UTC (rev 15163)
+++ django/branches/releases/1.2.X/django/core/serializers/pyyaml.py
2011-01-08 15:14:24 UTC (rev 15164)
@@ -38,9 +38,6 @@
 super(Serializer, self).handle_field(obj, field)
 
 def end_serialization(self):
-self.options.pop('stream', None)
-self.options.pop('fields', None)
-self.options.pop('use_natural_keys', None)
 yaml.dump(self.objects, self.stream, Dumper=DjangoSafeDumper, 
**self.options)
 
 def getvalue(self):

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To post to this group, send email to django-upda...@googlegroups.com.
To unsubscribe from this group, send email to 
django-updates+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/django-updates?hl=en.



[Changeset] r15163 - django/trunk/django/core/serializers

2011-01-08 Thread noreply
Author: andrewgodwin
Date: 2011-01-08 09:07:45 -0600 (Sat, 08 Jan 2011)
New Revision: 15163

Modified:
   django/trunk/django/core/serializers/base.py
   django/trunk/django/core/serializers/json.py
   django/trunk/django/core/serializers/pyyaml.py
Log:
Fixed #14888 -- Removing duplicated code in serialisers. Thanks to eric.fortin.

Modified: django/trunk/django/core/serializers/base.py
===
--- django/trunk/django/core/serializers/base.py2011-01-08 14:56:02 UTC 
(rev 15162)
+++ django/trunk/django/core/serializers/base.py2011-01-08 15:07:45 UTC 
(rev 15163)
@@ -31,9 +31,9 @@
 """
 self.options = options
 
-self.stream = options.get("stream", StringIO())
-self.selected_fields = options.get("fields")
-self.use_natural_keys = options.get("use_natural_keys", False)
+self.stream = options.pop("stream", StringIO())
+self.selected_fields = options.pop("fields", None)
+self.use_natural_keys = options.pop("use_natural_keys", False)
 
 self.start_serialization()
 for obj in queryset:

Modified: django/trunk/django/core/serializers/json.py
===
--- django/trunk/django/core/serializers/json.py2011-01-08 14:56:02 UTC 
(rev 15162)
+++ django/trunk/django/core/serializers/json.py2011-01-08 15:07:45 UTC 
(rev 15163)
@@ -18,9 +18,6 @@
 internal_use_only = False
 
 def end_serialization(self):
-self.options.pop('stream', None)
-self.options.pop('fields', None)
-self.options.pop('use_natural_keys', None)
 simplejson.dump(self.objects, self.stream, cls=DjangoJSONEncoder, 
**self.options)
 
 def getvalue(self):

Modified: django/trunk/django/core/serializers/pyyaml.py
===
--- django/trunk/django/core/serializers/pyyaml.py  2011-01-08 14:56:02 UTC 
(rev 15162)
+++ django/trunk/django/core/serializers/pyyaml.py  2011-01-08 15:07:45 UTC 
(rev 15163)
@@ -38,9 +38,6 @@
 super(Serializer, self).handle_field(obj, field)
 
 def end_serialization(self):
-self.options.pop('stream', None)
-self.options.pop('fields', None)
-self.options.pop('use_natural_keys', None)
 yaml.dump(self.objects, self.stream, Dumper=DjangoSafeDumper, 
**self.options)
 
 def getvalue(self):

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To post to this group, send email to django-upda...@googlegroups.com.
To unsubscribe from this group, send email to 
django-updates+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/django-updates?hl=en.



[Changeset] r15162 - django/branches/releases/1.2.X/django/views/decorators

2011-01-08 Thread noreply
Author: andrewgodwin
Date: 2011-01-08 08:56:02 -0600 (Sat, 08 Jan 2011)
New Revision: 15162

Modified:
   django/branches/releases/1.2.X/django/views/decorators/gzip.py
Log:
[1.2.X] Fixed #14929 -- Move gzip_page docstring to the right place. Thanks 
adamv.

Backport of [15161] from trunk

Modified: django/branches/releases/1.2.X/django/views/decorators/gzip.py
===
--- django/branches/releases/1.2.X/django/views/decorators/gzip.py  
2011-01-08 14:55:19 UTC (rev 15161)
+++ django/branches/releases/1.2.X/django/views/decorators/gzip.py  
2011-01-08 14:56:02 UTC (rev 15162)
@@ -1,6 +1,5 @@
-"Decorator for views that gzips pages if the client supports it."
-
 from django.utils.decorators import decorator_from_middleware
 from django.middleware.gzip import GZipMiddleware
 
 gzip_page = decorator_from_middleware(GZipMiddleware)
+gzip_page.__doc__ = "Decorator for views that gzips pages if the client 
supports it."

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To post to this group, send email to django-upda...@googlegroups.com.
To unsubscribe from this group, send email to 
django-updates+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/django-updates?hl=en.



[Changeset] r15161 - django/trunk/django/views/decorators

2011-01-08 Thread noreply
Author: andrewgodwin
Date: 2011-01-08 08:55:19 -0600 (Sat, 08 Jan 2011)
New Revision: 15161

Modified:
   django/trunk/django/views/decorators/gzip.py
Log:
Fixed #14929 -- Move gzip_page docstring to the right place. Thanks adamv.

Modified: django/trunk/django/views/decorators/gzip.py
===
--- django/trunk/django/views/decorators/gzip.py2011-01-08 14:53:44 UTC 
(rev 15160)
+++ django/trunk/django/views/decorators/gzip.py2011-01-08 14:55:19 UTC 
(rev 15161)
@@ -1,6 +1,5 @@
-"Decorator for views that gzips pages if the client supports it."
-
 from django.utils.decorators import decorator_from_middleware
 from django.middleware.gzip import GZipMiddleware
 
 gzip_page = decorator_from_middleware(GZipMiddleware)
+gzip_page.__doc__ = "Decorator for views that gzips pages if the client 
supports it."

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To post to this group, send email to django-upda...@googlegroups.com.
To unsubscribe from this group, send email to 
django-updates+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/django-updates?hl=en.



[Changeset] r15160 - django/trunk/django/views/generic

2011-01-08 Thread noreply
Author: andrewgodwin
Date: 2011-01-08 08:53:44 -0600 (Sat, 08 Jan 2011)
New Revision: 15160

Modified:
   django/trunk/django/views/generic/__init__.py
Log:
Fixed #14995 -- Add FormView import to generic views __init__. Thanks carbonXT.

Modified: django/trunk/django/views/generic/__init__.py
===
--- django/trunk/django/views/generic/__init__.py   2011-01-08 14:50:31 UTC 
(rev 15159)
+++ django/trunk/django/views/generic/__init__.py   2011-01-08 14:53:44 UTC 
(rev 15160)
@@ -3,7 +3,7 @@
  WeekArchiveView, DayArchiveView, 
TodayArchiveView,
  DateDetailView)
 from django.views.generic.detail import DetailView
-from django.views.generic.edit import CreateView, UpdateView, DeleteView
+from django.views.generic.edit import FormView, CreateView, UpdateView, 
DeleteView
 from django.views.generic.list import ListView
 
 

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To post to this group, send email to django-upda...@googlegroups.com.
To unsubscribe from this group, send email to 
django-updates+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/django-updates?hl=en.



[Changeset] r15159 - django/branches/releases/1.2.X/tests/regressiontests/forms/tests

2011-01-08 Thread noreply
Author: andrewgodwin
Date: 2011-01-08 08:50:31 -0600 (Sat, 08 Jan 2011)
New Revision: 15159

Modified:
   django/branches/releases/1.2.X/tests/regressiontests/forms/tests/formsets.py
Log:
Fixed #12295 -- Issue had already been fixed, but added test. Thanks 
tomevans222 and dpn.

Modified: 
django/branches/releases/1.2.X/tests/regressiontests/forms/tests/formsets.py
===
--- 
django/branches/releases/1.2.X/tests/regressiontests/forms/tests/formsets.py
2011-01-08 14:37:26 UTC (rev 15158)
+++ 
django/branches/releases/1.2.X/tests/regressiontests/forms/tests/formsets.py
2011-01-08 14:50:31 UTC (rev 15159)
@@ -29,6 +29,11 @@
 seen_drinks.append(drink['name'])
 
 
+class EmptyFsetWontValidate(BaseFormSet):
+def clean(self):
+raise ValidationError("Clean method called")
+
+
 # Let's define a FormSet that takes a list of favorite drinks, but raises an
 # error if there are any duplicates. Used in ``test_clean_hook``,
 # ``test_regression_6926`` & ``test_regression_12878``.
@@ -761,3 +766,13 @@
 formset = FavoriteDrinksFormSet(data, prefix='drinks')
 self.assertFalse(formset.is_valid())
 self.assertEqual(formset.non_form_errors(), [u'You may only specify a 
drink once.'])
+
+class TestEmptyFormSet(TestCase): 
+"Test that an empty formset still calls clean()"
+def test_empty_formset_is_valid(self): 
+EmptyFsetWontValidateFormset = formset_factory(FavoriteDrinkForm, 
extra=0, formset=EmptyFsetWontValidate) 
+formset = EmptyFsetWontValidateFormset(data={'form-INITIAL_FORMS':'0', 
'form-TOTAL_FORMS':'0'},prefix="form") 
+formset2 = 
EmptyFsetWontValidateFormset(data={'form-INITIAL_FORMS':'0', 
'form-TOTAL_FORMS':'1', 'form-0-name':'bah' },prefix="form") 
+self.assertFalse(formset.is_valid()) 
+self.assertFalse(formset2.is_valid())
+

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To post to this group, send email to django-upda...@googlegroups.com.
To unsubscribe from this group, send email to 
django-updates+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/django-updates?hl=en.



[Changeset] r15158 - django/trunk/tests/regressiontests/forms/tests

2011-01-08 Thread noreply
Author: andrewgodwin
Date: 2011-01-08 08:37:26 -0600 (Sat, 08 Jan 2011)
New Revision: 15158

Modified:
   django/trunk/tests/regressiontests/forms/tests/formsets.py
Log:
Fixed #12295 -- Issue had already been fixed, but added test. Thanks 
tomevans222 and dpn.

Modified: django/trunk/tests/regressiontests/forms/tests/formsets.py
===
--- django/trunk/tests/regressiontests/forms/tests/formsets.py  2011-01-08 
13:40:23 UTC (rev 15157)
+++ django/trunk/tests/regressiontests/forms/tests/formsets.py  2011-01-08 
14:37:26 UTC (rev 15158)
@@ -29,6 +29,11 @@
 seen_drinks.append(drink['name'])
 
 
+class EmptyFsetWontValidate(BaseFormSet):
+def clean(self):
+raise ValidationError("Clean method called")
+
+
 # Let's define a FormSet that takes a list of favorite drinks, but raises an
 # error if there are any duplicates. Used in ``test_clean_hook``,
 # ``test_regression_6926`` & ``test_regression_12878``.
@@ -872,3 +877,13 @@
 formset = ArticleFormSet(data)
 self.assertFalse(formset.is_valid())
 self.assertEquals([{}, {'pub_date': [u'This field is required.']}], 
formset.errors)
+
+class TestEmptyFormSet(TestCase): 
+"Test that an empty formset still calls clean()"
+def test_empty_formset_is_valid(self): 
+EmptyFsetWontValidateFormset = formset_factory(FavoriteDrinkForm, 
extra=0, formset=EmptyFsetWontValidate) 
+formset = EmptyFsetWontValidateFormset(data={'form-INITIAL_FORMS':'0', 
'form-TOTAL_FORMS':'0'},prefix="form") 
+formset2 = 
EmptyFsetWontValidateFormset(data={'form-INITIAL_FORMS':'0', 
'form-TOTAL_FORMS':'1', 'form-0-name':'bah' },prefix="form") 
+self.assertFalse(formset.is_valid()) 
+self.assertFalse(formset2.is_valid()) 
+

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To post to this group, send email to django-upda...@googlegroups.com.
To unsubscribe from this group, send email to 
django-updates+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/django-updates?hl=en.



[Changeset] r15157 - in django/branches/releases/1.2.X: django/db/models tests/regressiontests/get_or_create_regress

2011-01-08 Thread noreply
Author: andrewgodwin
Date: 2011-01-08 07:40:23 -0600 (Sat, 08 Jan 2011)
New Revision: 15157

Modified:
   django/branches/releases/1.2.X/django/db/models/query.py
   
django/branches/releases/1.2.X/tests/regressiontests/get_or_create_regress/tests.py
Log:
[1.2.X] Fixed #9029 -- Allow use of fieldname_id with get_or_create. Thanks to 
aaron and mrmachine.

Backport of [15156] from trunk

Modified: django/branches/releases/1.2.X/django/db/models/query.py
===
--- django/branches/releases/1.2.X/django/db/models/query.py2011-01-08 
13:27:30 UTC (rev 15156)
+++ django/branches/releases/1.2.X/django/db/models/query.py2011-01-08 
13:40:23 UTC (rev 15157)
@@ -367,9 +367,13 @@
 assert kwargs, \
 'get_or_create() must be passed at least one keyword argument'
 defaults = kwargs.pop('defaults', {})
+lookup = kwargs.copy()
+for f in self.model._meta.fields:
+if f.column in lookup:
+lookup[f.name] = lookup.pop(f.column)
 try:
 self._for_write = True
-return self.get(**kwargs), False
+return self.get(**lookup), False
 except self.model.DoesNotExist:
 try:
 params = dict([(k, v) for k, v in kwargs.items() if '__' not 
in k])
@@ -382,7 +386,7 @@
 except IntegrityError, e:
 transaction.savepoint_rollback(sid, using=self.db)
 try:
-return self.get(**kwargs), False
+return self.get(**lookup), False
 except self.model.DoesNotExist:
 raise e
 

Modified: 
django/branches/releases/1.2.X/tests/regressiontests/get_or_create_regress/tests.py
===
--- 
django/branches/releases/1.2.X/tests/regressiontests/get_or_create_regress/tests.py
 2011-01-08 13:27:30 UTC (rev 15156)
+++ 
django/branches/releases/1.2.X/tests/regressiontests/get_or_create_regress/tests.py
 2011-01-08 13:40:23 UTC (rev 15157)
@@ -21,7 +21,7 @@
 # Add an author to the book.
 ed, created = book.authors.get_or_create(name="Ed")
 self.assertTrue(created)
-# Book should have one author.
+# The book should have one author.
 self.assertEqual(book.authors.count(), 1)
 
 # Try get_or_create again, this time nothing should be created.
@@ -51,3 +51,12 @@
 # Now Ed has two Books, Fred just one.
 self.assertEqual(ed.books.count(), 2)
 self.assertEqual(fred.books.count(), 1)
+
+# Use the publisher's primary key value instead of a model instance.
+_, created = ed.books.get_or_create(name='The Great Book of Ed', 
publisher_id=p.id)
+self.assertTrue(created)
+# Try get_or_create again, this time nothing should be created.
+_, created = ed.books.get_or_create(name='The Great Book of Ed', 
publisher_id=p.id)
+self.assertFalse(created)
+# The publisher should have three books.
+self.assertEqual(p.books.count(), 3)

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To post to this group, send email to django-upda...@googlegroups.com.
To unsubscribe from this group, send email to 
django-updates+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/django-updates?hl=en.



[Changeset] r15156 - in django/trunk: django/db/models tests/regressiontests/get_or_create_regress

2011-01-08 Thread noreply
Author: andrewgodwin
Date: 2011-01-08 07:27:30 -0600 (Sat, 08 Jan 2011)
New Revision: 15156

Modified:
   django/trunk/django/db/models/query.py
   django/trunk/tests/regressiontests/get_or_create_regress/tests.py
Log:
Fixed #9029 -- Allow use of fieldname_id with get_or_create. Thanks to aaron 
and mrmachine.

Modified: django/trunk/django/db/models/query.py
===
--- django/trunk/django/db/models/query.py  2011-01-08 13:15:44 UTC (rev 
15155)
+++ django/trunk/django/db/models/query.py  2011-01-08 13:27:30 UTC (rev 
15156)
@@ -369,9 +369,13 @@
 assert kwargs, \
 'get_or_create() must be passed at least one keyword argument'
 defaults = kwargs.pop('defaults', {})
+lookup = kwargs.copy()
+for f in self.model._meta.fields:
+if f.column in lookup:
+lookup[f.name] = lookup.pop(f.column)
 try:
 self._for_write = True
-return self.get(**kwargs), False
+return self.get(**lookup), False
 except self.model.DoesNotExist:
 try:
 params = dict([(k, v) for k, v in kwargs.items() if '__' not 
in k])
@@ -384,7 +388,7 @@
 except IntegrityError, e:
 transaction.savepoint_rollback(sid, using=self.db)
 try:
-return self.get(**kwargs), False
+return self.get(**lookup), False
 except self.model.DoesNotExist:
 raise e
 

Modified: django/trunk/tests/regressiontests/get_or_create_regress/tests.py
===
--- django/trunk/tests/regressiontests/get_or_create_regress/tests.py   
2011-01-08 13:15:44 UTC (rev 15155)
+++ django/trunk/tests/regressiontests/get_or_create_regress/tests.py   
2011-01-08 13:27:30 UTC (rev 15156)
@@ -21,7 +21,7 @@
 # Add an author to the book.
 ed, created = book.authors.get_or_create(name="Ed")
 self.assertTrue(created)
-# Book should have one author.
+# The book should have one author.
 self.assertEqual(book.authors.count(), 1)
 
 # Try get_or_create again, this time nothing should be created.
@@ -51,3 +51,12 @@
 # Now Ed has two Books, Fred just one.
 self.assertEqual(ed.books.count(), 2)
 self.assertEqual(fred.books.count(), 1)
+
+# Use the publisher's primary key value instead of a model instance.
+_, created = ed.books.get_or_create(name='The Great Book of Ed', 
publisher_id=p.id)
+self.assertTrue(created)
+# Try get_or_create again, this time nothing should be created.
+_, created = ed.books.get_or_create(name='The Great Book of Ed', 
publisher_id=p.id)
+self.assertFalse(created)
+# The publisher should have three books.
+self.assertEqual(p.books.count(), 3)

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To post to this group, send email to django-upda...@googlegroups.com.
To unsubscribe from this group, send email to 
django-updates+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/django-updates?hl=en.



[Changeset] r15155 - in django/trunk: django/views/generic tests/regressiontests/generic_views

2011-01-08 Thread noreply
Author: andrewgodwin
Date: 2011-01-08 07:15:44 -0600 (Sat, 08 Jan 2011)
New Revision: 15155

Modified:
   django/trunk/django/views/generic/list.py
   django/trunk/tests/regressiontests/generic_views/list.py
Log:
Fixed inconsistency in ListView's pagination (short datasets should also 
trigger a pagination, but with a single possible page)

Modified: django/trunk/django/views/generic/list.py
===
--- django/trunk/django/views/generic/list.py   2011-01-08 10:03:27 UTC (rev 
15154)
+++ django/trunk/django/views/generic/list.py   2011-01-08 13:15:44 UTC (rev 
15155)
@@ -36,22 +36,19 @@
 Paginate the queryset, if needed.
 """
 paginator = self.get_paginator(queryset, page_size, 
allow_empty_first_page=self.get_allow_empty())
-if paginator.num_pages > 1:
-page = self.kwargs.get('page') or self.request.GET.get('page') or 1
-try:
-page_number = int(page)
-except ValueError:
-if page == 'last':
-page_number = paginator.num_pages
-else:
-raise Http404("Page is not 'last', nor can it be converted 
to an int.")
-try:
-page = paginator.page(page_number)
-return (paginator, page, page.object_list, True)
-except InvalidPage:
-raise Http404(u'Invalid page (%s)' % page_number)
-else:
-return (None, None, queryset, False)
+page = self.kwargs.get('page') or self.request.GET.get('page') or 1
+try:
+page_number = int(page)
+except ValueError:
+if page == 'last':
+page_number = paginator.num_pages
+else:
+raise Http404("Page is not 'last', nor can it be converted to 
an int.")
+try:
+page = paginator.page(page_number)
+return (paginator, page, page.object_list, True)
+except InvalidPage:
+raise Http404(u'Invalid page (%s)' % page_number)
 
 def get_paginate_by(self, queryset):
 """

Modified: django/trunk/tests/regressiontests/generic_views/list.py
===
--- django/trunk/tests/regressiontests/generic_views/list.py2011-01-08 
10:03:27 UTC (rev 15154)
+++ django/trunk/tests/regressiontests/generic_views/list.py2011-01-08 
13:15:44 UTC (rev 15155)
@@ -38,14 +38,15 @@
 self.assertEqual(list(res.context['authors'])[-1].name, 'Author 29')
 
 def test_paginated_queryset_shortdata(self):
+# Test that short datasets ALSO result in a paginated view.
 res = self.client.get('/list/authors/paginated/')
 self.assertEqual(res.status_code, 200)
 self.assertTemplateUsed(res, 'generic_views/author_list.html')
 self.assertEqual(list(res.context['object_list']), 
list(Author.objects.all()))
 self.assertIs(res.context['authors'], res.context['object_list'])
-self.assertIsNone(res.context['paginator'])
-self.assertIsNone(res.context['page_obj'])
-self.assertFalse(res.context['is_paginated'])
+self.assertEqual(res.context['page_obj'].number, 1)
+self.assertEqual(res.context['paginator'].num_pages, 1)
+self.assertTrue(res.context['is_paginated'])
 
 def test_paginated_get_page_by_query_string(self):
 self._make_authors(100)
@@ -90,7 +91,7 @@
 self._make_authors(7)
 res = self.client.get('/list/authors/paginated/custom_class/')
 self.assertEqual(res.status_code, 200)
-self.assertIsNone(res.context['paginator'])
+self.assertEqual(res.context['paginator'].num_pages, 1)
 # Custom pagination allows for 2 orphans on a page size of 5
 self.assertEqual(len(res.context['object_list']), 7)
 

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To post to this group, send email to django-upda...@googlegroups.com.
To unsubscribe from this group, send email to 
django-updates+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/django-updates?hl=en.



[Changeset] r15154 - in django/trunk: django/contrib/staticfiles/management/commands tests/regressiontests/staticfiles_tests

2011-01-08 Thread noreply
Author: jezdez
Date: 2011-01-08 04:03:27 -0600 (Sat, 08 Jan 2011)
New Revision: 15154

Added:
   django/trunk/tests/regressiontests/staticfiles_tests/storage.py
Modified:
   django/trunk/django/contrib/staticfiles/management/commands/collectstatic.py
   django/trunk/tests/regressiontests/staticfiles_tests/tests.py
Log:
Fixed #15035 -- Fixed collectstatic management command to work with non-local 
storage backends correctly. Also refactored a bit code smell.

Modified: 
django/trunk/django/contrib/staticfiles/management/commands/collectstatic.py
===
--- 
django/trunk/django/contrib/staticfiles/management/commands/collectstatic.py
2011-01-05 22:41:43 UTC (rev 15153)
+++ 
django/trunk/django/contrib/staticfiles/management/commands/collectstatic.py
2011-01-08 10:03:27 UTC (rev 15154)
@@ -32,24 +32,28 @@
 )
 help = "Collect static files from apps and other locations in a single 
location."
 
-def handle_noargs(self, **options):
-symlink = options['link']
-ignore_patterns = options['ignore_patterns']
-if options['use_default_ignore_patterns']:
-ignore_patterns += ['CVS', '.*', '*~']
-ignore_patterns = list(set(ignore_patterns))
+def __init__(self, *args, **kwargs):
 self.copied_files = set()
 self.symlinked_files = set()
 self.unmodified_files = set()
 self.destination_storage = 
get_storage_class(settings.STATICFILES_STORAGE)()
-
 try:
 self.destination_storage.path('')
 except NotImplementedError:
 self.destination_local = False
 else:
 self.destination_local = True
+# Use ints for file times (ticket #14665)
+os.stat_float_times(False)
 
+def handle_noargs(self, **options):
+symlink = options['link']
+ignore_patterns = options['ignore_patterns']
+if options['use_default_ignore_patterns']:
+ignore_patterns += ['CVS', '.*', '*~']
+ignore_patterns = list(set(ignore_patterns))
+self.verbosity = int(options.get('verbosity', 1))
+
 if symlink:
 if sys.platform == 'win32':
 raise CommandError("Symlinking is not supported by this "
@@ -70,17 +74,13 @@
 if confirm != 'yes':
 raise CommandError("Collecting static files cancelled.")
 
-# Use ints for file times (ticket #14665)
-os.stat_float_times(False)
-
 for finder in finders.get_finders():
 for source, prefix, storage in finder.list(ignore_patterns):
 self.copy_file(source, prefix, storage, **options)
 
-verbosity = int(options.get('verbosity', 1))
 actual_count = len(self.copied_files) + len(self.symlinked_files)
 unmodified_count = len(self.unmodified_files)
-if verbosity >= 1:
+if self.verbosity >= 1:
 self.stdout.write("\n%s static file%s %s to '%s'%s.\n"
   % (actual_count, actual_count != 1 and 's' or '',
  symlink and 'symlinked' or 'copied',
@@ -88,6 +88,15 @@
  unmodified_count and ' (%s unmodified)'
  % unmodified_count or ''))
 
+def log(self, msg, level=2):
+"""
+Small log helper
+"""
+if not msg.endswith("\n"):
+msg += "\n"
+if self.verbosity >= level:
+self.stdout.write(msg)
+
 def copy_file(self, source, prefix, source_storage, **options):
 """
 Attempt to copy (or symlink) ``source`` to ``destination``,
@@ -104,18 +113,13 @@
 destination = source
 symlink = options['link']
 dry_run = options['dry_run']
-verbosity = int(options.get('verbosity', 1))
 
 if destination in self.copied_files:
-if verbosity >= 2:
-self.stdout.write("Skipping '%s' (already copied earlier)\n"
-  % destination)
+self.log("Skipping '%s' (already copied earlier)" % destination)
 return False
 
 if destination in self.symlinked_files:
-if verbosity >= 2:
-self.stdout.write("Skipping '%s' (already linked earlier)\n"
-  % destination)
+self.log("Skipping '%s' (already linked earlier)" % destination)
 return False
 
 if self.destination_storage.exists(destination):
@@ -126,34 +130,27 @@
 # storage doesn't support ``modified_time`` or failed.
 pass
 else:
-destination_is_link = os.path.islink(
-self.destination_storage.path(destination))
+destination_is_link = (self.destination_local and
+os.path.islink(self.destination_storage.path(destination)))
 if destinati