Want to print out a list of items from another view django - django

I have a view which displays a list items.
def edit_order(request, order_no):
try:
status_list = models.Status.objects.all()
order = models.Order.objects.get(pk = order_no)
if order.is_storage:
items = models.StorageItem.objects.filter(orderstoragelist__order__pk = order.pk)
else:
items = models.StorageItem.objects.filter(orderservicelist__order__pk = order.pk)
except:
return HttpResponseNotFound()
I want to put these list of item in another view. Unfortunately this is proving to be trickier then I thought.
#login_required
def client_items(request, client_id = 0):
client = None
items = None
try:
client = models.Client.objects.get(pk = client_id)
items = client.storageitem_set.all()
item_list = models.StorageItem.objects.filter(orderstoragelist__order__pk = order.pk)
except:
return HttpResponse(reverse(return_clients))
return render_to_response('items.html', {'items':items, 'client':client, 'item_list':item_list}, context_instance = RequestContext(request))
I thought maybe I can just paste the definition of items and just call that item_list but that does not work. Any ideas
items.html
{% for item in item_list %}
{{item.tiptop_id}
{% endfor %}

From your comment:
I get a white screen with the url printed on the screen. /tiptop/client in this case.
Because that's what you've asked for:
except:
return HttpResponse(reverse(return_clients))
This means that if there are any bugs or problems in the above, your view will simply output a response containing just that URL. Maybe you meant to use HttpResponseRedirect, so the browser actually redirects to the URL - but still you should not use a blank except, as it prevents you from seeing what is actually going wrong.
To answer the main question, think about what your edit_order view returns: it gives you a complete HTML response with a rendered template. How could you use that as an element in a query in another view? You need to think logically about this.
One possible solution would be to define a separate function which just returns the data you want - as a plain queryset - and both views can call it. Does that do what you want?

Related

Django not displaying correct URL after reverse

There's lots of documentation about Django and the reverse() method. I can't seem to locate my exact problem. Suppose I have two urlconfs like this:
url(r'ParentLists/$', main_page, name = "main_page"),
url(r'ParentLists/(?P<grade_level>.+)/$', foo, name = "foo")
and the two corresponding views like this:
def main_page(request):
if request.method == 'POST':
grade_level = request.POST['grade_picked']
return HttpResponseRedirect(reverse('foo', args = (grade_level,)))
else:
return render(request, 'index.html', context = {'grade_list' : grade_list})
def foo(request, grade_level):
grade_level = request.POST['grade_picked']
parent_list = # get stuff from database
emails = # get stuff from database
return render(request, 'list.html', context = {'grade_list' : grade_list, 'parent_list' : parent_list})
Here, list.html just extends my base template index.html, which contains a drop down box with grade levels. When the user goes to /ParentLists, the main_page view renders index.html with the drop down box as it should.
When the user picks a grade level from the drop down box (say 5th Grade), the template does a form submit, and main_page once again executes - but this time the POST branch runs and the HttpResponseRedirect takes the user to /ParentLists/05. This simply results in an HTML table pertaining to grade 5 being displayed below the drop down box.
The problem is, when the user now selects say 10th Grade, the table updates to show the grade 10 content, but the URL displayed is still /ParentLists/05. I want it to be /ParentLists/10.
Clearly, after the first selection, the main_page view never executes again. Only foo does...and so the HttpResponseRedirect never gets called. How should I reorganize this to get what I'm looking for? Thanks in advance!
As you correctly mentioned you will never redirect to foo() from foo().
So the simple way to fix this is just add similar code as in main_page() view:
def foo(request, grade_level):
if request.method == 'POST':
grade_level = request.POST['grade_picked']
return HttpResponseRedirect(reverse('foo', args = (grade_level,)))
else:
parent_list = # get stuff from database
emails = # get stuff from database
return render(request, 'list.html', context = {'grade_list' : grade_list, 'parent_list' : parent_list})
Please note that I remove grade_level = request.POST['grade_picked'] because as Nagkumar Arkalgud correctly said it is excessively.
Also instead of combination of HttpResponseRedirect and reverse you can use shortcut redirect which probably little easy to code:
from django.shortcuts redirect
...
return redirect('foo', grade_level=grade_level)
I would suggest you to use kwargs instead of args.
The right way to use the view is:
your_url = reverse("<view_name>", kwargs={"<key>": "<value>"})
Ex:
return HttpResponseRedirect(reverse('foo', kwargs={"grade_level": grade_level}))
Also, you are sending "grade_level" to your view foo using the URL and not a POST value. I would remove the line:
grade_level = request.POST['grade_picked']
as you will override the grade_level sent to the method from the url.

Can you use a Django form multiple times in one view?

I have a Django view that uses one form multiple times. The form is just a boolean field form that is supposed to initialize to True but then the user can decide to uncheck the boxes or not.
The problem I'm having is that the all of the fields evaluate to True no matter what the user leaves checked. Is this a problem with using the same form multiple times, or did I mess something else up?
The form looks like this:
class DataTypeForm(forms.Form):
def __init__(self,*args,**kwargs):
section_label = kwargs.pop('section_label')
initial_value = kwargs.pop('initial_value')
super(DataTypeForm,self).__init__(*args,**kwargs)
self.fields['dataType'].label=mark_safe(section_label)
self.fields['dataType'].initial=initial_value
self.fields['dataType'].required=False
dataType = forms.BooleanField(required=False)
This is the view:
def Manual_Request(request):
form_dict = {}
arg_dict = {}
message = message = {'last_url':'Nominal_Request'}
if request.method == 'POST':
logger.info("Query submitted, beginning query results render for:")
form_NOM = DataTypeForm(request.POST or None,section_label="ENG_NOM",initial_value=True)
form_DDM = DataTypeForm(request.POST or None,section_label="SCI_DDM",initial_value=True)
form_RAW = DataTypeForm(request.POST or None,section_label="SCI_RAW",initial_value=False)
if form_NOM.is_valid():
NOM = form_NOM.cleaned_data['dataType']
arg_dict.update({'ENG_NOM':str(NOM)})
logger.info("ENG_NOM: {val}".format(val=NOM))
if form_DDM.is_valid():
DDM = form_DDM.cleaned_data['dataType']
arg_dict.update({'SCI_DDM':str(DDM)})
logger.info("SCI_DDM: {val}".format(val=DDM))
if form_RAW.is_valid():
RAW = form_RAW.cleaned_data['dataType']
arg_dict.update({'SCI_RAW':str(RAW)})
logger.info("SCI_RAW: {val}".format(val=RAW))
return Request_Results(request,args_dict)
else:
logger.info("Rendering query page")
form_NOM = DataTypeForm(section_label="ENG_NOM",initial_value=True)
form_DDM = DataTypeForm(section_label="SCI_DDM",initial_value=True)
form_RAW = DataTypeForm(section_label="SCI_RAW",initial_value=True)
form_dict.update({'form_NOM':...etc})
return render(request,'InterfaceApp/COMMRequest_Manual.html',form_dict)
Help much appreciated!
I haven't run your code, but my best guess is that yes, it's a problem with using the same form multiple times in the same view. The reason? All of your <input type="checkbox" name="..." ... /> tags will have the same name, 'dataType'. The user's browser knows nothing of your back-end, and will just send, for example, dataType=on&dataType=on as POST data for the three fields if two are checked and one is not.
Seeing the problem here? How is django supposed to know which of those dataType fields are for your NOM, DDM, or RAW forms? It can't know.
You should be able to solve this using form prefixes. In short, there's a kwarg that you can pass to a form's __init__() that will cause a prefix to be added to all of the form items in the rendered HTML. So, for example:
form_NOM = DataTypeForm(request.POST or None, section_label="ENG_NOM",
initial_value=True, prefix="NOM")
form_DDM = DataTypeForm(request.POST or None, section_label="SCI_DDM",
initial_value=True, prefix="DDM")
form_RAW = DataTypeForm(request.POST or None, section_label="SCI_RAW",
initial_value=False, prefix="RAW")
Hope that helps!
This is exactly what Django formsets are for. They allows you to create a set of the same type of form. It handles prefixes, and adds a management form so that Django doesn't get confused as to what data comes from what form.
https://docs.djangoproject.com/en/1.8/topics/forms/formsets/

How to get /test/?grid-view or /test/?list-view' in Django view

I have a page that can be viewed by list or grid view through jQuery, but I want the URL to display what view it is -- especially when user paginate so that they don't have to reclick what they want to view -- so something like this: /test/?grid_view or /test/?list_view.
I've been trying to use request.GET.get, but it doesn't seem to be working. Here is what I have so far:
def test (request):
grid_view = request.GET.get('grid_view')
list_view = request.GET.get('list_view')
if grid_view:
return render_to_response('grid_view.html', {}, context_instance=RequestContext(request))
elif list_view:
return render_to_response('list_view.html', {}, context_instance=RequestContext(request))
else:
return render_to_response('default_view.html', {}, context_instance=RequestContext(request))
Then in my main template I'd point the different views to list view, etc. There is probably a better way to do it so any suggestions are appreciated too.
An empty string is evaluated to False and, that is what your GET request Query String parameters will contain.
You could modify your code to:
if 'grid_view' in request.GET or 'grid_view/' in request.GET:
pass
elif 'list_view' in request.GET or 'list_view/' in request.GET:
pass
Or:
if request.GET.has_key('grid_view') or request.GET.has_key('grid_view/'):
# ...
That's not a GET parameter. Use request.META['QUERY_STRING'] to get the query string.

Passing variables between views

I have two views:
def importContent(request):
d = get_some_data()
t = get_template('import.html')
c = Context({'entries' : d.entries })
return HttpResponse(t.render(c))
def doImport(request):
return HttpResponse("hey")
Here is import.html:
{% for entry in entries %}
{{ entry.title}} <br>
{% endfor %}
soo
User open importContent() view and press the link, which opens th doImport() view. How can I pass d-variable from importContent() view to doImport() view?
I can think of a couple of ways to approach this.
The first requires that you have sessions enabled. In this mechanism the first view will store the variable in the user's session and the second will retrieve it. For e.g.
def importContent(request):
d = get_some_data()
t = get_template('import.html')
c = Context({'entries' : d.entries })
request.session['entries'] = d
return HttpResponse(t.render(c))
def doImport(request):
if 'entries' in request.session:
d = request.session['entries']
else:
d = # Perform a look up or show a message etc.
return HttpResponse("hey")
The session can be substituted with a custom cache too.
The second is to make the second explicitly look up the data. This is easier if the data is limited and doesn't require any extensive computation.
If you want to pass all entries back to doImport, it won't be easy. The way to pass parameter in a request is to put them in the url, use a post request or use session but this requires more work.
Using URL is not really convenient because there will be a lot of parameters on that url.
Using a post is sort of weird and not suited to a html link.
Using a session requires authentication and use of users.
Can't you just call:
d = get_some_data()
in doImport again ?

Next previous links from a query set / generic views

I have a quite simple query set and a related generic views:
f_detail = {
'queryset': Foto.objects.all(),
'template_name': 'foto_dettaglio.html',
"template_object_name" : "foto",
}
urlpatterns = patterns('',
# This very include
(r'^foto/(?P<object_id>\d+)/$', list_detail.object_detail, f_detail, ),
)
Just a template for generating a detail page of a photo: so there's no view.
Is there an easy way to have a link to previous | next element in the template
without manualy coding a view ?
Somthing like a:
{% if foto.next_item %}
Next
{% endif}
class Foto(model):
...
def get_next(self):
next = Foto.objects.filter(id__gt=self.id)
if next:
return next.first()
return False
def get_prev(self):
prev = Foto.objects.filter(id__lt=self.id).order_by('-id')
if prev:
return prev.first()
return False
you can tweak these to your liking. i just looked at your question again... to make it easier than having the if statement, you could make the methods return the markup for the link to the next/prev if there is one, otherwise return nothing. then you'd just do foto.get_next etc. also remember that querysets are lazy so you're not actually getting tons of items in next/prev.
The Foto version above has a couple of shortcomings:
Doing a boolean evaluation like if next: can be slow since it basically loads the entire QuerySet result. Use next.exists() or the try/except like in my version.
The get_prev() result is wrong because you need to reverse the ordering in this case.
So FWIW here is my version, which is for a generic primary key:
def get_next(self):
"""
Get the next object by primary key order
"""
next = self.__class__.objects.filter(pk__gt=self.pk)
try:
return next[0]
except IndexError:
return False
def get_prev(self):
"""
Get the previous object by primary key order
"""
prev = self.__class__.objects.filter(pk__lt=self.pk).order_by('-pk')
try:
return prev[0]
except IndexError:
return False
If you'll accept Model.objects.all() as your queryset, and you are ok with grabbing next / previous items by a date field (usually a 'created' field with auto_now_add=True will give the same order as object id's), you can use get_next_by_foo() and get_previous_by_foo(), where 'foo' is the date field.
For next / previous links from a more complicated QuerySet, using the Paginator with threshold set to one seems like it might be the best option.