Reputation: 125
I want to create a slug field stored in database.
I searched and I found http://flask.pocoo.org/snippets/5/ but I'm having trouble integrating the code in my app.
This is my modele.py
:
from unicodedata import normalize
def slugfy(text, encoding=None,
permitted_chars='abcdefghijklmnopqrstuvwxyz0123456789-'):
if isinstance(text, str):
text = text.decode(encoding or 'ascii')
clean_text = text.strip().replace(' ', '-').lower()
while '--' in clean_text:
clean_text = clean_text.replace('--', '-')
ascii_text = normalize('NFKD', clean_text).encode('ascii', 'ignore')
strict_text = map(lambda x: x if x in permitted_chars else '', ascii_text)
return ''.join(strict_text)
class Chanteur(db.Model):
id = db.Column(db.Integer, primary_key = True)
nom = db.Column(db.String(200), index = True, unique = True)
slug = db.Column(db.String(255))
chanteurs = db.relationship('Chanson', backref = 'chanteur', lazy = 'dynamic')
def __repr__(self):
return '<Chanteur %r>' % (self.nom)
def __setattr__(self, key, value):
super(Chanteur, self).__setattr__(key, value)
if key == 'nom':
self.slug = slugfy(self.nom)
class Chanson(db.Model):
id = db.Column(db.Integer, primary_key = True)
titre = db.Column(db.String(255))
chanteur_id = db.Column(db.Integer, db.ForeignKey('chanteur.id'))
def __repr__(self):
return '<Chanson %r>' % (self.titre)
It is not working: when I add a new objet (chanteur) the slug field is empty
Upvotes: 7
Views: 11383
Reputation: 157
I wrote an article about this topic. My approach is to use the 'before_commit' event for the session. You can read about it here
Upvotes: 0
Reputation: 81
A small improvement on @berislav-lopac suggestion's, Using python-slugify you can
from slugify import slugify
class SlugModel(Base):
name = Column(String)
slug = Column(String)
@staticmethod
def slugify(target, value, oldvalue, initiator):
if value and (not target.slug or value != oldvalue):
target.slug = slugify(value)
event.listen(SlugModel.name, 'set', SlugModel.slugify, retval=False)
This will update slug's column content on create\update
if you want even a better solution, you can use the @hybrid_property decorator as suggested here
Upvotes: 8
Reputation: 17273
To persist the slug in the database, I use the following approach (employing the very helpful python-slugify
library):
from slugify import slugify # among other things
class Song(db.Model):
id = db.Column(db.Integer, primary_key = True)
title = db.Column(db.String(255))
slug = db.Column(db.String(255))
def __init__(self, *args, **kwargs):
if not 'slug' in kwargs:
kwargs['slug'] = slugify(kwargs.get('title', ''))
super().__init__(*args, **kwargs)
Upvotes: 18
Reputation: 1
in the slug function above, you need to do the loop
clean_text.replace('--', '-')
AFTER you reduce it to permitted characters. If you don't: This & That
will be returned as this--that
.
Upvotes: -2
Reputation: 552
Salute,
you can do this way if you want the slug field represents le titre de la Chanson.
from unicodedata import normalize
def slug(text, encoding=None,
permitted_chars='abcdefghijklmnopqrstuvwxyz0123456789-'):
if isinstance(text, str):
text = text.decode(encoding or 'ascii')
clean_text = text.strip().replace(' ', '-').lower()
while '--' in clean_text:
clean_text = clean_text.replace('--', '-')
ascii_text = normalize('NFKD', clean_text).encode('ascii', 'ignore')
strict_text = map(lambda x: x if x in permitted_chars else '', ascii_text)
return ''.join(strict_text)
class Chanson(object):
titre = ''
slugfield = ''
def __setattr__(self, key, value):
super(Chanson, self).__setattr__(key, value)
if key == 'titre':
self.slugfield = slug(self.titre)
m = Chanson()
m.titre = 'Non, je ne regrette rien'
print m.titre
print m.slugfield
The slug method was grabbed from here
Edited
def slug(text):
#slugfy logic here
class Chanson(db.Model):
id = db.Column(db.Integer, primary_key = True)
titre = db.Column(db.String(255))
chanteur_id = db.Column(db.Integer, db.ForeignKey('chanteur.id'))
slugfield = db.Column(db.String(255))
def __setattr__(self, key, value):
super(Chanson, self).__setattr__(key, value)
if key == 'titre':
self.slugfield = slug(self.titre)
Upvotes: 0
Reputation: 6460
Install package called Webhelpers and it makes slugification a piece of cake.
from webhelpers.text import urlify
class Chanteur(db.Model):
id = db.Column(db.Integer, primary_key=True)
nom = db.Column(db.String(200), index=True, unique=True)
chanteurs = db.relationship('Chanson', backref='chanteur', lazy='dynamic')
def __repr__(self):
return '<Chanteur %r>' % (self.nom)
@property
def slug(self):
return urlify(self.nom)
class Chanson(db.Model):
id = db.Column(db.Integer, primary_key=True)
titre = db.Column(db.String(255))
chanteur_id = db.Column(db.Integer, db.ForeignKey('chanteur.id'))
def __repr__(self):
return '<Chanson %r>' % (self.titre)
@property
def slug(self):
return urlify(self.nom)
Refer docs for more info.
Upvotes: 1