How to build URL from template to the admin pages - django

Once deployed onto a production server my django app URLs are like
http://example.com/myapp/Widget/10
I'd like to put a link to the admin forms in my pages. Not sure
the correct way to put an
Go to admin
in my templates
so that I can correctly get from a URL like the above for widgets to the admin page which would be http://example.com/myapp/admin
I can't do something like
<a href="/admin">
because this only works on the dev server but not in production. Is there a way to use the syntax like {% url admin %} to get to the admin page correctly? Not sure how to code the urlpattern if I add something like
url(r'^admin$', ?, name='admin')
in my urls.py

Related

How to login users with the built-in admin login panel for my own app?

Django comes with a built-in admin page, which has it's own login panel.
Most Django sites implement their own login panel. That makes sense, since it gives them a lot of flexibility. But for some apps it would be sufficient to use the existing admin login panel instead of implementing your own.
Of course I could just redirect the user to the admin login page. However, after login the user is automatically is redirected to the main admin page and I would like him to be redirected to my app'
s page instead.
How can I use Django's built-in admin login panel for my own app?
It is possible to seamlessly integrate the admin login panel into your app, by redirecting to your app's page instead of the admin site.
The Django admin site provides default views for login and logout as documented here:
admin:login
admin:logout
Both views support the next URL parameter, which allows you to specify to which page the user will be redirected after completing the process step. This allows you to specify your own app's pages instead of the admin site.
Note that there is one caveat to this approach: The admin login panel will only work for users, which have the staff role.
Example template snippet
For this Django template we are assuming your app is called my_app and this template is part of an view called my_app:index.
{% if request.user.is_authenticated == False %}
<p>
You are currently not logged in. Click
here
to login.
</p>
{% else%}
<p>
You are logged in as user: <b>{{ request.user.username }}</b>
<a href="{% url 'admin:logout' %}?next={% url 'my_app:index' %}">[Logout]
</a>
</p>
{% endif %}

How to create an article list view in django-cms

I am an absolute beginner in django-cms, just acquired some pieces of knowledge to create templates. Just wondering, how to create a portal page that has a few acticles in each different categories?
Please simply point out a practical way to do, no real code is needed.
Thank you.
As others have pointed out, the way to do this is by hooking your CMS page to another set of views. Django-CMS provides application hooks:
#cms_app.py
from cms.app_base import CMSApp
from cms.apphook_pool import apphook_pool
class YourModuleApp(CMSApp):
name = 'My App MOdule'
urls = ['my_app.urls']
apphook_pool.register(YourModuleApp)
So, if you had a module called "my_app" with a urls.py in it, Django-CMS will add those patterns to the page. Look in the "Advanced Settings" section of the page in admin for the application drop-down menu.
Once the app is hooked to the page, Django-CMS will pull any content and the layout template from the information it holds, then hand off processing to the additional URL patterns that are hooked to it. That's how you can pull in another model, add a form, handle a POST, etc.
You could just do it the normal Django way. Create a normal Django app, with a URL pointing to a view that renders a template. The view could look like this:
from django.shortcuts import render
from cms.models import Page
def articles(request):
pages = Page.objects.public()
render(request, 'example.html', {'pages': pages})
And the template could look like this:
{% load cms_tags %}
{% for page in pages %}
<p>{% page_attribute "page_title" page %}</p>
{% endfor %}
You could stop here. Or you could have...
Additional Django CMS integration with AppHooks
Do you want your non-developer content managers to be able to put a list of articles wherever they want? This is where AppHooks come in.
Create a CMSApp class in the file appname/cms_app.py like this:
from cms.app_base import CMSApp
from cms.apphook_pool import apphook_pool
from django.utils.translation import ugettext_lazy as _
class ArticleListApp(CMSApp):
app_name = 'articlelist'
name = _('Article List')
def get_urls(self, page=None, language=None, **kwargs):
return ['articlelist.urls']
apphook_pool.register(YourModuleApp)
Delete the URL entry in your project-wide urls.py as you no longer need it. Your app's urls.py needs to include a view for the regex ^$.
Now you or any content manager user with necessary permissions can create a page in the admin interface, and modify the advanced settings to select the "Article List" application:
One gotcha is that this will have no effect until the page is published (as well as all of its ancestor pages).

Add links to navigation based on INSTALLED_APPS

I have a project that has a number of apps. These apps translate into modules that perform different functions for the end user.
Now each deployment of the project may have certain apps enabled or disabled.
What I'd like to achieve is a navigation list of links that only displays links for apps that are in INSTALLED_APPS.
For example deployment 1 has App1 and App2 listed in INSTALLED_APPS so would have a navigation something like this:
Link to App1's view
Link to App2's view
And deployment 2 has App2 and App3 installed so should show a navigation something like this:
Link to App2's view
Link to App3's view
Without having a navigation defined in a base template and editing it for each deployment, I can't see a way of doing this. Even by using { block.super }, this seems to not allow 2 apps to be installed as each child template would append to the parent.
This is strictly from the top of my head, so it may not be the "best" or most appropriate way.
First, if you're going to rely on INSTALLED_APPS you should actually implement something along the lines of:
MY_INSTALLED_APPS = (
'app1',
'app2',
)
INSTALLED_APPS = (
# other installed apps
) + MY_INSTALLED_APPS
Then, instead of having to figure out which of the items in INSTALLED_APPS are yours and which are third-party, you just use MY_INSTALLED_APPS instead for things like building your menus.
Second, in Django, apps aren't tied to views in any meaningful way. There's no concept of a "default" view, and you can't simply link to an app. However, you can some what achieve this idea through the use of namespaces and a convention for view naming, specifically, all your apps will at least have a urlpattern named "index", for example.
Then, in your urls.py you create urlpatterns like:
url(r'^app1/', include('app1.urls', namespace='app1', app_name='app1'),
url(r'^app2/', include('app2.urls', namespace='app2', app_name='app2'),
# etc
In each app, you create a urls.py that has at least one urlpattern:
url(r'^$', some_view, name='index'),
This means that the going to /app1/ in your browser would then load some_view and you can reference this view in your code with a name like: app1:index.
The tricky part is using this in your templates. Django 1.5 will add the ability to use context variables in the {% url %) tag for the view name. As of Django 1.3, you can use this behavior as well via {% load url from future %}. However, even that only gets you part-way to what you need.
In your template, you'll need to loop through the values of MY_INSTALLED_APPS and construct the links. The following should work in Django 1.3-1.4 via {% load url from future %} or Django 1.5:
{% for app in apps %}
{{ app }}
{% endfor %}
The other way to accomplish this is with a template filter, which is your only option in Django <1.3, and may still be preferable in later versions. Something like:
#register.filter
def default_url_for_app(app):
return reverse(app+':index')
And, in your template:
{% for app in apps %}
{{ app }}
{% endfor %}
You can simple import your settings.py file and iterate over the INSTALLED_APPS list.
from django.conf import settings
for installed_app in settings.INSTALLED_APPS:
But I'm also in doubt if this is a smart decision to implement your application as such.
What you really want here is some kind of app registration system. That is, for each app that's loaded (ie included in INSTALLED_APPS), register its homepage with the list of links.
Rather than doing all this automatically, I would follow the example of the admin application and get each app to call a register function on first load. You could do this in the models.py, for example, since you know that will be imported by Django on startup. The register function would take the app name and the url and build a dictionary which could then be passed to each template via a context processor.

Redirecting to last view after login

I have wrestled with this one for a bit and googled and looked through documentation, so I guess its time to ask. I am trying make my app redirect to the last viewed page after logging in. I am running django 1.2.4 and have had no luck so far.
This Stack Overflow thread seemed like it would do the trick but I have not had success with it:
Django: Redirect to previous page after login...
Currently after logging in from any view I am redirected to: //localhost:1100/accounts/profile/
settings.py has this suggested code:
"django.core.context_processors.request",
With this as my login button link:
login
I also made sure to import the RequestContext in my views.py file:
from django.template import RequestContext
I get the impression this is not working. Also I noticed now
login URL has a partial next URL in it:
//localhost:1100/accounts/login/?next=
Suggestions?
Thanks in advance!
As sdolan said, you can use the login_required decorator, but also there are a few more possiblities:
Form action:
<form method="post" action="{% url django.contrib.auth.views.login %}?next={{request.path}}">
Next hidden field:
<input type="hidden" name="next" value="{{request.path}}" />
With a link to the login form:
Login
For using them, you have to pass the Request Context in the corresponding view. Examples of doing this can be found here: http://lincolnloop.com/blog/2008/may/10/getting-requestcontext-your-templates/
If you use the login_required decorator on your views, it will do this for you automatically.
This is confirmed by experience, and explained in the docs:
If the user isn't logged in, redirect
to settings.LOGIN_URL, passing the
current absolute path in the query
string. Example:
/accounts/login/?next=/polls/3/.

Django: Reverse URL lookup with arbitrary URL components

Assume a Django app, shop, whose urls.py is included in the main urls.py:
# main urls.py
urlpatterns = patterns('',
(r'^[^/]+/shop/', include('shop.urls')),
)
Note, that there is an arbitrary prefix before /shop. This is of no interest for the shop app, it's only interesting to some middleware.
The shop.urls could look like this:
# shop's urls.py
urlpatterns = patterns('',
url(r'^$', index, name="shop_index"),
url(r'^product/(?P<id>[^/]+)$', product, name="shop_product"),
)
I now want to use {% url %} in my shop templates. What overthrows this plan is, that the generated URL doesn't include the prefix from the global urls.py. The generated URLs look more like, e.g.
/^/shop/product/1
Question: Now, is there a possibility (in Django 1.2 or svn trunk) to enable the reverse lookup to use just the same prefix, that is there in the current URL? For example, if request.path is /foo/shop/, that {% urls shop_product id=1 %} returns
/foo/shop/product/1
The only way I came up with is to embrace the prefix and send it to the shop app views, but this is a really bad solution, since shop then has to deal with something it doesn't need at all.
No there is not, not a straightforward django way anyway. Django has no idea of knowing what you mean with [^/]+, in your case that it is a prefix that should be dynamically be added to a reverse url lookup.
I wonder also why you add middleware specific info to an url and not even as GET paramters, doing something like this is jsut asking for trouble imho. If you say the prefix is middleware-specific, it doesn't make sense to mess with it somewhere outside of the middleware.
A solution that could work (did not test it) is setting in your middleware a request context variable like environment_prefix, then append this manually before the url. So something like this:
/{{ environment_prefix }}{% filter slice:"1:" %}{% url shopview %}{% endfilter %}
Another possiblity is to try to implemented your own url template tag (inheritted from the url templatetag) to always include the current prefix which can again be a context variable set by the middleware.