Ticket #5490: urlquote_string_primarekey_with_tests.diff

File urlquote_string_primarekey_with_tests.diff, 10.1 KB (added by Remco Wendt, 16 years ago)

Updated patch and added unit tests

  • django/contrib/admin/options.py

     
    1515from django.utils.text import capfirst, get_text_list
    1616from django.utils.translation import ugettext as _
    1717from django.utils.encoding import force_unicode
     18from django.utils.http import urlquote, URL_SAFE_CHARACTERS
    1819import sets
    1920
    2021HORIZONTAL, VERTICAL = 1, 2
     
    680681
    681682        # Populate deleted_objects, a data structure of all related objects that
    682683        # will also be deleted.
    683         deleted_objects = [mark_safe(u'%s: <a href="../../%s/">%s</a>' % (escape(force_unicode(capfirst(opts.verbose_name))), force_unicode(object_id), escape(obj))), []]
     684        deleted_objects = [mark_safe(u'%s: <a href="../../%s/">%s</a>' % (escape(force_unicode(capfirst(opts.verbose_name))), urlquote(object_id, safe=URL_SAFE_CHARACTERS), escape(obj))), []]
    684685        perms_needed = sets.Set()
    685686        get_deleted_objects(deleted_objects, perms_needed, request.user, obj, opts, 1, self.admin_site)
    686687
  • django/contrib/admin/models.py

     
    44from django.utils.translation import ugettext_lazy as _
    55from django.utils.encoding import smart_unicode
    66from django.utils.safestring import mark_safe
     7from django.utils.http import urlquote, URL_SAFE_CHARACTERS
    78
    89ADDITION = 1
    910CHANGE = 2
     
    5051        Returns the admin URL to edit the object represented by this log entry.
    5152        This is relative to the Django admin index page.
    5253        """
    53         return mark_safe(u"%s/%s/%s/" % (self.content_type.app_label, self.content_type.model, self.object_id))
     54        return mark_safe(u"%s/%s/%s/" % (self.content_type.app_label, self.content_type.model, urlquote(self.object_id, safe=URL_SAFE_CHARACTERS)))
  • django/contrib/admin/views/main.py

     
    66from django.utils.encoding import force_unicode, smart_str
    77from django.utils.translation import ugettext
    88from django.utils.safestring import mark_safe
    9 from django.utils.http import urlencode
     9from django.utils.http import urlencode, urlquote, URL_SAFE_CHARACTERS
    1010import operator
    1111
    1212try:
     
    246246        return qs
    247247
    248248    def url_for_result(self, result):
    249         return "%s/" % quote(getattr(result, self.pk_attname))
     249        return "%s/" % urlquote(getattr(result, self.pk_attname), safe=URL_SAFE_CHARACTERS)
  • django/contrib/admin/templates/admin/index.html

     
    5959            {% else %}
    6060            <ul class="actionlist">
    6161            {% for entry in admin_log %}
    62             <li class="{% if entry.is_addition %}addlink{% endif %}{% if entry.is_change %}changelink{% endif %}{% if entry.is_deletion %}deletelink{% endif %}">{% if not entry.is_deletion %}<a href="{{ entry.get_admin_url }}">{% endif %}{{ entry.object_repr|escape }}{% if not entry.is_deletion %}</a>{% endif %}<br /><span class="mini quiet">{% filter capfirst %}{% trans entry.content_type.name %}{% endfilter %}</span></li>
     62            <li class="{% if entry.is_addition %}addlink{% endif %}{% if entry.is_change %}changelink{% endif %}{% if entry.is_deletion %}deletelink{% endif %}">{% if not entry.is_deletion %}<a href="{{ entry.get_admin_url }}">{% endif %}{{ entry.object_repr }}{% if not entry.is_deletion %}</a>{% endif %}<br /><span class="mini quiet">{% filter capfirst %}{% trans entry.content_type.name %}{% endfilter %}</span></li>
    6363            {% endfor %}
    6464            </ul>
    6565            {% endif %}
  • django/utils/http.py

     
    44from django.utils.encoding import smart_str, force_unicode
    55from django.utils.functional import allow_lazy
    66
     7# These are the safe characters as defined by:
     8# http://www.ietf.org/rfc/rfc2396.txt (see: 2.3. Unreserved Characters)
     9# these characters are safe to be used in a URL part.
     10URL_SAFE_CHARACTERS = "-_.!~*'()"
     11
    712def urlquote(url, safe='/'):
    813    """
    914    A version of Python's urllib.quote() function that can operate on unicode
  • tests/regressiontests/admin_views/fixtures/string-primary-key.xml

     
     1<?xml version="1.0" encoding="utf-8"?>
     2<django-objects version="1.0">
     3    <object pk="1" model="admin_views.modelwithstringprimarykey">
     4        <field type="CharField" name="id"><![CDATA[abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ 1234567890 -_.!~*'() ;/?:@&=+$, <>#%" {}|\^[]`]]></field>
     5    </object>   
     6</django-objects>
     7 No newline at end of file
  • tests/regressiontests/admin_views/tests.py

     
    22from django.test import TestCase
    33from django.contrib.auth.models import User, Permission
    44from django.contrib.contenttypes.models import ContentType
     5from django.contrib.admin.models import LogEntry
    56from django.contrib.admin.sites import LOGIN_FORM_KEY, _encode_post_data
    67
    78# local test models
    8 from models import Article, CustomArticle, Section
     9from models import Article, CustomArticle, Section, ModelWithStringPrimaryKey
    910
    1011def get_perm(Model, perm):
    1112    """Return the permission object, for the Model"""
     
    320321        self.assertRedirects(post, '/test_admin/admin/')
    321322        self.failUnlessEqual(Article.objects.all().count(), 0)
    322323        self.client.get('/test_admin/admin/logout/')
    323        
    324  No newline at end of file
     324       
     325class AdminViewStringPrimaryKeyTest(TestCase):
     326    fixtures = ['admin-views-users.xml', 'string-primary-key.xml']
     327   
     328    def __init__(self, *args):
     329        super(AdminViewStringPrimaryKeyTest, self).__init__(*args)
     330       
     331        # The primary key value used is just a string containing all possible characters
     332        self.pk = """abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ 1234567890 -_.!~*'() ;/?:@&=+$, <>#%" {}|\^[]`"""
     333
     334        self.pk_escaped = """abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ 1234567890 -_.!~*&#39;() ;/?:@&amp;=+$, &lt;&gt;#%&quot; {}|\^[]`"""
     335       
     336        # The characters that should be quoted are defined in:
     337        # These are the safe characters as defined by:
     338        # http://www.ietf.org/rfc/rfc2396.txt (see chapter 2)
     339        # The safe characters are defined in django.util.http.URL_SAFE_CHARACTERS
     340        self.pk_quoted = """abcdefghijklmnopqrstuvwxyz%20ABCDEFGHIJKLMNOPQRSTUVWXYZ%201234567890%20-_.!~*'()%20%3B%2F%3F%3A%40%26%3D%2B%24%2C%20%3C%3E%23%25%22%20%7B%7D%7C%5C%5E%5B%5D%60"""
     341   
     342    def setUp(self):
     343        self.client.login(username='super', password='secret')
     344       
     345        # This entry refers to content type which is not known at the moment the fixture is imported
     346        content_type_id = ContentType.objects.get_for_model(ModelWithStringPrimaryKey).id
     347        ContentType.objects.all()
     348       
     349        LogEntry.objects.log_action(100, content_type_id, self.pk, self.pk, 2, change_message='')
     350   
     351    def tearDown(self):
     352        self.client.logout()
     353   
     354    def test_get_change_view(self):
     355        "Retrieving the object using urlencoded form of primary key should work"       
     356        response = self.client.get('/test_admin/admin/admin_views/modelwithstringprimarykey/%s/' % self.pk_quoted)
     357
     358        self.assertContains(response, self.pk_escaped)
     359   
     360    def test_changelist_to_changeform_link(self):
     361        "The link from the changelist referring to the changeform of the object should be quoted"
     362        response = self.client.get('/test_admin/admin/admin_views/modelwithstringprimarykey/')
     363       
     364        should_contain = """<tr class="row1"><th><a href="%s/">%s</a></th></tr>""" % (self.pk_quoted, self.pk_escaped)
     365        self.assertContains(response, should_contain)
     366   
     367    def test_recentactions_link(self):
     368        "The link from the recent actions list referring to the changeform of the object should be quoted"
     369        response = self.client.get('/test_admin/admin/')
     370       
     371        should_contain = """<a href="admin_views/modelwithstringprimarykey/%s/">%s</a>""" % (self.pk_quoted, self.pk_escaped)
     372        self.assertContains(response, should_contain)
     373   
     374    def test_deleteconfirmation_link(self):
     375        "The link from the delete confirmation page referring back to the changeform of the object should be quoted"
     376        response = self.client.get('/test_admin/admin/admin_views/modelwithstringprimarykey/%s/delete/' % self.pk_quoted)
     377
     378        should_contain = """<a href="../../%s/">%s</a>""" % (self.pk_quoted, self.pk_escaped)       
     379        self.assertContains(response, should_contain)
     380   
     381 No newline at end of file
  • tests/regressiontests/admin_views/models.py

     
    4848                'extra_var': 'Hello!'
    4949            }
    5050        )
    51        
     51
     52class ModelWithStringPrimaryKey(models.Model):
     53    id = models.CharField(max_length='255', primary_key=True)
     54   
     55    def __unicode__(self):
     56        return self.id
     57
    5258admin.site.register(Article, ArticleAdmin)
    5359admin.site.register(CustomArticle, CustomArticleAdmin)
    5460admin.site.register(Section)
     61admin.site.register(ModelWithStringPrimaryKey)
Back to Top