""" utils.converter: Custom URL converters to match patterns in @app.route() The Flask documentation is elusive on this topic. To add a new converter, proceed as follows: 1. Define a new converter class. 2. Set the [regex] attribute to decide which portion of the URL will be considered for conversion (apparently the default is everything until next slash or end of string). 3. Define the to_python() and to_url() methods to actually convert. 4. Add the class to __all__ at the bottom of this file. 5. In app/__init__.py, add a dictionary entry to [app.url_map.converters]. For more information, see the Werkzeug documentation: """ from werkzeug.routing import BaseConverter, ValidationError from app.models.forum import Forum from app.models.topic import Topic import re import sys class ForumConverter(BaseConverter): # This regex will decide which portion of the URL is matched by the curtom # converter. By default, slashes are not included, so we must add them. regex = r'[a-z/]+' def to_python(self, url): url = '/' + url f = Forum.query.filter_by(url=url).first() if f is None: raise ValidationError(f"ForumConverter: no forum with url {url}") return f def to_url(self, forum): return forum.url[1:] class TopicSlugConverter(BaseConverter): # Only catch integers followed by an optional slug string regex = r'(\d+)(?:-[\w-]*)?' def to_python(self, url): """Convert an URL pattern to a Python object, or raise an exception.""" m = re.fullmatch(TopicSlugConverter.regex, url) if m is None: raise Exception(f"TopicSlugConverter: conversation failed") return Topic.query.get_or_404(int(m[1], 10)) def to_url(self, topic): return str(topic.id) # Export only the converter classes __all__ = "ForumConverter TopicSlugConverter".split()