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