passing data to view using httpresponseredirect

978 views
Skip to first unread message

Maarten

unread,
Jan 3, 2008, 12:21:01 PM1/3/08
to Django users
Hi,

I took a look around the django website and the user group here, but
didn't really find an answer to this.

I my application (which does administrative things with a stock) I
have a view that allows creation of items that are stored in the
stock.

The view does different things on different actions: when accessed
without POST data it just shows a form to input the new data. This
form requires some objects (the new item has foreign keys, these need
to be passed to the form) and thus I use a
render_to_response(objects).

If the form is entered and submitted, a post is done to the same view.
When the view detects the post it will read from it and try to create
the items, ending with a httpresponseredirect to this view. (called
new())

There are two arrays that I use throughout the project (included in
the base template from which all inherit) called messages and errors
(passed as error_list and message_list). I use these to notify the
user how many objects were created succesfully, what errors occured
(most common is except error, e: errors.append("error:"%e), etc..

The return_to_response can easily handle this, but
httpresponseredirect can't. However, I have added the arguments to my
view as follows:

def new(request, errors = [], messages = []):
...

This somehow gets the errors and messages to my template after a
httpresponseredirect.
(and also with a render_to_response). That's good news, unfortunatly,
django somehow remembers this and the arrays don't get cleaned up. I
tried several things to clear the arrays, but when used with
httpresponseredirect, they need to reach the render_to_response
statement before being cleared or I can't view the message. (which was
the intention in the first place.)
Also, from what I know, this shouldn't even work as no where I'm
passing arguments to new(), not in the urls.py, not in
render_to_response and certainly not using httpresponseredirect.
So, normal python rules say these should get default values [] and
thus be cleared.

On to the question, what is going on here?
Why is it that the arrays don't get their default value ([]) and how
is it possible that they do contain the errors and messages generated?
All this just doesn't feel right to me and I haven't been able to
figure it out.
Any comments greatly appreciated!

(running postgresql on a seperate linux server and running the code on
my computer (winxp).
Browser = opera, same problems with IE though, django version 0.96,
python 2.5, psycopg2

The code:

def new(request, errors = [], messages = []):
messages.append("Current total: %d"%len(Stock.objects.all()))
if(request.POST):
textarea = request.POST['serial_boxid']
po_nr = request.POST['po_no']
if(po_nr!="POnumber"):#use nothing
npo = PO.objects.get(id=request.POST['po_no'])
try:
ndp, exist_dp =
DP.objects.get_or_create(dp_no=int(request.POST['dispatch']),
defaults={'pub_date':date.today()})
except (TypeError, ValueError), e:
errors.append("error: %s"%e)
return HttpResponseRedirect('/stock/new/')
lines = textarea.splitlines()
for units in lines:
line = units.split()
if(len(line)==2):
nstock, exists =
Stock.objects.get_or_create(serialno = line[0], boxid = line[1],
defaults={'location':request.POST['location'], 'po':npo, 'dp':ndp})
if(exists):
messages.append("created %s"%nstock)
else:
errors.append("%s already exists!"%nstock)
else:
errors.append("wrong syntax in entry: %s"%line)
return HttpResponseRedirect('/stock/new/')
else:
errors.append("Please specify a PO")
return render_to_response('stock/stock_new.html',
{'error_list':errors, 'po_list':PO.objects.all(),
'message_list':messages})
else:
return render_to_response('stock/stock_new.html',
{'po_list':PO.objects.all(), 'error_list':errors,
'message_list':messages})

Regards,
Maarten

l5x

unread,
Jan 3, 2008, 12:28:43 PM1/3/08
to Django users

Peter Rowell

unread,
Jan 3, 2008, 1:30:09 PM1/3/08
to Django users
> def new(request, errors = [], messages = []):
> ...
> [ snip]
> unfortunatly, django somehow remembers this and the arrays don't get cleaned up.

It's not django that's tripping you up.

> So, normal python rules say these should get default values [] and
> thus be cleared.

Actually, normal python rules say "Don't do this." It is (IMHO) one
of the less intuitive aspects of the language -- it's consistent, just
not intuitive. If the default value for a parameter is mutable (in
this case, a list) then what happens is that each time the function is
called without that param, then it *uses the same mutable object* for
the default value. This is why it has "memory".

Instead, set the params to None and test for that in the function.
E.g.

def new(request, errors = None, messages = None):
if errors is None:
errors = []
if messages is None:
messages = []
...

Peter Rowell

unread,
Jan 3, 2008, 1:38:50 PM1/3/08
to Django users
I didn't like my own explanation and did a little more searching.

I just found a better description of this at
http://requires-thinking.blogspot.com/2007/10/note-to-self-default-parameter-values.html.

He points out that the 'def' is an executable statement and it's only
executed once. Therefore, the foo=[] only happens once.

See the Python Language Reference for the authoritative description
http://docs.python.org/ref/function.html

Note the subsection titled "Default parameter values are evaluated
when the function definition is executed."

Maarten

unread,
Jan 4, 2008, 6:13:34 AM1/4/08
to Django users
Ok, thanks.

This explains what was going on. I did read that when I was first
learning python, but I bet now, I won't forget about it anymore. I
tried working around it, but that wasn't really working as the default
value for the arguments get changed, also using messages = None wasn't
an option as that would clear the message.

I am not using sessions yet, but that will probably be a later add on
and could also solve the problem.

My solution for now is that I added a small class (global object) that
contains the arrays errors and messages. It has addError, addMessage,
getError and getMessage.
I call the set methods whenever I want to add a notice to the user
(error or message) and I call the get method in the render_to_response
statements. The get methods return the arrays and clear them.

def getErrors(self):
retrieve = self.errors
self.errors = []
return retrieve

This allows me to add all errors and messages and then display them
once. This is working for me and does the job for both
httpresponseredirect and render_to_response.
Basic setup:

view(request):
if(request.POST):
#do stuff
setErrors, setMessages
httpresponseredirect
else:
rendertoresponse(... { 'error_list':getErrors,
'message_list':getMessages})


cheers,
Maarten


On Jan 3, 7:38 pm, Peter Rowell <hedron...@gmail.com> wrote:
> I didn't like my own explanation and did a little more searching.
>
> I just found a better description of this athttp://requires-thinking.blogspot.com/2007/10/note-to-self-default-pa....
Reply all
Reply to author
Forward
0 new messages