views:

1645

answers:

3

Hi stack overflow,

I guess this is a really novice question, still I'm having trouble with django templates and CharField models.

So I have a model with a CharField that creates a slug that replaces spaces with underscores. If I create an object Somename Somesurname this creates slug Somename_Somesurname and gets displayed as expected on the template.

However, if I create an object Somename Somesurname (notice the second space), slug Somename__Somesurname is created, and although on django console I see this as <Object: Somename Somesurname>, on the template it is displayed as Somename Somesurname.

So django templates strips somehow spaces? Is there a filter I can use to get the name with it's spaces?

Thank you for your time!

+6  A: 

Django sees the object internally as having two spaces (judging by the two underscores and two spaces in the repr output). The fact that it only shows up with one space in the template is just how HTML works. Notice how, in the question you just asked, most of the places where you entered two spaces, only one is showing up?

From the HTML4 Spec:

In particular, user agents should collapse input white space sequences when producing output inter-word space.

As S.Lott suggested, you can verify that my guess is correct by adding debug logging, or using the Firebug plugin for Firefox or something similar, to see exactly what's getting sent to the browser. Then you'll know for sure on which end the problem lies.

If multiple spaces are really important to you, you'll need to use the &nbsp; entity, though I don't know offhand how you'd get Django to encode the output of that specific object using them.

DNS
+1: What you see in the browser is not what's really there. Might want to add some hints about using logging to see what's really there.
S.Lott
  doesn't work, neither does %20
YHVH
A: 

Slugify removes all leading spaces, you'll need to rewrite this as a custom template tag to get the behaviour you're after. The original filter code looks like this

def slugify(value):
   """
   Normalizes string, converts to lowercase, removes non-alpha characters,
   and converts spaces to hyphens.
   """
   import unicodedata
   value = unicodedata.normalize('NFKD', value).encode('ascii', 'ignore')
   value = unicode(re.sub('[^\w\s-]', '', value).strip().lower())
   return mark_safe(re.sub('[-\s]+', '-', value))

which changes "some   string" into "some-string" killing the extra whitespace. You could change it like so:

def new_slugify(value):
   """
   Normalizes string, converts to lowercase, removes non-alpha characters,
   and converts spaces to hyphens, does not remove leading whitespace.
   """
   import unicodedata
   value = unicodedata.normalize('NFKD', value).encode('ascii', 'ignore')
   value = unicode(re.sub('[^\w\s-]', '', value).strip().lower())
   return mark_safe(re.sub('[-\s]', '-', value))

Which will result in the following behaviour: "Some  String here" to "some--string-here"

You still might have problems as mentioned before with how html treats extra whitespace, you'd have to write another, deslugify filter.

YHVH
+8  A: 

Let me preface this by saying @DNS's answer is correct as to why the spaces are not showing.

With that in mind, this template filter will replace any spaces in the string with &nbsp;

Usage:

{{ "hey there  world"|spacify }}

Output would be hey&nbsp;there&nbsp;&nbsp;world

Here is the code:

from django.template import Library
from django.template.defaultfilters import stringfilter
from django.utils.html import conditional_escape
from django.utils.safestring import mark_safe
import re

register = Library()

@stringfilter
def spacify(value, autoescape=None):
    if autoescape:
 esc = conditional_escape
    else:
 esc = lambda x: x
    return mark_safe(re.sub('\s', '&'+'nbsp;', esc(value)))
spacify.needs_autoescape = True
register.filter(spacify)

For notes on how template filters work and how to install them, check out the docs.

Paolo Bergantino
+1 for taking on the extra work to do the filter
Jarret Hardie
+1: great answer, and links to the docs too!
DNS
very nice indeed!
Markos Gogoulos