Django: Generic views based 'as_view()' method - python

I was working on an application wherein I created a generic ListView. Now, while defining that view in my urls.py, I read from the documentation that I need to use the as_view() method as follows:
from django.conf.urls import patterns, include, url
from .views import BlogIndex
urlpatterns = patterns(
'',
url(r'^$', BlogIndex.as_view(), name="index"),
)
Now, I didn't really understood what the documentation had to say about this method. Can someone shed some light into this concept?

In Class-based views, you have to call as_view() function so as to return a callable view that takes a request and returns a response. Its the main entry-point in request-response cycle in case of generic views.
as_view is the function(class method) which will connect my MyView class with its url.
From django docs:
classmethod as_view(**initkwargs)
Returns a callable view that takes a request and returns a response:
You just can't use class-based views like you could in normal function-based views.
BlogIndex(request) # can't do this in case of CBVs
The above code is not valid if you want the CBVs to function properly. For that, you need to provide a view which is callable and then pass request to it. For example:
response = MyView.as_view()(request) # valid way
By calling the as_view() function on my view class MyView will give me a view which i will call with request parameter to initiate the request-response cycle.
In your case:
my_callable_view = BlogIndex.as_view() # returns a callable view
<function blog.views.BlogIndex>
Now, call this function and pass the request.
response = my_callable_view(request) # generate proper response

view function have different format than before because :
This view will actually be implemented as a class
We will be inheriting from an existing generic view function that already does most of what we want this view function to do, rather
than writing our own from scratch.
Class method as_view()- this does all the work of creating an instance of the class, and making sure that the right handler methods
are called for incoming HTTP requests.
ref : https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Generic_views

Maybe I can try to write the as_view with pseudo-code:
class ViewClass():
#other stuff
def as_view(self):
return self.render(*args)
It return the render function inside the CBV.
So it actually is the same as path('some_path',views.some_view_function,name='some_name')
Of course, there there is actually much more things going on than only render function, for example to verify and save the content inside post queryDict, actually you need def post(): to handle the post, in function you just if request.method == 'POST' they are actually mutual.
To be specific, as_view() just generate a overall function, including if request.method =='POST': #some code Maybe the actual code doesn't work like that, but you could understand it this way if you are not prepared to contribute to django source code yourself.

Related

How to get serialized API view data into another view?

What is the best way to get DRF API view data into another Django view?
Currently I am just calling the view through requests module:
response = requests.get('my_api_view')
but is there a cleaner way?
I can also just instantiate the API view class in another view, but this will give me unserialized objects.
Not sure what you mean by getting unserialized objects. You can do the following if you're using function-based views:
def view(request):
# some stuff done
return Response(<result>)
def another_view(request)
return view(request)
If you're views are class based then you can do the following:
class AClassBasedView(SomeMixin, SomeOtherMixin):
def get(self, request):
# do something with the request
return Response(<some result>)
class AnotherClassBasedView(SomeMixin, SomeOtherMixin):
def compute_context(self, request, username):
#some stuff here here
return AnotherClassBasedView.as_view()(request)
Both of these will return a <class 'rest_framework.response.Response'> object which can be passed further.
I'm not sure what exactly you want to achieve but wanting to call a view from another view maybe a sign of bad architecture. It could mean that you have a business logic implemented in the second view which you want to access in the first. Usually the rule of thumb is to move such a common logic somewhere else so it could be used by different views.
Again I don't know what you want to achieve but this is a possibilty.

how to get the url of the view calling the decorator in the decorator?

In a django app I have a decorator called my_dec , I want to use the url of the view that is calling the decorator in the decorator, for example if the code of view is like this :
#my_dec(key)
def my_view
pass
I want something like this :
def my_dec(key)
print #url of "my_view"
how can I access the url of my_view or any other view that is calling the decorator?
Assuming you're using function based views.
In your decorator you can access the request object of your function view.
Here's an example code
def my_dec(func):
def wrapped(request):
print request.path_info
return func(request)
return wrapped
And then you can use this decorator on a view like this:
#my_dec
def my_view(request):
return HttpResponse(...)
This example simply prints out the url associated with your view.
Note that in your view you have access to the entire request object and can fish out any information you want.
This example works on function based views but can easily be modified to work on class-based views as well

Restrict Pages/URLs to Admin only in Flask

In GAE, restrict certain urls to Admin only is quite easy:
- url: /admin/.*
script: admin.app
login: admin
Now I am using Flask. I have to repeat the same code in every admin only function to tell if a user is admin, which makes the code long and redundant.
#app.route('/admin/somepage')
def AdminPage():
#Figure out if a user is admin
Is there some better way to do that?
You could use a app.before_request() hook to inspect the request and respond with a redirect when the requested path starts with /admin/ but authentication information is missing or insufficient.
def check_for_admin(*args, **kw):
if request.path.startswith('/admin/'):
if not user.is_admin():
return redirect(url_for('login_form'))
By returning a response object (such as produced by the flask.redirect() function from a before_request handler stops processing and the actual view is not invoked.
You can also use a decorator to mark admin views; this is more flexible (routes don't need to be all under one path) and more discoverable (each route has the decorator on it).
your AdminPage() should be a class inheriting from flask_admin BaseView, and you override the method is_accessible, like this:
from flask_admin import BaseView
class AdminPage(BaseView):
def is_accessible(self):
return current_user_is_admin()
#expose('/', methods=('GET', 'POST'))
def do_whatever(self):
# do it
return self.render("admin/whatever.html")
of course, your user class need to have a method (in the example it's called current_user_is_admin()) which evaluates True only if the current user is an administrator. You need to have this information anyway, regardless the way you implement this.
This is the proper way to use flask_admin, as far as I understand. You can define as complex, or as simple, permission rules as you like, per every admin function, just by changing the is_accessible() override.

Django class-based view

Django
Following the official documentation, I am creating a Django app (the same poll app as in the documentation page). While using the class-based view, I got a error. I did not understand much about class based view, for instance, may someone explain, what is the difference between a class based view from a normal view?
Here's my code:
class DetailView(generic.DetailView):
model = Poll
template_name = 'polls/details.html'
def get_queryset(self):
def detail(request, poll_id):
try:
poll = Poll.objects.get(pk=poll_id)
except Poll.DoesNotExist:
raise Http404
return render(request, 'polls/details.html', {'poll': poll})
*********************Error ********************
TypeError at /polls/2/results/
as_view() takes exactly 1 argument (3 given)
Request Method: GET
Request URL: <app-path>/polls/2/results/
Django Version: 1.5.1
Exception Type: TypeError
Exception Value:
as_view() takes exactly 1 argument (3 given)
*****the url***
url(r'^(?P<pk>\d+)/$', views.DetailView.as_view, name='detail')
as_view should be called, not referenced, according to the docs, your url should look like:
url(r'^(?P<pk>\d+)/$', views.DetailView.as_view(), name='detail')
Note the usage of parenthesis.
Also, you should rather call your class PollDetailView to avoid confusion for code readers.
Also, the detail() method you have defined will not be called at all. So you shouldn't define it at all. Also, leave the get_queryset() method alone for the moment, try to get the basic View to work first.
When you use url for the CBV ensure that you can not use the reference of the of the url filed, so first you need to add change the as_view to as_view().
And you can use DetailView like this.,
class PollDetail(DetailView):
model=Book
def get_context_data(self,*args,**kwargs):
context=super(PollDetail,self).get_context_data(*args,**kwargs)
print(context) #It will give you the data in your terminal
return context
And for accessing data you need to use {{object}},
and if you want to access other fields at that time use like this {{object.fieldname}}
In CBV the template name is automatically named as per class name so you don't need to give it.
Note:Don't give class name same as DetailView,In future you will confuse.
Since you are not modifying the view functionality, to use this generic view, you can simply do this:
in your urls.py (along with other stuff):
from django.views.generic.detail import DetailView
from poll.models import Poll
url(r'^(?P<pk>\d+)/$',
DetailView.as_view(model=Poll,
template_name='polls/details.html'), name='detail')
Then in poll/details.html, you just need:
{{ object }}

cookie should be constructed first

I will call cookies before all web page. For this reason, I should create value key before all of the page or module is called. Before any of the page is called, cookie should be constructed first, for my case. How can I manage this? Where should I put request.session['id']=Null so that it will called first before any other page is called?
You need to write a custom decorator to handle the situation.
You can read more about Decorators here: https://docs.djangoproject.com/en/dev/topics/http/decorators/
For example the csrf_exempt decorator allows a request to be processed without the csrf token facility in forms, very useful for JSON based requests.
#csrf_exempt
def new(request):
if request.method == 'POST':
json_data = simplejson.loads(request.raw_post_data)
try:
Similarly have a custom decorator for ensuring cooking and use it as:
#ensure_cookie
def new(request):
...
Writing custom decorators: How to write a custom decorator in django?
You can put this code in process_request or process_view method in custom middleware.

Categories