I was looking at some different code on github and came across something that was confusing. Is there any differences between the code below?
class RandomView(View):
def get(self, *args, **kwargs):
return render(self.request, 'random_template.html)
Versus
class RandomView(View):
def get(self, request, *args, **kwargs):
return render(request, 'random_template.html)
To me this would do the same thing but to be fair my knowledge is pretty limited. Is one considered bad practice? Or maybe just preference?
They point to the same object. self.request is assigned in the factory
function that is returned from View.as_view(). I would guess that the
reason for passing the request argument explicitly is to make it
easier to convert between class based views and function views. And it
also makes it more clear that methods such as get uses the request
object.
I recommend that you follow the convention from the django source code
and examples in the docs, and use the request that is passed as an
argument instead of self.request.
found this answer on reddit
Related
I need to move the request.POST parameters to the request.query_params QueryDict.
Is there an accepted way of doing this?
Background
I am using datatables, with a DRF backend, which is working fine. I am moving the application to integration and ... it stops working. Why? Request URL too big (on the 7000 characters range) - which was not a problem in my dev host ...
So, I am looking for a solution to that problem. The first solution is to use POST instead of GET. That works, but the library integrating DRF with datatables is not processing the form parameters of the POST request. Because of that, filtering, pagination and so on have stopped working.
The easiest thing to solve this would be to put the form parameters into the query parameters, and let the backend process the request as if it was a normal GET request.
This is what I am doing at the moment:
class DataViewSet(viewsets.ModelViewSet):
queryset = Data.objects.all()
serializer_class = DataSerializer
def create(self, request, *args, **kwargs):
# DataTable uses a lot of parameters which do not fit into a normal URL. To get the data we need to do POST,
# so that the parameters are sent in the body
# We hijack the create method to list the data
return self.list(request, *args, **kwargs)
I'm not aware of any accepted ways of doing this. But let me offer you an idea. It is probably on the opposite side of what accepted means.
The rest_framework.request.Request.query_params look like this:
#property
def query_params(self):
return self._request.GET
Im thinking about substituting the self._request.GET with self._request.POST
class DataViewSet(viewsets.ModelViewSet):
queryset = Data.objects.all()
serializer_class = DataSerializer
def create(self, request, *args, **kwargs):
# DataTable uses a lot of parameters which do not fit into a normal URL. To get the data we need to do POST,
# so that the parameters are sent in the body
# We hijack the create method to list the data
request._request.GET = request._request.POST
return self.list(request, *args, **kwargs)
This should work for POST data. Sending files to this endpoint is probably bad idea.
NOTE: This is very fishy and could introduce bugs in the future. Without look into your code i cannot predict the side effects.
Hi I want to understand this line of code:
return super().get(request, *args, **kwargs)
This line is part of a method in class based view in views.py file , for example
class HomePage(TemplateView):
template_name = "index.html"
def get(self, request, *args, **kwargs):
if request.user.is_authenticated:
return HttpResponseRedirect(reverse("afterlogin"))
return super().get(request, *args, **kwargs)
I know this method will check if the current user is authenticated and redirect to a different tempalte (afterlogin) in this case if a user is logged in , otherwise it will stay in index.html and then this function will execute this line return super().get(request, *args, **kwargs) anyway {I don't understand this line} .for example, if we were redirect to afterlogin page for example,then what this last line will do then?? .. this is the general idea that I understand but I want to understand the details of the code like:
If anyone can explain:
1- why I have these parameters: (self, request, *args, **kwargs) in get function?
2- when this method : def get(self, request, *args, **kwargs): will be triggered or called?
3-
explain the last line in the get method: return super().get(request, *args, **kwargs) step by step and what is its purpose.
I will be grateful if anyone can explain in details because I am still learning.. Thanks a lot
The super() function represents the parent class of the current one (in this case, this means TemplateView).
In your code, this means that get() will, as you noted, first check if the user is authenticated; if it is, then it will redirect to the afterlogin URL. If the user is not authenticated however, the function will not return, so it will go on and call the get() method of TemplateView (with the same arguments that have been passed to your get()), that will output whatever it would normally output if you hadn't inherited it.
To see what exactly that would be, you can navigate to TemplateView in the source code and read its get() method.
About your second question: when a user navigates to a URL you defined in your project, Django will check the method used for the request (if they're just viewing the page for the first time, this will be GET; another example is POST, which you probably heard before) and call the method of your view (HomePage) with the corresponding name, get(). If you also define a post() method, that will be called when the user requests the page with a POST method, for example by submitting a form with the method="post".
About your first question: request is an HTTP request object that is passed to the function to basically tell them what the user('s browser) has requested, what it wants to do. *args is a list of all other positional arguments that might have been added to the get() call. The same states for **kwargs, which is instead a dictionary of keyword arguments. These can very well be empty, but it's good that we pass them on to the upper level so that we don't loose any functionality that may be needed.
Just as an example, if you go to a url like mysite.com/page/search?=myquery, this would be a GET request, and it would include a keyword argument with key search and value myquery, so your **kwargs would look like: kwargs = {"search": "myquery"}. In the same way, the contents of a form submitted by POST would be available to your method to do what you need to do with them.
I have a model that looks something like:
class DooDad(models.Model):
doo_dad_dogue = models.BooleanField(default=True)
Trouble is, that default needs to be manipulated by... stuff that is irrelevant to this question. If I were creating the form that creates the object, the solution would be trivial. I'm still using the django default form for creating these things, though, and I'd rather keep it that way.
I tried the obvious:
class DooDad(models.Model):
doo_dad_dogue = models.BooleanField(default=True)
def __init__(self, *args, **kwargs):
super(DooDad, self).__init__(*args, **kwargs)
self.doo_dad_dogue = False
...which I suspect would have terrible side effects, but was worth experimenting with. The form still comes up with the box checked.
EDIT: I should have mentioned that this is Django 1.9
If it is not possible to continue using the default model creation form, is there anything unusual that I need to do to to make a ModelForm that only impacts CREATE, and not EDIT?
I do not think using the __init__in model is a good practice. However, if you want to try it is important to know that your code is not correct one the field doo_dad_dogue is a descriptor. The correct way to access it is
using self.fields['doo_dad_dogue'] = False.
Using a form is the correct way to do that. You can override the default value in the Form by using the init method:
def __init__(self, *args, **kwargs):
super(<YOUR_FORM>, self).__init__(*args, **kwargs)
if args is not None and len(args) and args[0] is not None:
<MANIPULATE HERE>
Hope that helps.
Is there a way to stop execution and return an httpresponse in a function other than post, get, put?
So for example
class MyClass(View):
def post(self, request, *args, **kwargs):
test_some_things()
do_some_other_stuff()
return HttpResponse(..)
def test_some_things(self):
if test_fails:
return HttpResponse(..)
else:
return 1
I want to be able to end execution if test_fails and just return the response. But the above doesn't seem to work...
Although possible, it clearer to separate these things: have one method that tests things and returns the outcome of that (boolean). Then, check whether the tests succeeded and return the response in the view.
This will make your code a lot easier to maintain and test in the long run.
What your propose is possible but it won't lead to the simplest solution to this situation.
With function based Django view it was simple to switch between several different views based on a condition, e.g. something like:
def base_view(request):
if some_condition():
return foo_view(request)
else:
return bar_view(request)
I can't find a simple way to do the same with the new class-based generic views. The only way I can think of is to redisrect, which I would like to avoid for various reasons:
def base_view(request):
if some_condition():
return redirect(reverse("name_of_url_to_class-based_view_foo"))
else:
return redirect("/url_to_class-based_view_bar/")
Any suggestions?
This is equivalent to your example with class based views.
class FooView(View):
pass
class BarView(View):
pass
class BaseView(View):
# staticmethod to avoid adding 'self' to the arguments
foo_view = staticmethod(FooView.as_view())
bar_view = staticmethod(BarView.as_view())
def dispatch(self, request, *args, **kwargs):
if some_condition():
return self.foo_view(request, *args, **kwargs)
else:
return self.bar_view(request, *args, **kwargs)
Even though the Django docs do say that the function based generic views are now deprecated I think the only reason to switch would be if you're writing less code.
If you're still set on switching, you'll want to first identify which class based views or mixins are most appropriate (single object, multiple objects, date based, forms, etc.). If the conditional was used to select a function that returns different context data / template to provide to the view, you can push the conditional down into an overridden get_queryset|get_context_data|get_object|get_template_names depending on your use case.
For example,
def get_context_data(self, **kwargs):
# Call the base implementation first to get a context
context = super(BaseView, self).get_context_data(**kwargs)
# Add in the publisher
if some_condition():
context['some_data'] = ...
else:
context['other_data'] = ...
return context
If all else fails and you're still determined to have class based views, you could probably also override get(self, request, *args, **kwargs) and do the switching there to the appropriate method. The detailed docs are getting better but I've still found myself poking through the source code to figure out how to accomplish what I want.