django - how to check if model is empty - django

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)

Related

Get Kwargs through an intermediate page

I have a model (grade) inside another model (homework) which is inside another model (activity) and when I submit the grade of a homework and try to get back to activty I loose the id of the activity. How do I get the right kwargs to get back to activity after submiting a grade? Or any other solution you may think about. Thanks in advance.
Views.py
def grade_homework(request, id):
if not request.user.is_authenticated:
return render(request, "auctions/login.html")
try:
activity = Activity.objects.get(id=id)
except Activity.DoesNotExist:
activity = None
try:
hw_upload = Hw_upload.objects.get(id=id)
except Hw_upload.DoesNotExist:
hw_upload = None
if request.method == 'POST':
form = Hw_gradeForm(request.POST, request.FILES or None)
if form.is_valid():
hw_grade = form.save(commit=False)
hw_grade.grader = request.user
hw_grade.hw_upload = Hw_upload.objects.get(id=id)
hw_grade.save()
url = reverse('activity', kwargs={'id': id})
return HttpResponseRedirect(url)
Urls.py
path("auction/course/module/activity/<str:id>", views.activity, name="activity"),
path("grade_hw/<int:id>", views.grade_homework, name="grade_hw"),

Django post-form cannot validate when using Form with additional inputs

I have a form containing af MultipleChoiceField where the choices are created dynamic based on the given user
class UpdateForm(forms.Form):
def __init__(self,names,*args,**kwargs):
super(UpdateForm,self).__init__(*args,**kwargs)
self.fields["list_names"] = forms.MultipleChoiceField(choices = zip(names,names),widget=forms.CheckboxSelectMultiple,label="Pick some names")
add_new = forms.BooleanField(initial=True, label="Add new names?",required=False)
delete_missing = forms.BooleanField(label = "Delete names?",required=False)
and it works fine as GET-request, the issues arrives with the post-request:
My view is the following:
def update(request):
user = request.user
list_names = MyModel.objects.filter(user=user).all().values_list("nick_name",flat=True).distinct()
form = UpdateWishlistForm(names =list_names)
if request.method == "POST":
post_form = UpdateForm(request.POST)
if post_form.is_valid():
list_names = post_form.cleaned_data["list_names"]
add_new = post_form.cleaned_data["add_new"]
delete_missing = post_form.cleaned_data["delete_missing"]
messages.success(request, "Success")
context = {
"form":form,
}
redirect("home")
else:
#invalid post_form
messages.error(request, "Error")
context = {
"form":form,
}
return render(request, "discounttracker/update.html")
else: #Get request
context = {
"form":form,
}
return render(request, "myapp/update.html",context=context)
The post_form = UpdateForm(request.POST) does not validate and the post_form.errors is empty.
It does contain data though (before calling post_form.is_valid())
print(post_form)
# UpdateForm: <UpdateForm bound=False, valid=Unknown, fields=(add_new;delete_missing;list_names)>
print(request.POST.dict())
#<QueryDict: {'csrfmiddlewaretoken': ['...'], 'add_new': ['on'], 'list_names': ['test_name_1']}>
but I notice it is not bound, thus not validating. But I cannot understand why it's not "binding" when parsing request.POST?
In the POST request, you need to pass the names as well, so:
list_names = MyModel.objects.filter(user=user).values_list("nick_name",flat=True).distinct()
form = UpdateWishlistForm(names=list_names)
if request.method == 'POST':
post_form = UpdateForm(names=list_names, data=request.POST)
# …
# …
But I would advise to work with a ModelMultipleChoiceField [Django-doc] and thus pass a queryset. Since the nick names apparently can contain duplicates, it might be better to make a Nickname model, and use ForeignKeys to that model.

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)

Using session to store form input values in order to uso in another view

I am storing some form values, which is a list filter, from a post method in the request.session in order to use it in another view function to render the filtered results. The problem is any user that I log in keep the results stored, if they access the results page directly they will see other users filter results.
I use pagination (digg without AJAX), I am using django-el-pagination.
the views.py
def search(request):
if request.method == 'POST':
form = ComprarBuscaForm(request.POST)
if form.is_valid():
cidade = form.cleaned_data['cidade']
request.session['cidade'] = form.cleaned_data['cidade']
request.session['quartos'] = form.cleaned_data['quartos']
request.session['tipo_imovel'] = form.cleaned_data['tipo_imovel']
request.session['preco_minimo'] = form.cleaned_data['preco_minimo']
request.session['preco_maximo'] = form.cleaned_data['preco_maximo']
request.session['area_minima'] = form.cleaned_data['area_minima']
request.session['area_maxima'] = form.cleaned_data['area_maxima']
return HttpResponseRedirect(reverse('imoveis:resultado_busca'))
else:
form = ComprarBuscaForm()
return render (request, 'imoveis/busca_comprar.html', {'form':form})
def search_result(request):
anuncios = Anuncio.objects.filter(quartos=request.session['quartos'],
cidade=request.session['cidade'],
tipo_imovel=request.session['tipo_imovel'],
preco_venda__gte=request.session['preco_minimo'],
preco_venda__lte=request.session['preco_maximo'],
area_construida__gte=request.session['area_minima'],
area_construida__lte=request.session['area_maxima'],
tipo_anuncio='Venda')
return render(request, 'imoveis/resultado_busca_comprar.html', {'anuncios': anuncios})
Everything is working fine although the fact I mentioned before. I am wondering if what I am doing is the right approach for this kind of situation.
Is it really necessary to use two views for this? I would filter and render in the same form view if I were you.
def search(request):
if request.method == 'POST':
form = ComprarBuscaForm(request.POST)
if form.is_valid():
anuncios = Anuncio.objects.filter(quartos=request.session['quartos'],
cidade=request.session['cidade'],
tipo_imovel=form.cleaned_data['tipo_imovel'],
preco_venda__gte=form.cleaned_data['preco_minimo'],
preco_venda__lte=form.cleaned_data['preco_maximo'],
area_construida__gte=form.cleaned_data['area_minima'],
area_construida__lte=form.cleaned_data['area_maxima'],
tipo_anuncio='Venda')
return render(request, 'imoveis/resultado_busca_comprar.html', {'anuncios': anuncios})
else:
form = ComprarBuscaForm()
return render (request, 'imoveis/busca_comprar.html', {'form':form})

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})