#29839: Make leading character in quote/unquote in contrib.admin.utils
configurable
-------------------------------------+-------------------------------------
Reporter: ckz8780 | Owner: nobody
Type: New | Status: new
feature |
Component: | Version: 2.1
contrib.admin |
Severity: Normal | Keywords: admin quote unquote
Triage Stage: | Has patch: 0
Unreviewed |
Needs documentation: 0 | Needs tests: 0
Patch needs improvement: 0 | Easy pickings: 0
UI/UX: 0 |
-------------------------------------+-------------------------------------
= **The problem:**
The current leading character in the {{{contrib.admin.utils}}}
{{{quote()}}} and {{{unquote()}}} functions (an underscore) causes some
characters to be improperly escaped/unescaped if primary keys contain an
underscore. This character could be configurable through a setting in
{{{settings.py}}}, so that users who have underscores in text-based
primary keys can change it. If there is a primary key with an underscore
in it, for example, changing the leading character in the quote/unquote
functions to a dot ({{{.}}}) will fix edit links in the django admin.
= **The current (django 2.1.1) functions, with suggested changes:**
{{{
def quote(s):
"""
Ensure that primary key values do not confuse the admin URLs by
escaping
any '/', '_' and ':' and similarly problematic characters.
Similar to urllib.parse.quote(), except that the quoting is slightly
different so that it doesn't get automatically unquoted by the Web
browser.
"""
if not isinstance(s, str):
return s
res = list(s)
for i in range(len(res)):
c = res[i]
if c in """:/_#?;@&=+$,"[]<>%\n\\""":
res[i] = '_%02X' % ord(c) # Make this underscore a
configurable character
return ''.join(res)
def unquote(s):
"""Undo the effects of quote(). Based heavily on
urllib.parse.unquote()."""
mychr = chr
myatoi = int
list = s.split('_') # Make this underscore a configurable character
res = [list[0]]
myappend = res.append
del list[0]
for item in list:
if item[1:2]:
try:
myappend(mychr(myatoi(item[:2], 16)) + item[2:])
except ValueError:
myappend('_' + item) # Make this underscore a configurable
character
else:
myappend('_' + item) # Make this underscore a configurable
character
return "".join(res)
}}}
= **A couple example models:**
{{{
from django.db import models
from django.contrib.auth.models import User
# CUSTOMERS:
class Customer(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
customer_id = models.CharField(max_length=100, primary_key=True)
def __str__(self):
return self.customer_id
# SUBSCRIPTIONS:
class Subscription(models.Model):
subscription_id = models.CharField(max_length=100, primary_key=True)
customer_id = models.ForeignKey('Customer', db_column='customer_id',
on_delete=models.CASCADE)
def __str__(self):
return self.subscription_id
}}}
= **Steps to reproduce the issue:**
1. Create the above models.
2. Create a {{{Customer}}} object with a primary key of
{{{cus_C2testing}}}
3. Create a Subscription object with a primary key of {{{sub_C2testing}}}
and a ForeignKey back to the object created in step 1
4. Navigate to the django admin and click the Subscription object you
created. **Notice that the underscore in the primary key has been replaced
with {{{_5F}}} in the URL**
5. Click the edit customer icon (the small pencil next to the dropdown
containing your customer object) and notice that the popup displays
{{{Customer with ID "cusÂtesting" doesn't exist. Perhaps it was
deleted?}}}. The C2 has been replaced with its unicode codepoint, Â. I
believe this is due to the fact that the unquote function splits the ID at
the underscore, but regardless of the cause, **replacing the underscore in
the quote/unquote functions at the locations in the code above with a dot
({{{.}}}) resolves the issue.**
= **The suggestion:**
My suggestion is that we make this configurable, so that the quote/unquote
functions use an underscore by default, but take a second argument of a
leading character if desired. It would ideally be configurable via
settings.py in a variable like {{{ADMIN_QUOTE_UNQUOTE_LEADCHAR}}}. This
will give users the flexibility to use primary keys with underscores,
which are likely to be much more common than keys with dots.
--
Ticket URL: <https://code.djangoproject.com/ticket/29839>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
--
You received this message because you are subscribed to the Google Groups
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/django-updates/050.75f5ac11e090c0360d4fc0aaa783b2a7%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.