将slug化标题添加到网址

5 投票
1 回答
1387 浏览
提问于 2025-04-28 09:32

我有一个网址,比如 /posts/1,这里的 1 是数据库中文章的编号。

@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)

不过,我想要的网址是带有某种简化标题的,比如 /posts/1/my_stack_overflow_question_is_bad。我可以在模型里创建一个简化标题的属性:

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)

但是我该怎么把这个简化标题放进网址里呢?

暂无标签

1 个回答

8

你只需要在网址的路由中添加一个“slug”元素:

@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)

然后,当你想为它创建网址时,只需把这个“slug”放进 url_for 函数里:

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

不过这样做有点麻烦,所以我通常会使用一个叫做永久链接装饰器

# 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

接着调整我的模型来使用这个装饰器:

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}

这样,当我需要一个网址时,我只需向对象请求它的网址,就不用手动经过 url_for 的步骤了。

撰写回答