Django, Pass QuerySet to url using redirect/redirect_to - django

How can I redirect from view to another url, passing my queryset to another view?
I tried this:
return simple.redirect_to(request, 'some_url', **{'queryset': results})
and this
return redirect('some_url', queryset=results )
but it does not work....
How can i do it?
Gabi.

How are you expecting this to work? Redirection happens by getting the browser to request another URL. Anything you want to pass as a parameter to the redirection must therefore go into the URL you're redirecting to. It simply doesn't make sense to put a queryset into a URL parameter.
Presumably you could pass whatever arguments you used to get the queryset in the first place, but that's a lot of extra work.
Do you really need to redirect at all? What about simply calling the new view from your original one, and returning its response?

Related

Choosing correct Django delete view approach

I'm working on Django website and I have problem in figuring out correct/good way to handle delete view. From what I found out there are two ways to approach it:
1
class ObjectDeleteView(DeleteView):
model = Object
def get_success_url(self):
objectid = self.kwargs['object_id']
object = Object.objects.get(id = objectid)
container = object.container
containerid = container.id
url = reverse('Containers:showContainerContent', args=[containerid])
return url
def get_object(self):
return get_object_or_404(Object, pk=self.kwargs['object_id'])
2
def objectDelete(request, object_id):
object = Object.objects.get(id = object_id)
container = object.container
containerid = container.id
url = reverse('Containers:showContainerContent', args=[containerid])
return HttpResponseRedirect(url)
From what I can tell both are doing exactly the same thing - once object is deleted present user with page under Containers:showContainerContent.
The big difference I am experiencing is error I am getting when running unit test for this (simple call of the website and check of response code). With option 1 I end up getting error
django.template.exceptions.TemplateDoesNotExist: ContainerApp/object_confirm_delete.html
Which I understand - I don't have this template, this is default template for DeleteView, hence error is correct. The thing is I don't want to have any extra page. Just redirect user and that's it.
Also, I tested changing return url to return HttpResponseRedirect(url) in option 1, but result is the same.
What should I do here? Should I just continue with option 2? What are or might be the drawbacks for this approach?
There is a major difference between two class based delete view and function based view (the way you declared it).
CBV accepts get, post and delete http methods. When you send a get request to class based view, it does not delete the object. Instead it renders template with object to be deleted in context. This is basically used to have confirmation. For example you can send a get request and it will render a template with text "Do you really want to delete?" or "Please confirm blah blah..". And if you send a post or delete request, it will actually delete the object and redirect to next page.
FBV, on the other hand, give you full control over what you want to do. And as you declared it, it will accept any request type and delete the object and redirect to next page because you have not done any request type check in your view which is not a great idea IMHO. You should not allow deletion on get requests. They should be idempotent. There are plenty of otherthings that CBV provides. For example in case the object does not exist your FBV will crash. CBV, on contrary, will return proper 404 response if object does not exist.
So I think there is no bad in using FBV, but make is strong and secure enough that it handles every case (what if object does not exist?, what about confirmation?, GET should be idempotent only allow deletion with post? etc etc). Or simply use CBV.

Passing GET params to a Django View internally

I am trying to call a Django view internally from another view:
response = BlogViewSet.as_view({'get':'list'})(request)
BlogViewSet is actually a rest framework view.
The above code works and I can access response.data but what I actually want to do is pass in some GET params to do some filtering. I tried the following but it didn't work:
response = BlogViewSet.as_view({'get':'list'})(request, my_param=something)
I realise I could modify request to add GET params but it seems wrong to modify it as it might be used later in the view.
You shouldn't ever call the view itself form another view.
You should instead try to extract the meaningful data / code out of the BlogViewSet view and call them directly from the various views.
Calling one view from another is a bad practice.
Why not request url of the view instead of calling the view itself.
r = requests.get("<url_to_access_view>", params={})

Can I pass non-URL definition view keyword to a view function when redirecting?

NoReverseMatch at /natrium/script/4c55be7f74312bfd435e4f672e83f44374a046a6aa08729aad6b0b1ab84a8274/
Reverse for 'run_details' with arguments '()' and keyword arguments '{'script_text': u'print "happy"', 'run_id': '6b2f9127071968c099673254fb3efbaf'}' not found.
This is an excerpt of my views.py
run_id = new_run.run_id
if not run_id:
raise AssertionError("bad run id")
# I tried with args=[run_id, clean['script_text']] too
return HttpResponseRedirect(reverse('run_details', kwargs={'run_id':run_id, 'script_text':clean['script_text']}))
which in turns calling this view function
def run_details(request, run_id, script_text):
"""
Displays the details of a given run.
"""
run = Run(run_id)
run.update(request.user)
codebundle = CodeBundle(run.cbid)
codebundle.update(request.user)
return render_response(request, "graphyte/runs/run_script.html",
{'run':run, 'codebundle':codebundle, 'files':run.artifacts, 'bundle':codebundle,
'source_code': script_text
})
Now this is my urls.py. The actual redirect views is in another app (kinda insane, but whatever...).
urlpatterns = patterns("webclient.apps.codebundles.views",
# many.....
url(r"^cb/newfolder/$", 'codebundle_newfolder', name="codebundle_newfolder"),
)
urlpatterns += patterns('webclient.apps.runs.views',
url(r"^run_details/(?P<run_id>\w+)/$", 'run_details', name="run_details"),)
This is getting really nasty for the last three hours. I am not sure what's going on. Can someone help me debug this?
Thanks.
The original plan did not have script_text, and I used args=['run_id'] only. It works. In other words, remove script_text from the two views everything will work.
EDIT
Sorry for the confusion. Script text is just a context variable that I need to pass to the reverse destination, and from there I render my template. The URLs should only display the run_id.
No, you can't really pass an 'extra keyword' to the view function when redirecting. I'll try to explain why.
When you return HttpResponseRedirect, Django returns a response with a 302 status code, and the new location.
HTTP/1.1 302 Found
Location: http://www.example.com/new-url/
Your browser will then usually fetch the new url, but that's a separate request. If your view needs a keyword, it needs to be included in that response somehow, unless you store state in the session. Your two options are
Include the extra keyword in the url:
http://www.example.com/new-url/keyword-value/
Include the extra keyword as a GET parameter
http://www.example.com/new-url/?keyword=keyword-value.
Then in your view, grab the keyword with keyword=request.GET['keyword']. Note that the keyword is no longer a kwarg in the view signature.
A third approach is to stick the keyword into the session before you redirect, then grab it out the session in the redirected view. I would advise against doing this because it's stateful and can cause odd results when users refresh pages etc.
Your run_details url doesn't accept a kwarg named script_text at all -- remove that from your reverse kwargs.

Passing a variable in redirect in Django

I'm trying to pass a variable using the redirect function, but it is returning none.
def one:
# define location variable here
return redirect(getting_started_info, location=location)
def getting_started_info(request, location=''):
location = location
...
Could someone please tell me why the variable in the redirect is not passing?
Remember that redirect() isn't doing a direct call to your view, it's actually sending the client's browser a 302 Found status (301 Moved Permanently if you use permanent=True) with an instruction to redirect to a different URL. In this case, that URL is one that resolves to the getting_started_info view.
I believe that for this to work, there must exist a urlconf which maps to getting_started_view and which uses its location positional argument. This will most likely occur through named groups.
From the django 1.8 docs entry on redirect():
The arguments could be:
A model: the model’s get_absolute_url() function will be called.
A view name, possibly with arguments: urlresolvers.reverse will be used to reverse-resolve the name.
An absolute or relative URL, which will be used as-is for the redirect location.
return HttpResponseRedirect(reverse('getting_started_info', kwargs={'location': location}))
you may also pass a value of some variable using sessions or cookie.

Django URL match in HttpResponse object?

In django, when a URL is matched, the match group is passed as a second parameter to the view function, the first being a HttpRequest object. For example, with a URL patter like this
'/foo/(\d{2})/', 'app.views.handler'
the handler routine will have
def handler(request, value):
where value will contain a two digit number (as a string).
My question is: is value also contained in the request object, and if yes, how can I get it (of course, parsing the URL from the request object is not an option, too impractical).
Thanks
I'm not going to debate the merit of your idea. Just try to answer your question:
No there is no way, other than applying the regex to the URL again, to get at the url parameter.
Your view will be the first point where the parameter list will be available. Why don't you just create a wrapper object to encapsulate your request and your parameter list at that point?
Just pass that around...
Can you give any reason why you would need this?
I don't see why parsing the url path is 'impractical', given that you've already got a regexp that works, in your urlconf.