You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

static.py 4.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. from urllib.parse import quote, urljoin
  2. from django import template
  3. from django.apps import apps
  4. from django.utils.encoding import iri_to_uri
  5. from django.utils.html import conditional_escape
  6. register = template.Library()
  7. class PrefixNode(template.Node):
  8. def __repr__(self):
  9. return "<PrefixNode for %r>" % self.name
  10. def __init__(self, varname=None, name=None):
  11. if name is None:
  12. raise template.TemplateSyntaxError(
  13. "Prefix nodes must be given a name to return.")
  14. self.varname = varname
  15. self.name = name
  16. @classmethod
  17. def handle_token(cls, parser, token, name):
  18. """
  19. Class method to parse prefix node and return a Node.
  20. """
  21. # token.split_contents() isn't useful here because tags using this method don't accept variable as arguments
  22. tokens = token.contents.split()
  23. if len(tokens) > 1 and tokens[1] != 'as':
  24. raise template.TemplateSyntaxError(
  25. "First argument in '%s' must be 'as'" % tokens[0])
  26. if len(tokens) > 1:
  27. varname = tokens[2]
  28. else:
  29. varname = None
  30. return cls(varname, name)
  31. @classmethod
  32. def handle_simple(cls, name):
  33. try:
  34. from django.conf import settings
  35. except ImportError:
  36. prefix = ''
  37. else:
  38. prefix = iri_to_uri(getattr(settings, name, ''))
  39. return prefix
  40. def render(self, context):
  41. prefix = self.handle_simple(self.name)
  42. if self.varname is None:
  43. return prefix
  44. context[self.varname] = prefix
  45. return ''
  46. @register.tag
  47. def get_static_prefix(parser, token):
  48. """
  49. Populate a template variable with the static prefix,
  50. ``settings.STATIC_URL``.
  51. Usage::
  52. {% get_static_prefix [as varname] %}
  53. Examples::
  54. {% get_static_prefix %}
  55. {% get_static_prefix as static_prefix %}
  56. """
  57. return PrefixNode.handle_token(parser, token, "STATIC_URL")
  58. @register.tag
  59. def get_media_prefix(parser, token):
  60. """
  61. Populate a template variable with the media prefix,
  62. ``settings.MEDIA_URL``.
  63. Usage::
  64. {% get_media_prefix [as varname] %}
  65. Examples::
  66. {% get_media_prefix %}
  67. {% get_media_prefix as media_prefix %}
  68. """
  69. return PrefixNode.handle_token(parser, token, "MEDIA_URL")
  70. class StaticNode(template.Node):
  71. def __init__(self, varname=None, path=None):
  72. if path is None:
  73. raise template.TemplateSyntaxError(
  74. "Static template nodes must be given a path to return.")
  75. self.path = path
  76. self.varname = varname
  77. def url(self, context):
  78. path = self.path.resolve(context)
  79. return self.handle_simple(path)
  80. def render(self, context):
  81. url = self.url(context)
  82. if context.autoescape:
  83. url = conditional_escape(url)
  84. if self.varname is None:
  85. return url
  86. context[self.varname] = url
  87. return ''
  88. @classmethod
  89. def handle_simple(cls, path):
  90. if apps.is_installed('django.contrib.staticfiles'):
  91. from django.contrib.staticfiles.storage import staticfiles_storage
  92. return staticfiles_storage.url(path)
  93. else:
  94. return urljoin(PrefixNode.handle_simple("STATIC_URL"), quote(path))
  95. @classmethod
  96. def handle_token(cls, parser, token):
  97. """
  98. Class method to parse prefix node and return a Node.
  99. """
  100. bits = token.split_contents()
  101. if len(bits) < 2:
  102. raise template.TemplateSyntaxError(
  103. "'%s' takes at least one argument (path to file)" % bits[0])
  104. path = parser.compile_filter(bits[1])
  105. if len(bits) >= 2 and bits[-2] == 'as':
  106. varname = bits[3]
  107. else:
  108. varname = None
  109. return cls(varname, path)
  110. @register.tag('static')
  111. def do_static(parser, token):
  112. """
  113. Join the given path with the STATIC_URL setting.
  114. Usage::
  115. {% static path [as varname] %}
  116. Examples::
  117. {% static "myapp/css/base.css" %}
  118. {% static variable_with_path %}
  119. {% static "myapp/css/base.css" as admin_base_css %}
  120. {% static variable_with_path as varname %}
  121. """
  122. return StaticNode.handle_token(parser, token)
  123. def static(path):
  124. """
  125. Given a relative path to a static asset, return the absolute path to the
  126. asset.
  127. """
  128. return StaticNode.handle_simple(path)