Passing variables between views - django

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 ?

Related

using two templates from one view

I am trying to present content from a view in two ways: html and csv download. The only way I was able to do it was to use 2 different views, one for html presentation and one for csv. This duplicates my code and I am looking for a more elegant solution.
Any suggestions?
Here is the sample code:
# views.py
[...]
def member_list(request):
member_list = Member.objects.all()
return render_to_response("member_list.html",
{'member_list':member_list)
def member_csv_list(request):
member_list = Member.objects.all()
csv_list = HttpResponse(content_type='text/csv')
csv_list['Content-Disposition'] = 'attachment; filename="member_list.csv"'
writer = csv.writer(csv_list)
writer.writerow(['Name', 'Member Type', 'Rooms'])
for member in member_list:
fields = [member.name, member.member_type, member.room]
writer.writerow(fields)
return member_list
You can use a parameter in your url and implement a view like
def myview(request) :
type = request.GET.get('type', 'html')
# do processing
if type == 'html':
# return html
else if type == 'csv':
# return csv
If you access a url like http://yourserver/myview?type=csv it will render the csv part of the view. When the url http://yourserver/myview is accessed it will return the html part of the view.
Rohan's answer is absolutely the right paradigm. For an excellent tutorial-style introduction to this topic, cf. Multiple Templates in Django.
Here are a few quotes (all credit goes to Scott Newman).
To serve a printable version of an article, for example, we can add ?printable to the end of the URL.
To make it work, we'll add an extra step in our view to check the URL for this variable. If it exists, we'll load up a printer-friendly template file. If it doesn't exist, we'll load the normal template file.
def detail(request, pid):
'''
Accepts a press release ID and returns the detail page
'''
p = get_object_or_404(PressRelease, id=pid)
if request.GET.has_key('printable'):
template_file = 'press/detail_printable.html'
else:
template_file = 'press/detail.html'
t = loader.get_template(template_file)
c = Context({'press': p})
return HttpResponse(t.render(c))
He continues with template overrides and different templates by domain names. All this is excellent.

How can I redirect url with a frendly when user fill the form in django

I use a form in template,and I want to redirect a friendly url when user fill the form
I search many issue in stackoverflow,I think my problem like this issue: Django form redirect,
but I can't understand the template tag,so I can't solve my problem.
I write the form:
<form method="GET" action="/stock/search">
search:<input class="search" name="search" type="text" value="" id="serach" >
<input type="submit" value="Go"/>
</form>
and write the urls:
url(r'^(?P<number>\w+)/$', 'stock.views.stocknumber'),
url(r'^search/$', 'stock.views.search'),
and the views:
def stocknumber(request, number):
"""
stock info
"""
stock = Stock.objects.filter(number="%s"%number)
stock_number = Stock.objects.filter(number="%s"%number)
stock_reportinfo = Reportinfo.objects.filter(number="%s"%number)
stock_blockinfo = Blockinfo.objects.filter(number="%s"%number)
stock_stockinfo = Stockinfo.objects.filter(number="%s"%number)
data = Stockhq.objects.filter(number="%s"%number).values('timeStamps','openData','highData','lowData', 'closeData', 'volData').reverse()
datalist=[ ]
for item in data:
d =[item['timeStamps'].toordinal(),item['openData'],item['highData'],item['lowData'],item['closeData'],item['volData']]
datalist.append(d)
hisdata = datalist
return render_to_response(
'stock/stock.html',
{"stock_number": stock_number,
"stock_reportinfo": stock_reportinfo,
"stock_blockinfo": stock_blockinfo,
"stock_stockinfo": stock_stockinfo,
"hisdata":simplejson.dumps(hisdata) ,
},
context_instance=RequestContext(request))
def search(request):
return HttpResponseRedirect('/stock/%s/'%request.GET['search'])
and now I hope the user input the stock number and redriect to the friendly url like:http://..../stock/YHOO
and this url is get the stock info to render template,is this idea is right?
if it is ,what is the correct code ?
I don't think that question is really similar to your question, if I'm understanding correctly. Because that one already predetermines the action of the form, the redirected URL doesn't seem to depend on the user input. So I'm not entirely sure what your question is.
Are you implementing a simple search that, when a user inputs the stock's number (I'm assuming you consider "YHOO" a number? Is the "number" input something like "YHOO" or is it actually a number?), the stock with the number (so "YHOO" stock) is displayed with all of its information on a new page with the URL "http://.../stock/YHOO"?
In any case, here are some observations.
stock = Stock.objects.filter(number="%s"%number)
stock_number = Stock.objects.filter(number="%s"%number)
Is there a reason why you have both when you don't use the first one? In addition, are numbers unique? If so, you can just do Stock.objects.get(number=number), because:
You would use "get" instead of "filter" because you'd expect a
single record to match that.
Number is already a string when
passed in, so you don't need to do "%s" % number.
You can also try the following instead of using the actual URL, to make it more Django-like.
from django.core.urlresolvers import reverse
...
def search(request):
number = request.GET['search']
return HttpResponseRedirect(reverse('stock.views.stocknumber', args=(number,)))

Want to print out a list of items from another view 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?

How to Pass Django form values to a model class method

What is the best way to pass request information to a model class method?
I'm wondering whether I have my logic in the wrong place. Maybe I need to move it out of my model.
I want to be able to pass in POST variables or a form to filter the model by country or institution.
I can't do that from the template, but the question is whether I should do that from within the model or controller somehow.
My Model:
class AccountExtra(User):
def myPendingPaymentSchedules(self, status=1, **args):
if self.is_staff: # status = approved by MFI
schedules = PaymentSchedule.objects.select_related(depth=3).filter(active=True)
if country:
schedules = schedules.filter(country=country)
if institution:
schedules = schedules.filter(institution=institution)
return schedules
My Controller:
myAccount = get_object_or_404(AccountExtra, id=request.user.id)
My Template
{% for sample in myAccount.myPendingPaymentSchedules %} # Can't pass parameters for country, etc
Yes, I'd say your logic is in the wrong place. I don't know where the values are coming from that you're trying to pass into myPendingPaymentSchedules, but it seems like it should be done in the view rather than the template. Then you can pass the resulting schedules directly into the template context.
(By the way, your naming scheme is not very Pythonic: I'd use my_account and my_pending_payment_schedules - see PEP8.
Thanks for the feedback. I've done a little bit of research about how to access business login from within templates and I thought I'd provide an update in case others find this question in the search results:
There are two cases in which the parameters for the method need to be passed:
Case #1) Passing paramaters for a single value
If we only have a single account, we can simply pass them to the model through a single call in the controller, and pass the result to the template as a single context variable.
Model
class AccountExtra(models.Model):
..
def my_pending_payment_schedules(self, status=1, country=None, institution=None)
if self.is_staff:
schedules = payment_schedule.objects.filter(active=True)
if country:
schedules = schedules.filter(product__country=country)
if institution:
schedules = schedules.filter(product__institution=institution)
return schedules
Controller
my_account = get_object_or_404(AccountExtra, id=request.user.id)
form = staff_approval_form(request.POST)
if form.is_valid():
cd = form.cleaned_data
pending_schedules = my_account.my_pending_payment_schedules(
country=cd.get('country', None),
institution=cd.get('institution', None)
)
c = RequestContext( request, {
'form': form,
'pending_schedules': pending_schedules,
})
return render_to_response(
'my/approvals/approvals_index.html',
context_instance=RequestContext(request, c)
)
Template
{% for sample in pending_schedules %}
Case #2: Passing parameters for multiple values
If however, we are trying to iterate through multiple users's pending schedules who each require different parameters, we can't use a simple 'pending_schedules' variable.
We have to either turn that variable into a dictionary to store the results of multiple users.
A collegue of mine developed a template tag that allows you to access the dictionary by key, as you iterate through the loop.
Templatetags
#register.filter
def hash(obj, key):
"""return hash lookup of key in object
If the key can be hard-coded into the template, then the normal dot-notation
is sufficient (obj.key). But if the key is referenced by a name in the
template context then this hash filter becomes useful.
Template usage: obj|hash:key
"""
return obj[key]
Template:
for user in users:
for sample in pending_schedules|hash:user.id
Do something
endfor
endfor

passing object data through URL

I know that I can pass object values through a URL pattern and use them in view functions. For instance:
(r'^edit/(?P<id>\w+)/', edit_entry),
can be utilized like:
def edit_entry(request, id):
if request.method == 'POST':
a=Entry.objects.get(pk=id)
form = EntryForm(request.POST, instance=a)
if form.is_valid():
form.save()
return HttpResponseRedirect('/contact/display/%s/' % id)
else:
a=Entry.objects.get(pk=id)
form = EntryForm(instance=a)
return render_to_response('edit_contact.html', {'form': form})
But how do I pass a value from a model field (other than "id") in the url? For instance, I have an abstract base model with a field "job_number" that is shared by child models "OrderForm" and "SpecReport". I want to click on the "job_number" on the order form and call the Spec Report for that same job number. I can create an
href="/../specifications/{{ record.job_number }}
to pass the info to the url, but I already know that this regex syntax is incorrect:
(r'^specifications/(?P<**job_number**>\w+)/', display_specs),
nor can I capture the job_number in the view the same way I could an id:
def display_specs(request, job_number):
records = SpecReport.objects.filter(pk=job_number)
tpl = 'display.html'
return render_to_response(tpl, {'records': records })
Is there an easy approach to this or is it more complicated than I think it is?
the amended code is as follows:
(r'^specdisplay/?agencyID=12/', display_specs),
and:
def display_specs(request, agencyID):
agencyID= request.GET.get('agencyID')
records = ProductionSpecs.objects.filter(pk=id)
tpl = 'display_specs.html'
return render_to_response(tpl, {'records': records })
not sure how to filter. pk is no longer applicable.
Yes, you are making this a little more complicated that it is.
In your urls.py you have:
(r'^edit/(?P<id>\w+)/', edit_entry),
Now you just need to add the almost identical expression for display_specs:
(r'^specifications/(?P<job_number>\w+)/', display_specs),
Parenthesis in the regex identifies a group and the (?P<name>...) defines a named group which will be named name. This name is the parameter to your view.
Thus, your view will now look like:
def display_specs(request, job_number):
...
Finally, even though this will work, when you redirect to the view, instead of using:
HttpResponseRedirect('/path/to/view/%s/' % job_number)
Use the more DRY:
HttpResponseRedirect(
reverse('display_specs', kwargs={'job_number': a.job_number}))
Now if you decide to change your resource paths your redirect won't break.
For this to work you need to start using named urls in your urlconf like this:
url(r'^specifications/(?P<job_number>\w+)/', display_specs, name='display_specs'),
Not knowing what your model structure is like ... why couldn't you just pass the particular job's id and then pick it up with a query?
Afaik every model automatically has an id field that autoincrements and is a unique identifier of a row (an index if you will), so just change the href creation to {{record.id}} and go from there.
Try passing the job_number through the url then, especially if you don't care about pretty url's too much just do this:
url: /foo/bar/?job_number=12
no special markup to catch this btw, the regex is r'^foo/bar/'
And then read it in the view like this:
job_number= request.GET.get('job_number')
I really don't understand your question. What's the difference between passing id and passing job_number in a URL? If you can do one, why can't you do the other? And once the job_number is in the view, why can't you do a normal filter:
records = SpecReport.objects.filter(job_number=job_number)