Django Passing list of objects to template - django

I have trouble of passing my get_profiles in the same template as r'^compose/$' here. r'^users/$' is what I'm using as a model and it works. "compose" is a function in my views.py.
from django.conf.urls.defaults import *
from django.views.generic.simple import redirect_to
from django.views.generic.simple import direct_to_template
from messages.views import *
from userprofile.views import get_profiles
urlpatterns = patterns('',
url(r'^$', redirect_to, {'url': 'inbox/'}),
url(r'^inbox/$', inbox, name='messages_inbox'),
url(r'^outbox/$', outbox, name='messages_outbox'),
url(r'^compose/$', compose, name='messages_compose'),
url(r'^users/$', direct_to_template, {'extra_context': { 'profiles': get_profiles }, 'template': 'messages/users.html' }),
)
userprofile/views.py
def get_profiles():
return Profile.objects.order_by("user")
I tried this:
url(r'^compose/$', compose, direct_to_template, {'extra_context': { 'profiles': get_profiles }, 'template': 'messages/compose.html' }),
But I get a function object is not iterable.

As others have said, you need to actually call the function, but if you do that in urls.py it will only be evaluated once per process. You don't want to do that.
You don't show what get_profiles does, but I assume it's some sort of utility function. I tend to think that those belong in a separate file, lib.py or utils.py, rather than views.py. (That is, assuming it's not actually a view itself - if it is, then you'll need to rethink your whole approach).
However, what I think you actually need to do is to make a template tag instead. You can keep the logic in get_profiles if you like, then make a simple tag that calls that function. Then you don't need to mess about with passing data in extra_context - just add the tag to your template.

Try adding brackets to the function call maybe?
'profiles': get_profiles()
Otherwise you are just passing a reference to the function object.
But the problem is this would only be evaluated once, when urls.py is called.
Why not make a view function to correspond with the url 'users/'?

get_profiles(), with parentheses

Related

How is the Django view class executed?

I have a simple question to ask. How is the class executed defined the views.py? For example, if I have the path defined like the following, I assume that the snippet, 'views.PostListView.as_view()', is executing the PostListView defined in the views.py. Am I right?
urlpatterns = [
path('', views.PostListView.as_view(), name='post_list'),
path('about/', views.AboutView.as_view(), name='about'),
path('post/<int:pk>', views.PostDetailView.as_view(), name='post_detail'),
]
If you look at https://github.com/django/django/blob/master/django/views/generic/base.py (which is the base View class for generic views that all of your other views would generally inherit from), as_view is defined as a class/static method of the base view class, and it specifically returns a function view (def view(request, *args, **kwargs) ), which in turn takes a request object and then multipe optional args/kwargs. This view function is what gets passed to the urlpatterns. When an actual request comes in from the user, Django walks through the urlpatterns until it finds a match, and will then pass the request object and other information to the actual view function (so it gets executed once per matching request).
Hope that helps.

Url maps operation in Django

i'm new to django and i'd like to know how the url maps work in detail.
from django.conf.urls import url
from polls import views
urlpatterns =[
url(r'^$',views.index,name='index')
]
the url function takes 3 parameters, could you explain how they work and what functionalies they have.
I've searched for this, but no detailed information are available for an absolute beginner
The Django URL dispatcher contains urlpatterns which is a Python list of url() instances.
The url(regex, view, kwargs=None, name=None) function can take 4 arguments:
regex: Regular expression, pattern matching the url.
view: View name, path, function or the result of as_view() for class-based views. It can also be an include().
kwargs: Allows you to pass additional arguments to the view function or method.
name: Naming URL patterns.

The smartest way to redirect in django without creating view

The task is simple:
If user visits site root then:
if user is authenticated then:
redirect to /dashboard/
else:
redirect to settings.LOGIN_URL
There are many ways to implement that, but I wonder if there is such way in which I do need to use only urls.py.
I found a solution with RedirectView login_required(RedirectView.as_view(url=my_url)), however then I can only write static my_url instead of reverse(), which is not flexible.
You could use reverse_lazy (Django 1.4) in you url configuration, like so:
from django.conf.urls.defaults import url, patterns
from django.core.urlresolvers import reverse_lazy
from django.shortcuts import redirect
urlpatterns = patterns('',
url(r'^/$', lambda request: return redirect(reverse_lazy('url_name')),
)
Another possibility is to define LOGIN_URL using reverse_lazy, so you could continue to use settings.LOGIN_URL in your redirects.
Code is untested, might have a typo somewhere.
You just need to mixin LoginRequired to your view. You can find an example of the mixin here:
http://djangosnippets.org/snippets/2442/
Then where you define that view, you just do:
class RedirectView(LoginRequiredMixin, DetailView):
....
Or whatever Class Based View you're inheriting from. Hope that helps!

Django odd problem with using reverse and url tag

I've found very odd thing about using reverse in Django 1.2.1.
I have:
myapp/
views.py
urls.py
in urls.py
from django.conf.urls.defaults import *
urlpatterns = patterns('myapp.views',
url(r'^$', 'browse'),
)
in views.py
from django.shortcuts import render_to_response
from django.core.urlresolvers import reverse
print reverse('myapp.views.browse') # <----- this will print correct value
def browse (request):
print reverse('myapp.views.browse') # <----- this fails with exception
return render_to_response('myapp/browse.html')
When I put reverse method anywhere outside the view method (browse - in this case) I get an exception in every further use of reverse or {% url %} tag.
NoReverseMatch at /
Reverse for 'myapp.views.browse' with arguments '()'
and keyword arguments '{}' not found.
WTF? When I comment/delete the print line outside browse() , second print line inside browse() magically start working!
The most basic case is:
class MyForm(forms.Form):
field = forms.CharField(default=reverse(....))
def some_view(request):
print reverse(...)
....
1) I define a class in main-scope that is initialized when django initialize (and runs reverse)
2) When a request comes the some_view function has been triggered and it evaluates the reverse function again (and fails with exception).
I don't see anything bad at all in this approach. Why not to initialise some values in the django main-scope with results of the reverse() function ?
You will probably need to pass 'request' as the second parameter when calling reverse() from within the view function after it's already been called.
def browse(request):
print reverse('myapp.views.browse', args=[request])
This is odd behavior indeed, but this might possibly be a solution for now.
First, you should be naming your URLs in order to use reverse. That is the correct approach AFAIK.
Second, why are you calling reverse from within a FormField? I really don't get it.
Maybe you could enlighten us by posting the full code rather than a curated set of snippets.
# urls.py
url(r'^/$', 'home_view', name='home'),
url(r'^login/$', 'login_view', name='login'),
# views.py
from django.shortcuts import render_to_response
from django.template import RequestContext
from django.http import HttpResponseRedirect
def login_view(request):
# do login stuff and redirect to home
return HttpResponseRedirect(reverse('home'))
def home(request):
# do home stuff
return render_to_response("home.html", locals(), context_instance=RequestContext(request))
The problem is caused by import hell in python. reverse depends on other things and cannot be used while initialization.
The solution is to use lazy reverse. E.g. using this:
http://djangosnippets.org/snippets/499/

CRUD pattern for urls.py, passing object from URI to view

Can the object value be looked up and passed to the generic view? Would the generic views need to be moved to views.py in order to support the object lookup?
urls.py
urlpatterns = patterns('myapp.views',
url(r'^mymodel/create/$', view='mymodel_create', name='mymodel_create'),
)
urlpatterns += patterns('django.views.generic',
url(r'^(?P<model>\w+)/create/$','create_update.create_object', name='object_create'),
url(r'^(?P<model>\w+)/(?P<id>\d+)/update/$', 'create_update.update_object', name='object_update' ),
url(r'^(?P<model>\w+)/(?P<id>\d+)/delete/$', 'create_update.delete_object', name='object_delete'), url(r'^(?P<model>\w+)/(?P<object_id>\d+)/$', 'list_detail.object_detail', name='object_detail'),
url(r'^(?P<model>\w+)/$','list_detail.object_list', name='object_list'),'
)
Example URL's:
http://localhost/myapp/thing/create
http://localhost/myapp/thing/1
http://localhost/myapp/thing/1/update
http://localhost/myapp/thing/1/delete
I'd like to use (?P\w+) to find the corresponding Model, 'Thing', but when this code is executed, the following error occurs: object_list() got an unexpected keyword argument 'model'
Yes, you can do this, and I've done it. The Django generic views don't support it directly. You need to wrap the generic view with your own view that looks up the model and constructs the queryset. Here's an example (showing only the detail view, you can do the others similarly). I've changed your named patterns in the URLconf to use "model" instead of "object", which is clearer naming:
in urls.py:
url(r'^(?P<model>\w+)/(?P<object_id>\d+)/$', 'my_app.views.my_object_detail', name='object_detail'),
in my_app/views.py
from django.views.generic.list_detail import object_detail
from django.db.models.loading import get_model
from django.http import Http404
def get_model_or_404(app, model):
model = get_model(app, model)
if model is None:
raise Http404
return model
def my_object_detail(request, model, object_id):
model_class = get_model_or_404('my_app', model)
queryset = model_class.objects.all()
return object_detail(request, queryset, object_id=object_id)
If you're clever and want to keep things as DRY as possible, you could create a single wrapper that accepts the generic view function to call as one of its arguments, rather than having a wrapper for create, a wrapper for update, etc.
I think you might be a bit confused about what the generic views are designed to do. If you go and read django.views.generic.list_detail, for instance, you will see that neither object_list nor object_detail accept an "object" argument, but both require a "queryset" argument. You don't need to "find the corresponding Model" - both generic views are simply common ways to render the provided queryset (in the case of object_detail, after being filtered by either object_id or slug and slug_field). I'm not entirely sure what you're trying to do but I don't think these generic views are what you're looking for.