Create url with article title

I have articles on MongoDB. I want the URLs for the articles to be readable. If I have an article titled "How to Use Flask and MongoDB Unlimited with Heroku" I want the url to be something like localhost:5000/blog/how-to-use-flask-and-mongodb-seamlessly-with-heroku

.

What's the best way to do this? Any pointers in the right direction are appreciated. I wasn't sure where to start on this one.

+3


source to share


1 answer


You are looking for a way to generate a "slug" and use that to identify the message.

If you only want to use a slug, all titles must have a unique slug (which roughly means a unique title). This also means that if you change the post title, the URL may change, which will invalidate bookmarks and other external links.

The best way is to do something like what stack overflow does for questions. If you look at this question url, you will notice that it has a unique id and pool. In fact, the slug is optional, you can still navigate to this page by removing it from the URL.

You will need a bullet creation method and a custom url converter . The inflection library provides a nice way to flush strings using parameterize

. The following url converter takes an object and returns the url with the_object.id

and the_object.title

as a slug. When parsing the url, it just returns an object id

as the pool is optional.

from inflection import parameterize
from werkzeug.routing import BaseConverter

class IDSlugConverter(BaseConverter):
    """Matches an int id and optional slug, separated by "/".

    :param attr: name of field to slugify, or None for default of str(instance)
    :param length: max length of slug when building url
    """

    regex = r'-?\d+(?:/[\w\-]*)?'

    def __init__(self, map, attr='title', length=80):
        self.attr = attr
        self.length = int(length)
        super(IDSlugConverter, self).__init__(map)

    def to_python(self, value):
        id, slug = (value.split('/') + [None])[:2]
        return int(id)

    def to_url(self, value):
        raw = str(value) if self.attr is None else getattr(value, self.attr, '')
        slug = parameterize(raw)[:self.length].rstrip('-')
        return '{}/{}'.format(value.id, slug).rstrip('/')

      

Register the transformer so it can be used in routes:

app.url_map.converters['id_slug'] = IDSlugConverter

      



Use it in your route:

@app.route('/blog/<id_slug:id>')
def blog_post(id):
    # get post by id, do stuff

      

Create a url for the post. Note that you are passing an object ('post'), not just an id, to the id parameter .:

url_for('blog_post', id=post)
# /blog/1234/the-post-title

      


A converter I wrote for the Python stack overflow chat site .

+6


source







All Articles