How is the Django view class executed? - django

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.

Related

Django - Retrieve url origin from view - multiple urls to 1 view

I have several urls mapping to one view. Inside the url, I would like to know the url origin? It is to avoid writing multiple views (DRY).
urlpatterns = [
path('path1/', views.IndexView.as_view(), name='index'),
path('path2/', views.IndexView.as_view(), name='index')
]
class IndexView(generic.ListView):
url_origin = ... #would like path1 or path2
I looked for 'reverse' but it does not seem to be a solution to my problem. It returns an error.
reverse('index')
Thank you in advance
You can obtain the original path with request.path [Django-doc] (so in a view function for a class-based view, you can access this with self.request.path.
You can however fix this, for example by providing an extra parameter, like:
urlpatterns = [
path('path1/', views.IndexView.as_view(), name='index1', kwargs={'through': 'path1'}),
path('path2/', views.IndexView.as_view(), name='index2', kwargs={'through': 'path2'})
]
Then you can inspect the self.kwargs['through'] parameter in your class-based view.
Note that you better give the different paths a different name, since otherwise, it will indeed raise an error. By giving these as name 'index1' and 'index2', you can simply use reverse('index1'), and it is not ambiguous to what URL it should redirect.

redirect vs reverse django

I have experienced using reverse within get_absolute_url method in the model, but I wish I have an idea about the difference between reverse and redirect, I have tried to search on google about it but there is almost nothing
I don't know what should I write also to convince stack overflow that I don't have any other description
Reverse and redirect have a different meaning. Here is a simple explanation:
reverse in Django is used to find the URL of a given resource. Let's say that you have a blog website and from the main page, you want to provide links to your blog posts. You can of course just hard-code /posts/123/ and just change the ID of your blog post in URL, but that makes it hard to change your URL for the post in the future. That's why Django comes with reverse function. All you need to do is to pass the name of your URL path (defined in your urlpatterns) and Django will find for you the correct URL. It is called reverse because it is a reverse process of determining which view should be called for a given URL (which process is called resolving).
Redirects are not specific to Django or any other web frameworks. Redirect means that for a given URL (or action), the user should be instructed to visit a specific URL. This can be done by sending a special redirect request and from there the browser will handle it for the user, so no user action is required in that process. You can use reverse in redirect process to determine the URL that the user should be redirected to.
GwynBleidD has given you the answer, but there is a reason why you might be getting confused. The Django redirect shortcut accepts arguments in several different forms. One of them is a URLpattern mane, with arguments, that is then passed to reverse to generate the actual URL to redirect to. But that's just a shortcut, to enable a common pattern.
here's an example
app/views
#imports
def indexView(request):
....
return render(request, 'index.html', context)
def loginView(request):
....
return redirect('index')
def articleDetailView(request, id):
....
return redirect(reverse('article-comments', kwargs={'id':id})
def articleCommentsView(request, id):
....
return render(request, 'comment_list.html', context)
proj/urls
#imports
urlpatterns = [
....,
path('', include(app.urls))
]
app/urls
#imports
urlpatterns = [
....,
path('index/', index, name='index'),
path('login/', loginView, name='login'),
path('article/<int:id>/detail', articleDetailView, name='article-detail'),
path('article/<int:id>/comments/',articleCommentsView, name='article-comments')
....,
]
For loginView redirect will return url as-is i.e. 'index' which will be appended to base(project) urlpatterns. Here redirect(reverse('index')) will also work since kwargs is None by default for reverse function and 'index' view doesn't require any kwarg. It returns '/index/' which is passed to redirect(which again will be appended to base urls).
One thing to note is that reverse is used to make complete url - needed for redirect - that is shown in 'articleDetailview'.
The most basic difference between the two is :
Redirect Method will redirect you to a specific route in General.
Reverse Method will return the complete URL to that route as a String.

Django class based views. Use same custom class for different url

I would like to know if it would be possible to create only a custom class for my views in django that could be valid for different urls.
For example:
#urls.py
url(r'^$', CustomClass.as_view(), name='index'),
url(r'^other_url/(?P<example>[-\w]+)$', CustomClass.as_view(), name='other')
#views.py
CustomClass(View):
# for / url
def first_method(self, request):
pass
# for other_url/
def second_method(self, request, example):
pass
I have readed the documentation about class based views, but in the example only talks about a single url...
https://docs.djangoproject.com/en/1.9/topics/class-based-views/intro/
So, I suppose I have to create a class for each url. But it would be possible use the same class with different methods for different url?
You don't need to create different classes for different urls. Although it is pretty redundant to have the same class in different urls, you could do:
url(r'^$', CustomClass.as_view(), name='index'),
url(r'^other_url/(?P<example>[-\w]+)$', CustomClass.as_view(), name='other')
exactly what you're doing. There are some cases where you have a generic class you want to use (either generic from the generics module/package, or generic in the OOP sense). Say, an example:
url(r'^$', CustomBaseClass.as_view(), name='index'),
url(r'^other_url/(?P<example>[-\w]+)$', CustomChildClass.as_view(), name='other')
Or even the same class with only different configuration (regarding generic classes (descending from View): accepted named parameters depend on how are they defined in your class):
url(r'^$', AGenericClass.as_view(my_model=AModel), name='index'),
url(r'^other_url/(?P<example>[-\w]+)$', AGenericClass.as_view(my_model=Other), name='other')
Summary You have no restriction at all when using generic views, or passing any kind of callable at all, when using url.

How do I override `as_view` in class-based views in Django?

I'm trying to introduce class-based views in my project. Looked good so far, until I found the following problem.
I'm using django-navigation to create breadcrumbs. It works like this: a view function gets decorated and this decorator introduces an attribute on that function called breadcrumb. In the template, current URL or its part get resolved and the resulting view get checked for this attribute. If it's there, it's evaluated and the result is the breadcrumb text.
Since class-based views are normally represented by the as_view() method, it seems I would need to decorate it, however, since it's a class method, I can't really access the instance there, which my breadcrumb of course depends on.
Attaching breadcrumb attribute to as_view() in the __init__() didn't work either, or I got the syntax wrong. EDIT: Of course it didn't work, since I attached it to as_view, not to its return value.
Any ideas how to properly integrate that breadcrumb decorator and class-based views?
I've solved this now like this. I've put my breadcrumb routine in a method on a child class and overridden as_view in my base view. Also used a trick from the actual as_view to get a self pointer.
#classonlymethod
def as_view(cls, **initkwargs):
self = cls(**initkwargs)
view = super(MyBaseView, cls).as_view(**initkwargs)
if hasattr(self, 'breadcrumb') and callable(getattr(self, 'breadcrumb', None)):
return breadcrumb(self.breadcrumb)(view)
return view
I guess you could do something like this in urls.py:
the_view = ListView.as_view(...)
the_view = the_decroator(the_view)
urlpatterns = patterns('',
url(r'^$', the_view, name='app_index'),
...
)
The as_view method returns a callable, and that can be decorated. The '#'-syntax is just a shortcut for what is done on line 2.

Django Passing list of objects to template

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