views:

233

answers:

3

Hello All,

Hopefully a really simple one, possible even stupid!

I'm building a tagging system in Django and would like to allow spaces and other characters in the tag name for display but filter them out and use lower case when matching names etc.

To that end I have added a field to my Tag model as so:

class Tag(models.Model):
    name = models.CharField(max_length=200, unique=True)
    matchname = re.sub("\W+" , "", name.lower())

However I am running into a problem, the CharField is not a string and I cannot for the life of me find out how to convert it to one!

Any help (plus comments on the general approach) would be much appreciated!

Thanks,
Dave

Edit: Great answers one and all. Have marked Dave Webb's as it explains the main thing I was doing wrong, Doh! Although I will be using Ferran's answer as it makes sense to be able to use Djangos built in querys on the matchname, plus it means I can make both unique to ensure no repeats with different caps etc.

Thanks guys, if I could mark all as answers I would as they are all valid and potentially useful for others in the same situation. Up votes all round!

(also should I leave this here or add another post for it?)

+5  A: 

You're defining a class there so name is not a string it's a Django Field.

Additionally, converting name to matchname at the class level doesn't make any sense. You should be doing this on the instance.

You could add a method to your class to do this:

def get_matchname(self):
    """Returns the match name for a tag"""
    return re.sub("\W+" , "", self.name.lower())
Dave Webb
Something like `def matchname(self): return re.sub("\W+" , "", self.name.lower())` (this is what I was going to put in my answer, but today stackoverflow hates me).
Dominic Rodger
@Dominic - Was just editing the answer to add that. <meta>I keep getting server error too; the site keeps logging me in and out which I think is the source of the problem.</meta>
Dave Webb
+1 from me (docstrings in code samples? whatever next!)
Dominic Rodger
And a documentation link too! :D
DavidM
+1  A: 

You could add a method:

class Tag(models.Model):
    name = models.CharField(max_length=200, unique=True)
    def get_matchname(self):
        return re.sub("\W+" , "", name.lower())

And use property decorator:

class Tag(models.Model):
    name = models.CharField(max_length=200, unique=True)
    @property
    def matchname(self):
        return re.sub("\W+" , "", name.lower())

All this will let you to access name field lowercased and with non-word characters stripped. But you won't get it stored in DB. If you want this you'll need to add another CharField and keep name and matchname synchronized.

pingw33n
+2  A: 

First you have to define the field as as a CharField to be able to use it for search.

class Tag(models.Model):
    name = models.CharField(max_length=200, unique=True)
    matchname = models.CharField(max_length=200, unique=True)

And then you can overwrite the save function in the model to populate it like this:

class Tag(models.Model):

    def save(self):
        self.matchname = re.sub("\W+" , "", self.name.lower())
        super(Tag,self).save()

Or use a signal for doing the same:

from django.db.models.signals import pre_save

def populate_matchname(sender,instance,**kwargs):
    instance.matchname = re.sub("\W+" , "", instance.name.lower())

pre_save(populate_matchname,sender=Tag)
Ferran