I am not completely satisfied with this decision, it can break channels using Requestand depends on the magic method. Here it is:
import re
from django import template
from django.conf import settings
from django.contrib.syndication.views import Feed
from django.core.urlresolvers import reverse, resolve, NoReverseMatch
from django.template import Node
from django.template import TemplateSyntaxError
from django.utils.encoding import smart_str
from django.utils.html import escape as html_escape
from django.utils.safestring import mark_safe
register = template.Library()
kwarg_re = re.compile(r"(?:(\w+)=)?(.+)")
class FeedInfoNode(Node):
def __init__(self, view_name, args, kwargs, asvar):
self.view_name = view_name
self.args = args
self.kwargs = kwargs
self.asvar = asvar
def render(self, context):
args = [arg.resolve(context) for arg in self.args]
kwargs = dict([(smart_str(k,'ascii'), v.resolve(context))
for k, v in self.kwargs.items()])
url = ''
try:
url = reverse(self.view_name, args=args, kwargs=kwargs, current_app=context.current_app)
except NoReverseMatch, e:
if settings.SETTINGS_MODULE:
project_name = settings.SETTINGS_MODULE.split('.')[0]
try:
url = reverse(project_name + '.' + self.view_name,
args=args, kwargs=kwargs, current_app=context.current_app)
except NoReverseMatch:
if self.asvar is None:
raise e
else:
if self.asvar is None:
raise e
if 'request' in context:
request = context['request']
else:
request = None
feed_instance, feed_args, feed_kwargs = resolve(url)
if not isinstance(feed_instance, Feed):
raise NoReverseMatch, \
'feed_info can only reverse class-based feeds'
feed_obj = feed_instance.get_object(request, *feed_args, **feed_kwargs)
feed_data = {
'url': url,
'obj': feed_instance,
'args': feed_args,
'kwargs': feed_kwargs,
'title': html_escape(
feed_instance._Feed__get_dynamic_attr('title', feed_obj)
),
'type': feed_instance.feed_type.mime_type,
}
if self.asvar:
context[self.asvar] = feed_data
return ''
else:
return mark_safe(
'<link rel="alternate" type="%(type)s" title="%(title)s" href="%(url)s" />' \
% feed_data
)
def feed_info(parser, token):
"""
Returns an mapping containing populated info about the reversed feed
Works exactly as the url tag, but the mapping is not returned, instead
a variable is always set in the context.
This is a way to define links that aren't tied to a particular URL
configuration::
{% feed_info path.to.some_feed_view_class arg1 arg2 as feed_info_var %}
or
{% feed_info path.to.some_feed_view_class name1=value1 name2=value2 as feed_info_var %}
"""
bits = token.split_contents()
if len(bits) < 2:
raise TemplateSyntaxError("'%s' takes at least one argument"
" (path to a feed view)" % bits[0])
viewname = bits[1]
args = []
kwargs = {}
asvar = None
bits = bits[2:]
if len(bits) >= 2 and bits[-2] == 'as':
asvar = bits[-1]
bits = bits[:-2]
if bits and ',' in bits[0]:
check_old_format = True
for bit in bits[1:-1]:
if ',' not in bit:
check_old_format = False
break
else:
check_old_format = False
if check_old_format:
match = kwarg_re.match(bits[0])
if match:
value = match.groups()[1]
try:
parser.compile_filter(value)
except TemplateSyntaxError:
bits = ''.join(bits).split(',')
if len(bits):
for bit in bits:
match = kwarg_re.match(bit)
if not match:
raise TemplateSyntaxError("Malformed arguments to url tag")
name, value = match.groups()
if name:
kwargs[name] = parser.compile_filter(value)
else:
args.append(parser.compile_filter(value))
return FeedInfoNode(viewname, args, kwargs, asvar)
feed_info = register.tag(feed_info)
{% url %} , , URL , resolve(), , .
- Django 1.2 Class Feeds, , .
- ,
Request , None . - Feed.__ get_dynamic_attr(). Feed ; . , ...