Repository: django-cms/django-cms

Issue:
as argument to page_url template tag (that supresses exceptions)
I'd like to have an "as" argument to the `page_url` template tag similar to the one for django's `url` template tag.  On a current project, it's hard to decouple content because of the `Page.DoesNotExist` exception thrown when a page matching the lookup argument for `page_url` doesn't exist.  I'd like a solution that lets me keep `DEBUG = True` in my settings and doesn't raise an exception when a page doesn't exist.  The `as` argument to the tag seems like an unobtrusive fix that doesn't break the existing functionality of the tag.  It would allow for patterns like this:

```
{% page_url "about" as about_url %}
{%if about_url %}<a href="{{ about_url }}">{% trans "About" %}</a>{% endif %}
```

If there's traction for this feature, I can probably code it up, but wanted to get a sense of whether the community is into it before I get started.



Discussion:
It looks like at least one other person has asked about this in the past (https://groups.google.com/forum/?fromgroups=#!topic/django-cms/MOk6fv4tGW0)

This would indeed be very handy in combination with the `blocktrans` templatetag.

For example:

``` django
{% blocktrans with page_url "my_page_id" as my_url %}Have a look at <a href="{{ my_url }}">{{ my_url }}</a> for further information.{% endblocktrans %}
```

Without investigating any further, could `PageUrl` inherit from `AsTag` instead of `InclusionTag`?

:+1: need something like that.

pull request would be accepted


Resolving patch:
diff --git a/cms/templatetags/cms_tags.py b/cms/templatetags/cms_tags.py
--- a/cms/templatetags/cms_tags.py
+++ b/cms/templatetags/cms_tags.py
@@ -110,42 +110,60 @@ def _get_page_by_untyped_arg(page_lookup, request, site_id):
                 mail_managers(subject, body, fail_silently=True)
             return None
 
-
-class PageUrl(InclusionTag):
-    template = 'cms/content.html'
+#
+# This is borrowed from https://github.com/okfn/foundation
+#
+class PageUrl(AsTag):
     name = 'page_url'
 
     options = Options(
         Argument('page_lookup'),
         Argument('lang', required=False, default=None),
         Argument('site', required=False, default=None),
+        'as',
+        Argument('varname', required=False, resolve=False),
     )
 
-    def get_context(self, context, page_lookup, lang, site):
+    #
+    # We override render_tag here so as to provide backwards-compatible
+    # behaviour when varname is not provided.
+    #
+    # If varname is not provided, and the specified page cannot be found, we
+    # pass through the Page.DoesNotExist exception.
+    #
+    # If varname is provided, we swallow the exception and just set the value
+    # to None.
+    #
+
+    def get_value(self, context, page_lookup, lang, site):
         from django.core.cache import cache
+
         site_id = get_site_id(site)
         request = context.get('request', False)
+
         if not request:
-            return {'content': ''}
+            return ''
 
-        if request.current_page == "dummy":
-            return {'content': ''}
         if lang is None:
             lang = get_language_from_request(request)
-        cache_key = _get_cache_key('page_url', page_lookup, lang, site_id) + '_type:absolute_url'
+
+        cache_key = _get_cache_key('page_url', page_lookup, lang, site_id) + \
+            '_type:absolute_url'
+
         url = cache.get(cache_key)
+
         if not url:
             page = _get_page_by_untyped_arg(page_lookup, request, site_id)
             if page:
                 url = page.get_absolute_url(language=lang)
-                cache.set(cache_key, url, get_cms_setting('CACHE_DURATIONS')['content'])
+                cache.set(cache_key, url,
+                          get_cms_setting('CACHE_DURATIONS')['content'])
         if url:
-            return {'content': url}
-        return {'content': ''}
+            return url
+        return ''
 
 
 register.tag(PageUrl)
-
 register.tag('page_id_url', PageUrl)
 
 


Test patch:
diff --git a/cms/tests/rendering.py b/cms/tests/rendering.py
--- a/cms/tests/rendering.py
+++ b/cms/tests/rendering.py
@@ -276,6 +276,16 @@ def test_page_url_by_page(self):
         output = self.render(template, self.test_page, {'test_page': self.test_page2})
         self.assertEqual(output, self.test_page2.get_absolute_url())
 
+    def test_page_url_by_page_as(self):
+        template = u'{% load cms_tags %}{% page_url test_page as test_url %}{{ test_url }}'
+        output = self.render(template, self.test_page, {'test_page': self.test_page2})
+        self.assertEqual(output, self.test_page2.get_absolute_url())
+
+    def test_page_url_by_page_as_for_bogus_page(self):
+        template = u'{% load cms_tags %}{% page_url "bogus_page" as test_url %}{{ test_url }}'
+        output = self.render(template, self.test_page, {'test_page': self.test_page2})
+        self.assertEqual(output, '')
+
     def test_page_attribute(self):
         """
         Tests the {% page_attribute %} templatetag, using current page, lookup by pk/dict/reverse_id and passing a Page object.