Context: In my template, I click "Add product" and it takes me to another template where I have a list of all the products, I choose one and it takes me back to my selected product list template, and I keep adding so on.
In my receiver view I have this:
def vw_Sell(request):
if request.POST:
POST_received = request.POST
if 'ses_productList' in request.session:
request.session['ses_productList'].append({
'product': POST_received['idProduct'],
'quant': POST_received['quantity'],
})
else:
request.session['ses_productList'] = []
producList = request.session['ses_productList']
else:
if 'ses_productList' in request.session:
producList = request.session['ses_productList']
else:
producList = {}
context = {
"selected_products": producList
}
return render(request, "shop.html", context)
It only saves the first product to the session dictionary. I researched and found the SESSION_SAVE_EVERY_REQUEST and set it to True, and then it works, but I'm worry if I'm doing the correct way, thanks!
The session will only be saved automatically, if its modified property is True. That property is set every time you call the session object's __setitem__() method (usually via the = operator).
Here is the Django code for it.
However, you are appending to an already existing list, so the session object never knows that anything changed. To save the session, you need to set its modified property manually
request.session.modified = True
to mark the session "dirty" and have the session's Middleware save it.
The session Middleware code.
Final code thanks to #C14L:
if 'ses_productList' in request.session:
request.session['ses_productList'].append({
'product': POST_received['idProduct'],
'quant': POST_received['quantity'],
})
request.session.modified = True
Related
I have a url, http://127.0.0.1:8000/lesson/riff-lab/1305/pentab-wow/
When a user navigates to the above url, I want to change it to http://127.0.0.1:8000/lesson/riff-lab/1305/pentab-wow/?d:a3ugm6eyko59qhr/pentab-Track_1.js
The appended part is needed in order to load something that I want to load, but the specifics are not important for this question.
Here's what I have tried.
def my_view(request, pk):
context = {}
page = Page.objects.get(pk=pk)
request.GET._mutable = True
request.GET['?d:%s/%s' % (page.dropbox_key, page.dropbox_js_file_name)] = ""
return render(request, template, context)
Also
def my_view(request, pk):
context = {}
page = Page.objects.get(pk=pk)
request.GET = request.GET.copy()
request.GET['?d:%s/%s' % (page.dropbox_key, page.dropbox_js_file_name)] = ""
return render(request, template, context)
These do not change the url.
Can anyone help? Thanks in advance.
You trying to change the aim of a shell that already has hit it's target.
URL comes first, then view routed to it is processed, there is no way to change it without making another request, e.g. returning a redirect response "please open this url now" to the client.
You can easily find it in django docs by this keywords, but what you are trying to do generally doesn't look very reasonable, if you know beforehand how you need to construct url, why change it mid-way or why change it at all if view has all required data? I don't know your context, but it's probable that you need to reconsider your approach.
Trying to create a django application but getting an UnboundLocalError at /search/ local variable 'results' referenced before assignment error. I can't see the problem as in my code results is assigned - have a look:
def post_search(request):
form = SearchForm()
if 'query' in request.GET:
form = SearchForm(request.GET)
if form.is_valid():
cd = form.cleaned_data
results = SearchQuerySet().models(Post).filter(content=cd['query']).load_all()
# count total results
total_results = results.count()
return render(request, 'blog/post/search.html', {'form': form,
'cd': cd,
'results': results,
'total_results': total_results})
Maybe you should initialize results.
Put results = [] before if form.is_valid()
It depends on what you want to do if there are no results. Do you still want to load the view? Then initialise the results variable above any if condition (in this case, the outer one):
...
results = [] #Or whatever empty datatype you need
if 'query' in request.GET:
...
If you don't want to load the view if there are no results, you could move the return render(...) inside the inner if when you're sure there is a results variable to begin with. Then, you can add a fallback return render(...) at the end of the function, outside of any if conditions.
If you always want to load the same view, however, I'd just go for the first one. Adding multiple return render(...) seems more suitable when you want to load a different view when no results were found.
What if form is invalid? For example, user provided incorrect value on no value at all? In this case results is uninitialized. You may:
Initialize it with some empty value like [].
Raise error and return to user info that form is invalid.
def post_search(request):
cd = ""
total_results = ""
form = SearchForm()
if 'query' in request.GET:
form = SearchForm(request.GET)
if form.is_valid():
cd = form.cleaned_data
results = SearchQuerySet().models(Post).filter(content=cd['query']).load_all()
# count total results
total_results = results.count()
return render(request, 'blog/post/search.html', {'form': form,
'cd': cd,
'results': results,
'total_results': total_results})
now you have to write validation code in template
If you want to use the definition in a recursive way(count the results in your case) you should assign the var results outside the definition, because if you do it will reset every time you call it. You have to assign it out of the definition and state it like a global var.
global results
results = ''
I personally recommend you to do a bit more reading and learning on python before coding with Django.
Good luck ! :)
My form2 is executing twice due to HttpResponseRedirect and from 'POST'. How do I prevent that from happening? Is it even possible?
What I've tried:
Process and render "getInfo" from form 1 and display it in form2. While this may work but I'll still end up going through the "getInfo" again in form2 to be able to use the returned variable.
Putting "getInfo" inside the if request.method will create an error because getInfo will need to be executed to obtain the returned errors variable.
Any suggestion is definitely welcomed.
Update
I've raised a similar question regarding "Why My Django Form Executed Twice?" and it was answered. I didn't want to create a bigger confusion by adding more questions on top of it. I created this as a follow-up question on how to actually solve it.
views.py
def form1 (request):
NameFormSet = formset_factory (NameForm, formset = BaseNodeFormSet, extra = 2, max_num = 5)
if request.method == 'POST':
name_formset = NameFormSet (request.POST, prefix = 'nameform')
if name_formset.is_valid ():
data = name_formset.cleaned_data
request.session ['data'] = data
return HttpResponseRedirect ('form2')
else:
name_formset = NameFormSet (prefix = 'nameform')
context = {'name_formset': name_formset}
return render (request, 'nameform/form1.html', context)
def form2 (request):
data = request.session ['data']
n, data, errors = getInfo (data) # <==== This statement executed twice in the console
CheckBoxFormSet = formset_factory (CheckBox, extra = 2, max_num = 5)
if request.method == 'POST':
checkbox_formset = CheckBoxFormSet (request.POST, prefix = 'checkbox')
if checkbox_formset.is_valid ():
for i, form in enumerate (checkbox_formset.cleaned_data):
data [i].update (form) # Join cleaned data with original data
n.processData (data, errors) # <=== n object will be used from getInfo
del request.session ['data']
context = {'data': data}
return render (request, 'nameform/success.html', context)
else:
checkbox_formset = CheckBoxFormSet (prefix = 'checkbox')
context = {
'checkbox_formset': checkbox_formset,
'data': data,
'errors': errors, # <==== getInfo needed to execute first to display errors messages
}
return render (request, 'nameform/form2.html', context)
def getInfo (data):
# Do something with data
return (n, data, errors)
Should the else: statement be less indented to align with if request.method == POST:? Also, where does getInfo come from? In the version of django I'm using (1.7) errors are an attribute on the formset after calling is_valid().
edit: further information
OK so your getInfo function runs twice because HttpResponseRedirect actually returns a 302 response to the browser with the new address, which the browser then GETs. Then when the user submits the form the browser POSTs the data to the same view. Since getInfo runs at the start of your view before any GET/POST conditional check, it runs both times. If you just want to delegate returning a response to another view function, you can call it directly, don't return a redirect.
Without knowing any more about your program this is as much as anyone can tell you.
Some more points:
getInfo sounds like it should be a 'safe' function that doesn't mutate its input or have any side effects, so running it twice shouldn't be a problem. If it does either of those things, you ought to rename it at least.
If the results of getInfo aren't expected to change between the GET and the POST request then you can move it into the form1 view function and store the results in session['data']. If it is expected to change, or you need to know if it does change, then you have no option but to run it twice anyway, unless there is some conditional you can check without running it to know if it will change.
Finally, form validation shouldn't be in the view if possible, keep it in your form class. There are hooks in django's form classes for whatever kind of validation you could want to do on submitted data. As a general rule, try to work within the framework, in the way it was designed to be used. This approach, as opposed to constructing a Rube-Goldberg machine out of the scavenged parts of many libraries taped together, will save you a lot of effort in the long run, as the library author and you will be working in the same direction.
I am setting up a payment gateway and am using sessions to store data across page requests. The class below is used for organizing and storing information to the session.
class Gateway:
def __init__(self, session_key=None, session_name="FOO"):
# Store session ID and name
self.session_key = session_key
self.session_name = session_name
# Get the session
session = SessionStore(session_key=self.session_key)
try :
data = session[self.session_name]
except :
data = {user_id:None, checked_in:False }
self.__dict__.update(data)
def save(self) :
session = SessionStore(session_key=self.session_key)
session[self.session_name] = deepcopy(self.__dict__)
try :
del session['session_key']
del session['session_name']
except :
pass
session.save()
This view checks to see if the user is logged in. If he/she is, then he/she is redirected. If not, he/she is asked to either login or check in as a guest.
def check_in(request):
gateway = Gateway(session_key=request.session.session_key)
if request.user.is_authenticated():
gateway.user_id = request.user.id
gateway.checked_in = True
gateway.save()
return redirect('next_step')
else:
login_form = FormLogin()
if request.POST:
data = request.POST.copy()
if 'login' in data:
login_form = FormLogin(data)
if login_form.is_valid():
user = login(request, login_form)
if user:
gateway.user_id = user.id
gateway.checked_in = True
gateway.save()
return redirect('next_step')
elif 'guest' in data:
gateway.checked_in = True
gateway.save()
return redirect('next_step')
return render(
request,
'shop/login.html',
{
'login_form':login_form,
}
)
The next view checks the "checked_in" variable. This is to make sure that users are not skipping over the login/checkin process. (As a side note, the function "login(request, login_form)" is a function that is works perfectly in other contexts and returns the User if it was successful and None otherwise)
def next_step(request):
gateway = Gateway(session_key=request.session.session_key)
if not gateway.checked_in:#edited
messages.info(request, _(u'You must specify login first.'))
return redirect('check_in')
else:
#do the next step
Now for the problem:
Even when the user is authenticated, the "checked_in" variable is still false and causes the views to loop. A new session with a new session id is created each time that that I set the variable and save. The django docs have some explanation about the modification of sessions, but I cannot understand why new session is being created or why the session key is changing.
edit:
I am using the database backend.
I have duplicated this bug/issue:
URL RULE
url(r'^test/', 'shop.views.catalog.test', name="test")
VIEW FUNCTION
def test(request) :
key1 = request.session.session_key
request.session['test'] = 'test'
key2 = request.session.session_key
raise Exception("%s : %s === %s" % (key1, key2, request.session['test']))
Clear cookies for 127.0.0.1
go to 127.0.0.1:8000/test/
Exception at /test/
4793f2453758d7021a43a348a0f40a83 : 8568f729991e740395179c56cd37cf18 === test
refresh the page (w/o clearing cookies)
Exception at /test/
8568f729991e740395179c56cd37cf18 : 8568f729991e740395179c56cd37cf18 === test
so until the first time my session is modified, I have a different session key... unexpected behavior. I'm also curious why.
Django will not persist a session to the database if it has not been accessed or modified, so I believe the session_key you are using to initialise SessionStore is not actually backed by a database entry.
If this is the case: when you save your SessionStore it will be allocated a new session_key automatically [1] (as the existing key does not exist in the DB and we want to avoid session fixation [2]) and saved to the DB but the client will not be allocated this new session_key because your SessionStore is independent of request.session (which remains unmodified).
[1] https://github.com/django/django/blob/master/django/contrib/sessions/backends/db.py#L22
[2] https://groups.google.com/forum/?fromgroups#!topic/django-users/8b_6oTaXv7Q
The simple fix to test this hypothesis out would be to set request.session['kate'] = 'bob' before you initialise your Gateway class as this should force request.session to be persisted. You might like to refactor your Gateway class so that methods that need access to the session take request.session as an argument.
Check your SESSION_COOKIE_SECURE value and make sure you are using HTTPS when True..
https://github.com/lepture/flask-wtf/issues/76
How could we make the django form to not validate if we are editing, not adding a new record. The code as following :
class PageForm(forms.Form):
name = forms.CharField(max_length=100,widget=forms.TextInput(attrs={'class':'textInput'}))
description = forms.CharField(max_length=300, required=False,widget=forms.TextInput(attrs={'class':'textInput'}))
body = forms.CharField(widget=forms.Textarea)
template = forms.CharField(max_length=30,widget=forms.TextInput(attrs={'class':'textInput'}))
navbar = forms.BooleanField(required=False, widget=forms.Select(choices=(('True','True'),
('False', 'False'))))
publish = forms.BooleanField(widget=forms.Select(choices=(('Published','Publish Now'),
('Private','Private'),
('Draft','Draft'))))
def save(self, page=None, commit=True):
data = self.cleaned_data
if not page:
page = models.Page(key_name=data['name'].replace(' ','-'))
page.name = data['name']
page.description = data['description']
page.body = data['body']
page.template = data['template']
page.publish = data['publish']
if commit: page.put()
return page
# prevent the same page 's name
def clean_name(self):
name = self.cleaned_data['name']
query = models.Page.all(keys_only=True)
query.filter('name = ', name)
page = query.get()
if page:
raise forms.ValidationError('Page name "%s" was already used before' % name)
return name
The purpose of this name validation is to prevent the records with the same name. BUt i found that, it also validate on edit, so we couldn't edit records, since it will said 'records with same name already exist'.
Actually for editing, the page param on save function wont be none, but prev record instead, and wil be none on saving a new one. But how we read this param, on clean_name function so we can now whether it is editing or creating?
Thanks a lot!
in your clean method, you can use self.initial to know whether it is adding or editing. If it is editing, the self.initial will not be empty. But when it is adding, self.initial will be dictionary of what the previous value.
If you are editing form, then the form has some instance, and you can check if that exists.
If it does, then you are probably editing existing object.. right?
Example:
If you are editing object with form, you create form object much like this:
form = MyForm(instance = myobject)
Then in your form class methods you can check if form has saved instance in a way that it is described here:
Test if Django ModelForm has instance
in your clean_name function exclude the current object from queryset
query.filter('name = ', name).exclude(pk=self.pk)
or change the if condition to check that page and current object are not the same.
Sorry, I couldn't comment below your guys post, don't know why.
#sunn0 : I didn't use django models, coz deploy the app in appengine, so use appengine model instead.
#Zayatzz : May you show a little code how to do it? Since whether we are adding or editing, we always bound the form to request.POST before validation, so don't know how to differentiate.
#Ashok : I made a workaround based on your suggestion. Since previously I didn't pass the pk to form, but passing the prev object as param instead, so couldn't exclude by using pk. So, I change the code and put additional key as pk (if create, let key empty, but if edit fill key with pk) and just check in if condition, if key field not empty, then it means we are editing. Not sure if it is best practice, but it works anyway.
I can suggest to override form's init method
https://stackoverflow.com/a/70845558/15080117
because there is an argument instance.