Save and retrieve a form with session? - django

I have a context_processor.py file with the following function
def include_user_create(request):
if 'form' not in request.session:
form = CreateUserForm()
else:
form = request.session['form']
return { 'create_user_form' : form }
I use this to display my register in my base.html template, so that I may reuse it for all pages. A function create_user handles the form submit
def create_user(request):
form = CreateUserForm(request.POST or None, request.FILES or None)
if request.method == 'POST':
if form.is_valid():
user = form.save(commit=False)
user.save()
user = authenticate(username=user.email, password=user.password)
else:
request.session['form'] = form #<--- save
next = request.POST.get('next', '/')
return HttpResponseRedirect(next)
If the form is invalid I'd like to save the form so that the context_processor may reuse the form, for the purpose of saving the errors so they may be displayed in the template.
Doing this gives me a error:
TypeError: <CreateUserForm bound=True, valid=False, fields=(email;password;confirm_password)> is not JSON serializable
Is it possible to get this to work somehow?

You have this error because a form object is not JSON serializable, and the default session serializer is serializers.JSONSerializer.
Try to change it to a pickle serializer in your settings.py:
SESSION_SERIALIZER = 'django.contrib.sessions.serializers.PickleSerializer'
EDIT:
With this setting, you don't have to care about pickle serialization, you just have to write:
request.session['form'] = form

Related

Create Form and update using same view in django

I am trying to use same view for creating form and updating any object.
My code is as below, I tried in many ways nothing is working, since I am excluding the shof from form and adding it after form.is_valid() it makes lot of confusion. If I update it creates new object. I have two urls one without ql (create new) and one with ql (update existing), I have a class vdview which provides v.shof which needs to applied in the f.shop in form. please help fix this,
#csrf_protect
#login_required
def addmenu(request, qs, ql=None):
v = vdview(request, qs)
ctgobj = get_object_or_404(v.shopcategs, pk=ql) if ql else None # ctgobj = ShopCtg(shop=v.shof)
if ql:
form = ShopCtgForm(instance=ctgobj) # Tried ShopCtgForm(instance=ctgobj, data=request.POST)
else:
form = ShopCtgForm(data= request.POST)
if request.method == 'POST':
if form.is_valid():
f=form.save(commit=False)
f.shop = v.shof
f.save()
#form.save_m2m()
return redirect('vendor-shop', qs) #thing='%s added' %f.name)
else:
pass
#else:
# form = ShopCtgForm()
return render(request,'vendorshop.html', {'shop':v.shof, 'shopcategs':v.shopcategs, 'form': form,
'heading':'Create New Category', 'createcateg': 'createcateg', 'pkaddmenupk':'y' } )
Use try blocks to handle both scenarios. The simplified example below will look for a given model instance pk and if it doesn't find it, will assume you want to create it. try will prevent django from throwing an error if the model instance doesn't exist. Rather, it will just return the empty model form.
It does this first to render the correct form in the template (the first try block) then again in the second try block after request.method == 'POST': to submit new data or update existing data.
Views.py
from .models import Books
from .forms import BookForm
def create_and_update_book_view(request, pk):
books = Books.objects.get(id=pk)
try: # get pre-populated form with model instance data (for update)
form = BookForm(instance=books.id)
except: # If it doesn't exist, show an empty form (for create)
form = BookForm(request.POST or None)
if request.method == 'POST':
try: # Do the same as above
form = BookForm(instance=books.id)
except: # Same as above
form = BookForm(request.POST or None)
if form.is_valid():
form.save()
return render(request, "create_and_update_book_page.html", {'form':form})

Create, get and edit user information in same form and template

I'm trying to retrieve data from user. The form where i want to show the user information is also the same that i use to update this information.
Update3
After some updates I make this work and this is my code. If somenone have a better way to do this can share it :)
models.py
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class informacionFacturacion(models.Model):
usuario = models.ForeignKey(User, on_delete=models.CASCADE)
apellidos = models.CharField(max_length=100)
nombres = models.CharField(max_length=100)
[More fields...]
def __str__(self):
self.apellidos
forms.py
from .models import informacionFacturacion
#Create your forms here.
class informacionFacturacionForm(ModelForm):
class Meta:
model = informacionFacturacion
fields = [
"usuario",
"apellidos",
"nombres",
[More fields...]
]
views.py
#login_required
def datosPersonales(request):
#Filter query by user ID
query = informacionFacturacion.objects.filter(usuario=request.user)
form = informacionFacturacionForm()
#If query has content, edit record, else, create a new record
if query:
if request.method == "POST":
form = informacionFacturacionForm(request.POST or None, instance=query[0])
if form.is_valid():
edit_content = form.save()
edit_content.save()
else:
if request.method == "POST":
form = informacionFacturacionForm(request.POST)
if form.is_valid():
create_content = form.save(commit=False)
create_content.save()
return HttpResponseRedirect(reverse('datosPersonales'))
context = {
"titulo": "Datos personales | Co.",
"body_class": "class= sidebar_main_open sidebar_main_swipe",
"form": form,
"infoFacturacion": query,
}
template = "micuenta/datosPersonales.html"
return render(request, template, context)
Thanks for the support.
At first glance, it seems that the informacionFacturacion table is not being populated. Have you checked that the instance.save() is reached? (in other words, that the form is valid)
Second, in the template you want to use the informacionFacturacion object as the form elements, and you are handling them separately. Do:
if request.POST:
form = informacionFacturacionForm(request.POST)
if form.is_valid():
instance = form.save(commit=False)
instance.save()
else:
# handle here the form error's, maybe report it in the template
else:
query = informacionFacturacion.objects.filter(usuario=request.user)
form = informacionFacturacionForm(instance=query[0])
and render the form parameter insead of infoFacturacion:
{{ form.as_p }}
finally, make sure that your template form id's matches the form element names, otherwise the form won't be filled.
UPDATE
Based on your edit, now the error is in this line:
form = informacionFacturacionForm(request.POST, instance=query_id)
query_id is an int, and it is expecting a model. Change the following line:
query_id = informacionFacturacion.objects.get(usuario=request.user).id
to
query = informacionFacturacion.objects.get(usuario=request.user)
and the faulty line to:
form = informacionFacturacionForm(request.POST, instance=query)
that should work for now, although code can be simplified a lot.
EDIT 2
Here is what I assume you want:
#login_required
def datosPersonales(request):
query = informacionFacturacion.objects.filter(usuario=request.user)
if request.method == "POST": # This will handle the template form's POST
form = informacionFacturacionForm(request.POST)
if form.is_valid():
asd = form.save(commit=False)
asd.save()
# Here you may want to redirect to somewhere else
# Im not sure here, I guess that you want to handle the GET method if
# there is no form in the request. Post your template form to see what
# is happening.
else:
form = informacionFacturacionForm(instance=query)
# you dont need to save it, it is already in DB
context = {
"titulo": "Datos personales | Co.",
"body_class": "class= sidebar_main_open sidebar_main_swipe",
# I think here is your main issue, you are handling a form object
# AND a infoFacturacion object. You need to use just the
# form object in the template and render it accordingly.
"form": form,
"infoFacturacion": query,
}
template = "micuenta/datosPersonales.html"
return render(request, template, context)
Well, I was with the same problem on my sytem, so I made this solution, maybe it works to you! =D
I'm changing the value of the submit button and using the same form:
<button type="submit" id="submitButton" name="button" value="">Save</button>
If is a new task, I change the value of the button with JQuery:
$('#submitButton').val('new');
And if is an edition, I change the value again:
$('#submitButton').val('edit');
On my views.py, I check if is an edit or a new save by the value of the button:
def index(request):
tasks = Task.object.filter()
context = {
'tasks': tasks
}
if request.method == 'POST':
form = NewTask(request.POST or None)
if request.POST['button'] == 'new':
if form.is_valid():
context['is_valid'] = True
form.save()
form = NewTask()
else:
context['is_valid'] = False
if request.POST['button'] == 'edit':
instance = Task.object.filter(pk=request.POST['id']).first()
form = NewTask(request.POST, instance=instance)
if form.is_valid():
context['is_valid'] = True
form.save()
else:
context['is_valid'] = False
else:
form = NewTask()
context['form'] = form
return render(request, 'index.html', context)

django - how to check if model is empty

I have settings form page. If user filled the form once; it must display those values. But if there is no data [first time] I get query error. I need that query, because the form data must be written as related with current user [logged in].
here is my view part :
#login_required(login_url='/login/')
def profile_page(request,username):
query = Profile.objects.get(owner__username = username) ##error!
if request.method == 'POST':
form = profile_form(request.POST,instance=query)
form.save()
return HttpResponseRedirect('/admin/')
else:
form = profile_form(instance=query)
return render_to_response('profile_save.html',{'form':form},context_instance = RequestContext(request))
I think I need to check the model and if it is empty I should do something different.
I am stuck.
Thank you
You want to make use of the .exists() queryset option
#login_required(login_url='/login/')
def profile_page(request,username):
form = profile_form()
if Profile.objects.get(owner__username = username).exists():
query = Profile.objects.get(owner__username = username)
if request.method == 'POST':
form = profile_form(request.POST,instance=query)
form.save()
return HttpResponseRedirect('/admin/')
else:
form = profile_form(instance=query)
return render_to_response('profile_save.html',{'form':form},context_instance = RequestContext(request))
see QuerytSet API reference for more information
You just need to wrap that get query in try ... except and set instance to none, like this.
from django.core.exceptions import ObjectDoesNotExist
#login_required(login_url='/login/')
def profile_page(request,username):
try:
query = Profile.objects.get(owner__username = username)
#to be more specific you can except ProfileObjectDoesNotExist
except ObjectDoesNotExist:
query = None #Doesn't exist, set to None
if request.method == 'POST':
form = profile_form(request.POST,instance=query)
form.save()
return HttpResponseRedirect('/admin/')
else:
form = profile_form(instance=query)
return render_to_response('profile_save.html',{'form':form},
context_instance = RequestContext(request))
I think i may have use get_or_create for this purpose.
Profile.objects.get_or_create(owner__username = username)

Django form is_valid() fails

I am a real beginner in web development. The following code is failing at the is_valid() check. But I do not understand why: The form should get its data filled from the POST-data or not?
Model:
class Statement(models.Model):
text = models.CharField(max_length=255)
user = models.ForeignKey(User)
time = models.DateField()
views = models.IntegerField()
ModelForm:
class StatementForm(ModelForm):
class Meta:
model = Statement
widgets = {
'time':forms.HiddenInput(),
'user':forms.HiddenInput(),
'views':forms.HiddenInput(),
}
View function:
def new(request):
if request.method == 'POST': # If the form has been submitted...
form = StatementForm(request.POST) # A form bound to the POST data
if form.is_valid():
stmt = form.save()
path = 'stmt/' + stmt.id
return render_to_response(path, {'stmt': stmt})
else:
c = {}
c.update(csrf(request))
loggedin_user = request.user
d = datetime.now()
form = StatementForm(request.POST, initial={'time': d.strftime("%Y-%m-%d %H:%M:%S"), 'user':loggedin_user, 'views':0})
return render_to_response('new_stmt.html', {'form': form, },context_instance=RequestContext(request))
I found similar topics and tried a lot. This is how i think it should work. I really need advice.
All fields of your model are required. So, form.is_valid() will be True, if all fields are filled with correct values and are not blanked.
You have declared fields time, user, views as hidden fields. Are you sure, that you have filled them in your template form?
Also, you may want to auto stamp field time = models.DateField(). Modify your model field like
time = models.DateField(auto_now=True)`.
After this you don't have to fill it by yourself in template form.
Your view must return HttpResponse object in all cases. If your form is not valid, i.e. if form.is_valid() will return False, then no HttpResponse object will be returned by your view. This can be the source of your fail. Add else statement for if form.is_valid():
from django.http import Http404
def new(request):
if request.method == 'POST': # If the form has been submitted...
form = StatementForm(request.POST) # A form bound to the POST data
if form.is_valid():
stmt = form.save()
path = 'stmt/' + stmt.id
return render_to_response(path, {'stmt': stmt})
else:
# Do something in case if form is not valid
raise Http404
else:
# Your code without changes
Change this line:
form = StatementForm(request.POST, initial={'time': d.strftime("%Y-%m-%d %H:%M:%S"), 'user':loggedin_user, 'views':0})
For this:
form = StatementForm(initial={'time': d.strftime("%Y-%m-%d %H:%M:%S"), 'user':loggedin_user, 'views':0})

How to recover ImageField value in Django when it returns an Error?

I have a form which contains an imagefield and some other fields.
my view looks like this:
def post_view(request):
def errorHandle(errors,form):
return render_to_response('post_form.html', {
'errors':errors,
'form' : form,
},context_instance=RequestContext(request))
if request.method == 'POST': # If the form has been submitted...
form = PostForm(request.POST, request.FILES) # A form bound to the POST data
if form.is_valid(): # All validation rules pass
#save
else:
errors = form.errors
return errorHandle(errors,form)
else:
form = PostForm() # An unbound form
sucess = ''
return render_to_response('post_form.html', {
'form': form,
}, context_instance=RequestContext(request))
When errorHandle is called, it returns to the page with the form, errors and the values entered except for the value entered on an ImageField.
tell me if you need to look at my form and model. thanks in advance.
I think it's normal.
Path of a client image is secure for a backend, so, it was not sent. It's an official HTTP feature.