Reversible, named URLs for Django flatpages (or multilingual-ng)? - django

Is there a way to have reversible, named URLs for Django flatpages (or multilingual-ng, which is flatpages + translations)?
If not, is there a similar app available which can have named URLs for pages which are editable through the admin? (And I'd rather avoid any behemoth CMSs, please.)
edit: Please see the comments in the answers below for more discussion and clarification of the question.

As the very last thing in your root URLConf, put
(r'^(?P<url>.*)$', 'django.contrib.flatpages.views.flatpage'),
Now you can use the {% url %} tag, with the view name flatpage and the keyword argument url. You can also use the reverse() function in views.

{% url %} template tag works with URLconf, whereas flatpages are handling nonexistent urls.
If you really want to reverse flatpages into URLs, my guess is that you have to write your own {% flatpage_url %} tag, which would looks like this:
#register.simple_tag
def flatpage_url(self, name):
return FlatPage.objects.get({param}=name).url
-- where {param} is one of FlatPage model fields.
Also, you can merge {% url %} and {% flatpageurl %} tags together, so that the latter fallbacks to reverse() in case FlatPage is not found (and reverse() is what {% url %} uses).
EDIT: I don't accept any more upvotes as James Bennet's answer is The One for this question (and I'm ashamed I overlooked such trivial solution) - so please upvote it.

Aren't the proposed solutions basically the same as hardcoding the URL in the template? What's the difference between hardcoding the URL in href="URL" vs. doing it in {% url URL %}?
I think a better solution is found on: How can I get the reverse url for a Django Flatpages template, proposed by bufh.
I think the optimal way of achieving this would be adding an extra 'name' field on the FlatPage model.

Related

Django Nested URL passing slugs

I'm looking to accomplish a URL as so:
/group/<group_name>/discussion/<discussion_name>/
My implementation is shown below
project urls.py
url(r'^group/', include('groups.urls')
group urls.py
url(r'^(?P<gslug>[\w-]+)/discussion/', include('discussions.urls')),
discussion urls.py
url(r'^(?P<slug>[\w-]+)',views.discussion_detail, name='discussion_detail'))
Unfortunately in my views.discussion_detail I do not have access to both gslug and slug. Where have I gone wrong?
discussion views.py
def discussion_detail(request, gslug, slug):
pass //logic in here
Make sure that you're passing variables into the view properly with the 'url' template tag like so
{% url 'discussion_detail' group.slug discussion.slug %}
Let me know if that works :)

NoReverseMatch at /, u'opts|admin_urlname' is not a registered namespace Django 1.4.1

Django newbie here. Following the documentation, I am trying the following to get a link to the admin site from the homepage of the public site I'm building:
{% load admin_urls %}
<p>Go to the admin.</p>
I am getting the error:
NoReverseMatch at /
u'opts|admin_urlname' is not a registered namespace
I am including the URLs properly:
url(r'^admin/', include(admin.site.urls)),
My template loaders are in the right order.
I've tried a few different variations on this, and they all throw namespace errors.
Any ideas? Thanks!
After 30 minutes with Daniel Roseman / Django docs in one screen and my code in the other, I come up with this simple solution:
In your views.py, add the opts context with the _meta of the model (that includes the required app_label and model_name):
class YourModelDetailView(DetailView):
def get_context_data(self, **kwargs):
context = super(YourModelDetailView, self).get_context_data(**kwargs)
context["opts"] = YourModel._meta
return context
In your templates:
{% url opts|admin_urlname:'change' object.pk %}
Where change can be any action in the reverse admin urls documentation page.
While the above answers were helpful about the code I was calling, there is a much easier way. I'm using this instead:
{% url 'admin:index' %}
This works for custom admin views as well, like:
{% url 'admin:myapp_mymodel_<keyword>' object.id %}
Where keyword is from the named parameters listed here (i.e. add, change, delete).
You are almost certainly using the released 1.4 version, rather than the development version. As the documentation for that version shows, you need to use {% load url from future %} before you can use that syntax.

Django how to define common url

I am implementing a directory service and as you know listing URLs appear on a lot of places. I am aware of using the {% url %} tag, it's still not bullet proof for cases like global listing url structure changes, say I had {% url id=listing.id %} and had to add slug to the URL like {% url id=listing.id slug=listing.slug %}
While global search & replace is an option, however I am curious if there is a canonical way
to approach this issue.
Currently my approach is have a listingurl.html which only has {% url id=listing.id slug=listing.slug %} and wherever needs to have the url will just include listingurl.html, however I am not sure if implementing a custom filter would be more efficient?
Not 100% sure this works and if it is the most elegant solution:
some_template.html
{% include 'listing.html' with url_thing %}
listing.html
{% url url_thing id=object.id %}
The best way to handle it IMHO is to add a get_absolute_url method to your model. Then, instead of working about reversing the URL in the template, you can just call that method:
#models.permalink
def get_absolute_url(self):
return ('listing_view_name', {'id': self.id, 'slug': self.slug})
Then:
{{ listing }}

Why does django page cms get_absolute_url return an empty string?

I am having issues with get_absolute_url in my django templates when using django page cms.
It returns an empty string and does not link to my required page.
I have the following Models, URLs templates and views
Models
class Body(models.Model):
...
url = models.SlugField(unique=True, help_text='---')
urls
(r'^news/', include('news.urls_news')),......
url(r'^/(?P<url>[\w\-]+)/$', 'news_view', name='news_view'),
View
def news_view(request, url):
new = get_object_or_404(Body, url=url)
return render_to_response('news/view.html', {
'news': news
}, context_instance=RequestContext(request))
Template
<li>{{ news.title }}</li>
the following code in my template returns the string I desire however this does to direct to my html page
<li>{{ news.title }}</li>
I know my everything links to the correct files because I have other views that work correctly. Could somebody please point me in the correct direction as to why get_absolute_url is not working correctly and why {{ news.url }} does not direct to the correct page. I am sure it has something to do with my urls.py however I am not certain.
Please bear with me I am new to django. All help is greatly appreciated.
Have you actually defined a get_absolute_url method on the News model? You don't show it.

Django: How can I identify the calling view from a template?

Short version:
Is there a simple, built-in way to identify the calling view in a Django template, without passing extra context variables?
Long (original) version:
One of my Django apps has several different views, each with its own named URL pattern, that all render the same template. There's a very small amount of template code that needs to change depending on the called view, too small to be worth the overhead of setting up separate templates for each view, so ideally I need to find a way to identify the calling view in the template.
I've tried setting up the views to pass in extra context variables (e.g. "view_name") to identify the calling view, and I've also tried using {% ifequal request.path "/some/path/" %} comparisons, but neither of these solutions seems particularly elegant. Is there a better way to identify the calling view from the template? Is there a way to access to the view's name, or the name of the URL pattern?
Update 1: Regarding the comment that this is simply a case of me misunderstanding MVC, I understand MVC, but Django's not really an MVC framework. I believe the way my app is set up is consistent with Django's take on MVC: the views describe which data is presented, and the templates describe how the data is presented. It just happens that I have a number of views that prepare different data, but that all use the same template because the data is presented the same way for all the views. I'm just looking for a simple way to identify the calling view from the template, if this exists.
Update 2: Thanks for all the answers. I think the question is being overthought -- as mentioned in my original question, I've already considered and tried all of the suggested solutions -- so I've distilled it down to a "short version" now at the top of the question. And right now it seems that if someone were to simply post "No", it'd be the most correct answer :)
Update 3: Carl Meyer posted "No" :) Thanks again, everyone.
Since Django 1.5, the url_name is accessible using:
request.resolver_match.url_name
Before that, you can use a Middleware for that :
from django.core.urlresolvers import resolve
class ViewNameMiddleware(object):
def process_view(self, request, view_func, view_args, view_kwargs):
url_name = resolve(request.path).url_name
request.url_name = url_name
Then adding this in MIDDLEWARE_CLASSES, and in templates I have this:
{% if request.url_name == "url_name" %} ... {% endif %}
considering a RequestContext(request) is always passed to the render function. I prefer using url_name for urls, but one can use resolve().app_name and resolve().func.name, but this doesn't work with decorators - the decorator function name is returned instead.
No, and it would be a bad idea. To directly refer to a view function name from the template introduces overly tight coupling between the view layer and the template layer.
A much better solution here is Django's template inheritance system. Define a common parent template, with a block for the (small) area that needs to change in each view's version. Then define each view's template to extend from the parent and define that block appropriately.
If your naming is consistent in your urls.py and views.py, which it should be, then this will return the view name:
{{ request.resolver_match.url_name }}
Be sure to apply some context to it when you call it in the template. For example, I use it here to remove the delete button from my detail view, but in my update view the delete button will still appear!
{% if request.resolver_match.url_name != 'employee_detail' %}
Since Django 1.5 you can access an instance of ResolverMatch through request.resolver_match.
The ResolverMatch gives you the resolved url name, namespace, etc.
one simple solution is :
def view1(req):
viewname = "view1"
and pass this viewname to the template context
def view2(req):
viewname = "view2"
and pass this viewname to the template context
in template access the viewname as
{{viewname}}
and also you can use this in comparisons.
I'm working on this for a help-page system where I wanted each view to correspond to a help-page in my cms with a default page shown if no help page was defined for that view. I stumbled upon this blog where they use a template context processor and some python inspect magic to deduce the view name and populate the context with it.
This sounds like the perfect example of a generic view that you can set up.
See the following resources:
Django Book - Chapter 11: Generic Views
Django Docs -Tutorial: Chapter 4
Django Docs - Generic Views
These links should help you simplify your views and your templates accordingly.
If you're using Class Based Views, you most likely have a view variable you can access.
You can use several methods from that to determine which view has been called or which template is being rendered.
e.g.
{% if view.template_name == 'foo.html' %}
# do something
{% else %}
# other thing
{% endif %}
Another option is to take out the piece of the template where you need something to change and make it into a snippet and then use {% include 'my_snippet.html' with button_type = 'bold' %} in your templates, sending arbitrary values to the snippet so it can determine what to show / how to style itself.
Most generic views — if not all — inherits the ContextMixin which adds a view context variable that points to the View instance.
In your template, you can access the current view instance like this:
{{ view }}
Define class_name method in your view
class ExampleView(FormView):
...
def class_name(self):
return self.__class__.__name__
You can get the class name of the current view in a template like this:
{{ view.class_name }}
{% if view.class_name == "ExampleView" %} ... {% endif %}
Why not trying setting up a session cookie, then read the cookie from your template.
on your views set cookies
def view1(request):
...
#set cookie
request.session["param"]="view1"
def view2(request):
request.session["param"]="view2"
then in your ONE template check something like..
{% ifequal request.session.param "view1" %}
... do stuff related to view1
{% endifequal %}
{% ifequal request.session.param "view2" %}
... do stuff related to "view2"
{% endifequal %}
Gath