When should I use a lazy function in Django - python

I am starting out with django and I have come across functions like reverse_lazy instead of reverse and gettext_lazy instead of gettext for translation.
From the information, I could get online, it seems that these lazy functions only call the original functions when they are to be used and not immediately they are declared.
What exactly does this mean and in what real life coding senerios should I use the lazy version as against the original function.
Thanks a lot in advance

This is the sort of thing that is only needed per-specific-situation, as you've intuited yourself.
A common example is with Generic Class-based Views. The attributes of the view are evaluated when the views.py file is read. But at the time it's being read, the urls file will not have been read yet! So assigning to an attribute with reverse() will fail, because any url named in the arguments sent to reverse() will not be available to the view file. But with reverse_lazy(), you can assign a url to an attribute in the class-based view, and it will not be updated until the named url is actually available:
class RegisterView(CreateView):
form_class = CustomUserCreationForm
success_url = reverse_lazy('index') # reverse() would fail here!
template_name = 'registration/register.html')
Again: success_url is an attribute of the view, and will be evaluated when the views.py file is read. But at that time, the urls will not have been read, so 'index', a named url, will not be available yet. We use reverse_lazy() instead of reverse() to get around this problem; 'index' is not evaluated until it's actually needed, and now we can define our attribute as desired.
Note that if your view has a user-defined method, you can use the normal reverse() call inside the method, if needed, because unlike view attributes, a view's methods are not evaluated until the method is explicitly called -- and by that time, the urls will be available.
There are other use cases, for sure, but CBV's are a common case where reverse_lazy() becomes necessary, specifically when assigning urls to attributes.

Related

Generic views for updating objects?

How do I rewrite the function-based view that only updates an object into a class-based view? Something like this (wrote this for a tutorial).
from django.contrib.auth.decorators import permission_required
#permission_required("catalog.mark_returned")
def mark_returned(request, pk):
bk = BookInstance.objects.get(pk=pk)
if bk.status == "a":
#some tests here
bk.status = "a"
bk.due_back = None
bk.borrower = None
bk.save()
return redirect("on-loan")
And in general, does it make sense to use generics for things like that?
Because currently, I only use the generic list and detail views.
Sorry for beginner-level questions:)
It's a view without a template or a form; that kinda excludes the usefulness of just about every generic view except the basic View class itself.
You would override the ClassBasedView's dispatch method (since the request method does not matter) with the logic of your function view.
The pk value can be accessed through self.args[0] or self.kwargs['_name_of_captured_variable_here'].
Does it make sense? In general, I would say becoming familiar with CBVs and especially the generic ones will do you good in the long run. In your special case, however, you gain or lose nothing by using a CBV over function view. The view is just too simplistic.

where to define a slug without a model.py in Django

I am rather new to django, and am looking at where to define a slug in django when creating a backend without models. the url is created as such:
url(r'^main/(?P<slug>[-\w]+)/', include('main.urls')),
I have slugs within my main.urls which I define inside of each view function. Im not exactly sure where to define this slug(link, whatever you may call it). On other django slug examples, the common way is in a model, and I am currently talking to a program rather then creating my own models.
Would this be in the urls.py, or views.py (in the project, not app)?
Thank you so much. Hopefully this is understandable.
It's not hard. Really.
In url-configs each entry is simply a regular expression which has to match a url that is visited by an end user. r'^main/(?P<slug>[-\w]+)/' will for example match with: http://localhost:8000/main/some-slug/
You can use a special kind of syntax in your regular expression to extract matched data and pass that data as a variable to your view function.
The bit that does that is (?P<slug>[-\w]+) it puts matched words (in this case a slug) into a variable called slug (the <slug> part, it defines the variable name). In this humble example the slug variable will be set to "some-slug".
The variable will be accessible in your view like this:
from django.http import HttpResponse
def handle_my_view(request, slug=homepage):
# do stuff with slug
return HttpResponse("I did stuff with slug: {}".format(slug))
Learn more about, and fiddle with regular expressions
At http://www.regexr.com
But why do i see slugs used in models?:
A slug (or named variable, coming from a url 'interception') can be used for anything. Commonly the slug variable itself will be used to retrieve a database record of some sorts... And that involves using models.
You can do whatever you want with them; add stuff, subtract stuff, capitalize, whatever. The sky is the limit.
From the Django docs:
https://docs.djangoproject.com/en/1.10/topics/http/urls/#named-groups
Named groups
The above example used simple, non-named regular-expression groups (via parenthesis) to capture bits of the URL and pass them as positional arguments to a view. In more advanced usage, it’s possible to use named regular-expression groups to capture URL bits and pass them as keyword arguments to a view.
In Python regular expressions, the syntax for named regular-expression groups is (?Ppattern), where name is the name of the group and pattern is some pattern to match.
Here’s the above example URLconf, rewritten to use named groups:
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^articles/2003/$', views.special_case_2003),
url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),
url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive),
url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]{2})/$', views.article_detail),
]
This accomplishes exactly the same thing as the previous example, with one subtle difference: The captured values are passed to view functions as keyword arguments rather than positional arguments. For example:
A request to /articles/2005/03/ would call the function views.month_archive(request, year='2005', month='03'), instead of views.month_archive(request, '2005', '03').
A request to /articles/2003/03/03/ would call the function views.article_detail(request, year='2003', month='03', day='03').
In practice, this means your URLconfs are slightly more explicit and less prone to argument-order bugs – and you can reorder the arguments in your views’ function definitions. Of course, these benefits come at the cost of brevity; some developers find the named-group syntax ugly and too verbose.

Django URL to View mapping

I have a viewset and some methods in it and getschedule is one of them.
def getschedule(self, request):
In the urls.py if I map the method getschedule like this
url(r'^event/(?P<pk>[0-9]+)/getschedule/$', EventSingleViewSet.getschedule, name='event-schedule'),
I get this error "getschedule() missing 1 required positional argument: 'request'
"
But if I do the mapping like this,
url(r'^event/(?P<pk>[0-9]+)/getschedule/$', event_getschedule, name='event-schedule'),
......
event_getschedule = EventViewSet.as_view({
'get': 'getschedule'
}, renderer_classes=[JSONRenderer])
it works and gives me a response.
I don't understand how the request is getting passed to the method in the second approach. Need help understanding this.
I would also like to know how i could make my first approach work.
If your viewset already is tied to a router then you can use
#detail_route, or #list_route to point it to a url with the name of your viewset method.
Check this part of documentation : http://www.django-rest-framework.org/tutorial/6-viewsets-and-routers/
Otherwise, it would make sense to use plan view class extending APIView and pointing a URL to it.
Viewsets are mainly useful when tied to a router.

Django - how to pass object to a template with a class based view?

I'm switching over to class based views in my project for most of my views just because they are less repeated code, and I can't figure out how to pass an object to a template. By default using a detail view passes the object, which is fine for accessing direct attributes of it, but my objects have tags on them that are defined via an extension and accessed via a function of that extension. In my old function based view, I would get the list of tags and pass it to the template like this to be iterated over:
return render(request, "gallerypage.html", {
'gallery': gallery,
'tags': gallery.misc_tags.names(),
'form': form
})
My new view looks like this:
class GalleryView(DetailView):
model = Gallery
template_name = 'gallerypage.html'
urls.py:
urlpatterns = patterns('',
url(r'^(?P<pk>\d+)/$', GalleryView.as_view(), name='show_gallery'),
url(r'^(?P<pk>\d+)/edit/$', GalleryUpdate.as_view(), name='update_gallery',),
)
The gallery object is passed to the template fine, and I can access attributes of it, for example the name, by using something like <h1>{{ object.name }}</h1>. But seeing as it isn't a good idea to try running arbitrary Python code in templates, I need a better way to pass the tags object into the template so I can display them, as something like
{{ object.misc_tags.names()|join:", " }}
right in it will not work. Thanks
You could override get_context_data and add any additional context you want. This method is often overriden in CBV's
Calling object.misc_tags.names without the parentheses would implicitly call the function. Alternatively use get_context_data like dm03514 had suggested.
From the django docs on periods in templates:
Technically, when the template system encounters a dot, it tries the following lookups, in this order:
Dictionary lookup
Attribute lookup
Method call
List-index lookup

Django Contect_processor reversed list

I'm working with django and trying to make a context_processor who´s going to make a list of newsposts which can be shown in my base template. My code look like this.
from news.models import Post
def get_news_title(request):
return{
'get_news_title': Post.objects.all().reverse()[:5]
}
But still it just show my first 5 newsposts...
Any tips?
Django docs say explicitly that
reverse() should generally only be called on a QuerySet which has a
defined ordering (e.g., when querying against a model which defines a
default ordering, or when using order_by()). If no such ordering is
defined for a given QuerySet, calling reverse() on it has no real
effect (the ordering was undefined prior to calling reverse(), and
will remain undefined afterward).
so you need to use order_by('some field here').
For example:
Post.objects.order_by('id').reverse()[:5]
See docs for order_by()

Categories