get a variables by GET in method get in DetailView django - django

Im trying to get the variable "segundos" by GET in the Detail View, im trying to get it by the method get:
the js file:
$(document).ready(function(){
var segundos=340;
console.log(segundos);
$.ajax({
data : {'segundos':segundos},
url : '/ajax/puzzle-1/',
type : 'GET',
});
});
views.py
class PuzzleView(DetailView):
model = Puzzle
template_name = 'puzzle.html'
def get (self,request,*args,**kwargs):
seconds = request.GET["segundos"]
self.object = self.get_object()
ranking = Ranking.objects.create(puzzle_id=self.object.id,usuario=self.request.user,segundos=seconds,puesto=89)
context = self.get_context_data(object=self.object)
return self.render_to_response(context)
class RankingView(ListView):
model = Ranking
template_name = 'ranking.html'
queryset = Ranking.objects.filter(puzzle_id=1).order_by('segundos')[:3]
class PuzzleAjaxView(TemplateView):
template_name = 'ranking.html'
But i get the famous error "MultiValueDictKeyError". If i try the same method "get" but with a TemplateView, i can get the variable, but not with DetailView
Just in case, my urls.py:
urlpatterns = patterns('puzzle.views',
url(r'^actividad/puzzle/(?P<slug>[-_\w]+)/$',PuzzleView.as_view(),name='puzzle'),
url(r'^ajax/puzzle-1/.*$', PuzzleAjaxView.as_view(),name='ajax'),
url(r'^ranking/.*$', RankingView.as_view(),name='ranking'),
)

seconds = request.GET("segundos")
You can't just call the GET MultiValueDict. You must access by dictionary lookup. It is a subclass of a dict.
request.GET.get('segundos')
request.GET['segundos']
Update
For future reference, your exception traceback would have explained all of this, but the error message should be pretty clear: something along the lines of segundos not being a valid key in the MultiValueDict.
I assume your PuzzleView (what you are calling the DetailView) never gets passed any GET parameters because your example shows GET params only with your AJAX call, which is mapped to your PuzzleAjaxView (what you are calling the TemplateView
What is determining whether or not your get function works or not isn't based on the fact that your view class is a TemplateView or DetailView, it's the fact that segundos is only passed to your AJAX view.
In other words.. any view (TemplateView, DetailView, doesn't matter) accessing a GET dict via direct lookup request.GET['foobar'] will fail if that get parameter isn't passed in.

Related

django get parameters and pass int type

I have the below entry in urls.py
url(r'^profile/(?P<price_id>[0-9]+)$', views.profile_view, name='profile'),
Where the price_id parameter is generated by the below template snippet:
'Proceed'
This is rendered by the below view:
class QuotesResultsView(ListView):
template_name = 'pages/quotes_results.html'
paginate_by = 20
context_object_name = 'quotes_results'
def get_queryset(self):
session = self.request.session
quotes = get_quotes(session) # return iterable from external api
quotes_results = quotes['searchResults']
return quotes_results
When the button is clicked in the rendered template it passes (via the url to the below view):
def profile_view(request, price_id):
request.session['price_id'] = int(price_id)
....
However the price_id parameter arrives in the view as a string eg '8234234' instead of an int which I have to covert. In the earlier QuotesResultsView the price_id is an int within quotes_results, but between then and it appearing in the next view its a string? Do GET parameters always get passed as strings?
Yes, the arguments coming from a URL are always strings, and it is your responsibility to cast them appropriately. The get_quotes may return a structure that contains an integer price_id, but it is obtaining that value through a different mechanism than the URL call.
The price_id in profile_view will always come in as a string when called by the URL configuration.

Django CBV - dealing with optional parameters in URLs

I have a Class Based View to list animals from a specific herd. There are multiple herds, so the user can either see all animals from ONE herd, or all animals from ALL herds.
How do I have an optional URL parameter and handle it in the CBV?
urls:
url(r'list/(?P<hpk>[0-9]+)/$', AnimalList.as_view(), name = 'animal_list'),
url(r'list/$', AnimalList.as_view(), name = 'animal_list'),
My view:
class AnimalList(ListView):
model = Animal
def get_queryset(self):
if self.kwargs is None:
return Animal.objects.all()
return Animal.objects.filter(herd = self.kwargs['hpk']) # <--- line 19 that returns an error
Going to a URL of like /animals/list/3/ works fine, while /animals/list/ fails with an error. Here's that error:
KeyError at /animals/list/
'hpk'
Request Method: GET
Request URL: http://localhost:8000/animals/list/
Django Version: 1.8.2
Exception Type: KeyError
Exception Value:
'hpk'
Exception Location: /var/www/registry/animals/views.py in get_queryset, line 19
I get that the self.kwargs is a dictionary, and when I print() it inside the view, it'll show it's empty. But I can't figure out how to capture that scenario. I feel like this is a simple, stupid error I'm missing.
To anyone who may stumble on this and need an answer, here is my working code after figuring it out:
class AnimalList(ListView):
model = Animal
def get_queryset(self):
if 'hpk' in self.kwargs:
return Animal.objects.filter(herd = self.kwargs['hpk'])
return Animal.objects.all()
Essentially we test to see if the URL parameter hpk is present in the list of self.kwargs. If it is, we filter the queryset. Otherwise, we return all animals.
Hope this helps someone :)
I would implement this using GET parameters instead of separate URLs. With this approach, there is only one URL /list/ that is filtered by parameters, for example /list/?hpk=1.
This is more flexible as you can eventually add more queries /list/?hpk=1&origin=europe
#url(r'list/$', AnimalList.as_view(), name = 'animal_list'),
class AnimalList(ListView):
model = Animal
def get_queryset(self):
queryset = Animal.objects.all()
hpk = self.request.GET.get("hpk"):
if hpk:
try:
queryset = queryset.filter(herd=hpk)
except:
# Display error message
return queryset

Get a list of objects in tastypie (in another view)

I'm trying to get a tastypie response to use in another view. I've seen the recipe in the cookbook. Problem is, I'd like to get the list view. In my case, /api/v1/source/. Here's what I've got so far:
sr = SourceResource()
objs = sr.get_object_list(request) # two objects returned
bun = sr.build_bundle(data=objs, request=request)
jsondata = sr.serialize(None, sr.full_dehydrate(bun), 'application/json')
Of course this all falls apart. bun.data doesn't have the required characteristics (a single object). So, has anyone done this successfully? How is it done?
Here's what I've come up with. I don't especially like that both the request and the QueryDict are copied, but I can't think of anything else at the moment, other than copying big portions of the tastypie code.
from copy import copy
from django.views.generic import TemplateView
from incremental.sources.resources import SourceResource
resource = SourceResource()
class AppView(TemplateView):
'Base view for the Source parts of the app'
template_name = 'sources/base.html'
def get_context_data(self, **data):
'get context data'
tmp_r = copy(self.request)
tmp_r.GET = tmp_r.GET.copy()
tmp_r.GET['format'] = 'json'
data.update({
'seed': resource.get_list(tmp_r).content
})
return data
In order to avoid the request copying stuff, you can set json as the default format, for instance in your Resource you can overload the following method:
SourceResource(Resource):
def determine_format(self, request):
return "application/json"

django form: Passing parameter from view.py to forms gives out error

Newbie question:
I need to accept a parameter in a form from a method in views.py but it gave me troubles. In the view I created a method with following snippet:
def scan_page(request):
myClient = request.user.get_profile().client
form = WirelessScanForm(client = myClient) # pass parameter to the form
and in the forms.py I defined the following form:
class WirelessScanForm(forms.ModelForm):
time = forms.DateTimeField(label="Schedule Time", widget=AdminSplitDateTime())
def __init__(self,*args,**kwargs):
myClient = kwargs.pop("client") # client is the parameter passed from views.py
super(WirelessScanForm, self).__init__(*args,**kwargs)
prob = forms.ChoiceField(label="Sniffer", choices=[ x.sniffer.plug_ip for x in Sniffer.objects.filter(client = myClient) ])
But django keeps giving me error saying: TemplateSyntaxError: Caught NameError while rendering: name 'myClient' is not defined(This error happens in the query)
I'm afraid it would be something stupid missing here, but I cannot really figure out why. Please help, thanks.
Assuming I've corrected your formatting properly, you have an indentation issue: prob is outside __init__, so doesn't have access to the local myClient variable.
However if you bring it inside the method, it still won't work, as there are two other issues: first, simply assigning a field to a variable won't set it on the form; and second, the choices attribute needs a list of 2-tuples, not just a flat list. What you need is this:
def __init__(self,*args,**kwargs):
myClient = kwargs.pop("client") # client is the parameter passed from views.py
super(WirelessScanForm, self).__init__(*args,**kwargs)
self.fields['prob'] = forms.ChoiceField(label="Sniffer", choices=[(x.plug_ip, x.MY_DESCRIPTIVE_FIELD) for x in Sniffer.objects.filter(client = myClient)])
Obviously replace MY_DESCRIPTIVE_FIELD with the actual field you want displayed in the choices.

Problem using generic views in django

I'm currently working with django generic views and I have a problem I can't figure out.
When using delete_object I get a TypeError exception:
delete_object() takes at least 3 non-keyword arguments (2 given)
Here is the code (I have ommited docstrings and imports):
views.py
def delete_issue(request, issue_id):
return delete_object(request,
model = Issue,
object_id = issue_id,
template_name = 'issues/delete.html',
template_object_name = 'issue')
urls.py
urlpatterns = patterns('issues.views',
(r'(?P<issue_id>\d+)/delete/$', 'delete_issue'),
)
The other generic views (object_list, create_object, etc.) work fine with those parameters. Another problem I have is when using the create_object() function, it says something about a CSRF mechanism, what is that?
You need to provide post_delete_redirect, this means url, where user should be redirected after object is deleted. You can find this in view signature:
def delete_object(request, model, post_delete_redirect, object_id=None,
slug=None, slug_field='slug', template_name=None,
template_loader=loader, extra_context=None, login_required=False,
context_processors=None, template_object_name='object'):