Plain is headed towards 1.0! Subscribe for development updates →

 1from plain.urls import NoReverseMatch, reverse
 2from plain.utils.functional import Promise
 3
 4
 5def resolve_url(to, *args, **kwargs):
 6    """
 7    Return a URL appropriate for the arguments passed.
 8
 9    The arguments could be:
10
11        * A model: the model's `get_absolute_url()` function will be called.
12
13        * A view name, possibly with arguments: `urls.reverse()` will be used
14          to reverse-resolve the name.
15
16        * A URL, which will be returned as-is.
17    """
18    # If it's a model, use get_absolute_url()
19    if hasattr(to, "get_absolute_url"):
20        return to.get_absolute_url()
21
22    if isinstance(to, Promise):
23        # Expand the lazy instance, as it can cause issues when it is passed
24        # further to some Python functions like urlparse.
25        to = str(to)
26
27    # Handle relative URLs
28    if isinstance(to, str) and to.startswith(("./", "../")):
29        return to
30
31    # Next try a reverse URL resolution.
32    try:
33        return reverse(to, *args, **kwargs)
34    except NoReverseMatch:
35        # If this is a callable, re-raise.
36        if callable(to):
37            raise
38        # If this doesn't "feel" like a URL, re-raise.
39        if "/" not in to and "." not in to:
40            raise
41
42    # Finally, fall back and assume it's a URL
43    return to