Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

add slugified title to url

Tags:

python

flask

I have a url like /posts/1, where 1 refers to the id of the article in the db.

@bp.route('/<post_id>')
@login_required
def post(post_id):
    """ find the post and then show it """
    p = Post.query.get(post_id)
    return render_template("post/single_post.html", post=p)

However, what I would like to do is have a url with some sort of slugified title in it, like /posts/1/my_stack_overflow_question_is_bad. I can make a slugify property in the model:

class Post(db.Model):
    __tablename__ = 'posts'
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String)
    html = db.Column(db.String)

    @property
    def slugified_title():
        return slugify(self.title, separator="_", to_lower=True)

but how would I put that in the url?

like image 796
corvid Avatar asked Oct 19 '14 13:10

corvid


1 Answers

You just need to add the slug element to the URL route:

@bp.route('/<post_id>/<slug>')
@login_required
def post(post_id, slug):
    """ find the post and then show it """
    p = Post.query.get(post_id)
    return render_template("post/single_post.html", post=p)

Then when you want to create the URL for it-- just supply the slug into the url_for function:

p = Post.query.get(1)
url_for('post', post_id=p.id, slug=p.slugified_title)

That can get a bit tedious, so I tend to have a permalink decorator:

# Inspired by http://flask.pocoo.org/snippets/6/

from flask import url_for

def permalink(function):
    def inner(*args, **kwargs):
        endpoint, values = function(*args, **kwargs)
        return url_for(endpoint, **values)
    return inner

Then adjust my model to use it:

class Post(db.Model):
    __tablename__ = 'posts'
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String)
    html = db.Column(db.String)

    @property
    def slugified_title():
        return slugify(self.title, separator="_", to_lower=True)

    @permalink
    def url(self):
        # where 'post' is the title of your route that displays the post
        return 'post', {'post_id': self.id, 'slug':self.slugified_title}

That way when I need a url, I can just ask the object for it's url, and not have to go through the url_for step manually.

like image 64
Doobeh Avatar answered Oct 16 '22 23:10

Doobeh