problem with accesing multiple values using django - python

I am new to python and I am using django for student database application .
Student database application must show id, firstname,lastname,subjectnames,marks.
Single student is having multiple subjects and their marks.
I am getting problem with accessing multiple values that student is having multiple subjects and marks.
models.py
class Person(models.Model):
firstname=models.CharField(max_length=50)
lastname=models.CharField(max_length=50)
def __unicode__(self):
return (self.firstname,self.lastname)
class Marksheet(models.Model):
subname=models.CharField(max_length=50)
marks=models.IntegerField(max_length=10)
person=models.ForeignKey(Person)
def __unicode__(self):
return self.subname
views.py
def add_page(request,page_name): # function for creating the new records
p1=None
p2=None
if request.method=='POST':
p1=Person(firstname=request.POST['firstname'],lastname=request.POST['lastname'])
p1.save()
p2=Marksheet(subname=request.POST.getlist('subnames'),person=Person(person_id))
p2.save()
return render_to_response("add.html",{"page_name":page_name})
creating a records I am using form in html which is shown below....
Templates
add.html
<form method="post" action="/newdcl/{{page_name}}/add/" > {% csrf_token %}
First name: <input type="text" name="firstname" /> <br />
Last name: <input type="text" name="lastname" /> <br />
Operating System <input value="os" name="subnames" type="checkbox"><br />
System Programming <input value="sp" name="subnames" type="checkbox"> <br />
Maths <input value="maths" name="subnames" type="checkbox"> <br />
<input type="submit" value="save" >
</form>
Can anyone help me in this????

Your problem seems to lie in your how you try to create Marksheet, you can't assign a list of values to one field like that.
Using your currently formless, scary, no-validation, setup... you can do something like this-
p1=Person(firstname=request.POST['firstname'],
lastname=request.POST['lastname'])
p1.save()
for subname in request.POST.getlist('subnames'):
new = MarkSheet(subname=subname, person=p1)
#no data for marks, must define it to be able to be blank/null
new.save()
You will need to add blank=True, null=True to you marks field in your models.py if you intend to not have any initial mark.
Please look at Making Queries and Forms

In my opinion it should be done by using many-to-many relation in Person, and form should be defined as a form class, because you don't have any validation in your form, and you are writing some html, which could be generated by putting one line of code in template. I would do it like this:
models.py
class Marksheet(models.Model):
subname=models.CharField(max_length=50)
marks=models.IntegerField(max_length=10)
def __unicode__(self):
return self.subname
class Person(models.Model):
firstname=models.CharField(max_length=50)
lastname=models.CharField(max_length=50)
marksheets = models.ManyToManyField(Marksheet)
def __unicode__(self):
return (self.firstname,self.lastname)
forms.py
from models import Person
class PersonForm(ModelForm):
def __init__(self, *args, **kwargs):
super(PersonForm, self).__init__(*args, **kwargs)
# by default m2m relation is rendered with SelectMultiple widget -
# - below line is changing it to checkbox list
self.fields['marksheets'].widget = forms.CheckboxSelectMultiple()
class Meta:
model = Person
views.py
#inside your view function
if request.method == 'POST':
form = PersonForm(request.POST)
if form.is_valid():
form.save()
# pass form to template in render_to_response
add.html
<form method="post" action="/newdcl/{{page_name}}/add/" > {% csrf_token %}
{{ form }}
<input type="submit" value="save" >
</form>

Related

Django inline formset will always create new object instead of update them

I've 2 model First and Second with a FK from Second to First. I created a form for the 2 class and a inline formset for Second. On template I manually designed my form and with jQuery I'm able to add dynamic forms of Second.
On UpdateView the form is correctly populated, but when I submit the form, all Second instances are created again with new ids instead of updating them. I double checked that on HTML there are name=PREFIX-FORM_COUNT-id with correct ids, but seems that Django ignores it.
I'm using Django 2.2.12 & Python 3.6
Here what I made:
models.py
class First(models.Model):
name = models.CharField(max_length=100, null=False)
class Second(models.Model):
first= models.ForeignKey(First, null=False, on_delete=models.CASCADE)
number= models.FloatField(null=False, default=0)
form.py
class FirstForm(forms.ModelForm):
class Meta:
model = First
fields = "__all__"
class SecondForm(forms.ModelForm):
class Meta:
model = Second
fields = "__all__"
SecondsFormset = inlineformset_factory(First, Second, SecondForm)
view.py
class FirstUpdateView(UpdateView):
template_name = "first.html"
model = First
form_class = FirstForm
context_object_name = "first_obj"
def get_success_url(self):
return reverse(...)
def forms_valid(self, first, seconds):
try:
first.save()
seconds.save()
messages.success(self.request, "OK!")
except DatabaseError as err:
print(err)
messages.error(self.request, "Ooops!")
return HttpResponseRedirect(self.get_success_url())
def post(self, request, *args, **kwargs):
first_form = FirstForm(request.POST, instance=self.get_object())
second_forms = SecondsFormset(request.POST, instance=self.get_object(), prefix="second")
if first_form .is_valid() and second_forms.is_valid():
return self.forms_valid(first_form , second_forms)
...
.html (putted only essential tags)
<form method="post">
{% csrf_token %}
<input type="text" id="name" value="{{ first_obj.name }}" name="name" required>
<input type="hidden" name="second-TOTAL_FORMS" value="0" id="second-TOTAL_FORMS">
<input type="hidden" name="second-INITIAL_FORMS" value="0" id="second-INITIAL_FORMS">
<input type="hidden" name="second-MIN_NUM_FORMS" value="0" id="second-MIN_NUM_FORMS">
<div id="seconds_container">
{% for s in first_obj.second_set.all %}
<input type="hidden" name="second-{{forloop.counter0}}-id" value="{{s.pk}}">
<input type="hidden" name="second-{{forloop.counter0}}-first" value="{{first_obj.pk}}">
<input type="number" min="0" max="10" step="1" value="{{s.number}}" name="second-{{forloop.counter0}}-number" required>
{% endfor %}
</div>
<button class="btn btn-success" type="submit">Update</button>
</form>
I checked how Django creates forms and it will only add DELETE checkbox on it, but all other infos are correctly stored into the formset. When I do .save() it will create new Second element on db instead of change them.
What am I missing?
I solved this!
I setted TOTAL_FORMS and INITIAL_FORMS with wrong values. From Django's docs:
total_form_count returns the total number of forms in this formset. initial_form_count returns the number of forms in the formset that were pre-filled, and is also used to determine how many forms are required. You will probably never need to override either of these methods, so please be sure you understand what they do before doing so.
So the correct way to use it is:
In views:
Generate FormSets with extra=0
In HTML:
Set TOTAL_FORMS with number of rows you are POSTing and change it dinamically if dinamically add/remove rows;
Set INITIAL_FORMSwith number of alredy filled rows (editing/deleting) and never change this;
To delete a pre-filled row use DELETE checkbox instead of removing entire row;
For me i wanted to update my images, everything suggested here and every other forums about handling the hidden form didn't worked until i changed this.
product_img_form = ProductImageFormSet(data=request.FILES or None, instance=your_model_instance)
To this.
product_img_form = ProductImageFormSet(request.POST or None, request.FILES or None, instance=your_model_instance)
Then like magic this ugly error stopped showing, and my new image successfully got updated
<tr><td colspan="2">
<ul class="errorlist nonfield">
<li>(Hidden field TOTAL_FORMS) This field is required.</li>
<li>(Hidden field INITIAL_FORMS) This field is required.</li>
</ul>
<input type="hidden" name="product_images-TOTAL_FORMS" id="id_product_images-TOTAL_FORMS">
<input type="hidden" name="product_images-INITIAL_FORMS" id="id_product_images-INITIAL_FORMS">
<input type="hidden" name="product_images-MIN_NUM_FORMS" id="id_product_images-MIN_NUM_FORMS">
<input type="hidden" name="product_images-MAX_NUM_FORMS" id="id_product_images-MAX_NUM_FORMS">
</td></tr>

Element of my django forms.py is not defined?

I've got a problem with django with handling forms : I created a form with 2 fields, and I associated it to my view, but it tells me that my fields are undefined. Could you explain me please ?
I created a form in my index.html :
<form action="/addUser" method="post">
{% csrf_token %}
<label> Name of the Employee : <input type="text" name="employeeName", id="employeeName"/> </label>
<label> Email of the Employee : <input type="email" name="employeeEmail", id="employeeEmail" /> </label>
<button class="btn btn-primary" type="submit">Add User</button>
</form>
Then I created in views.py
def addUser(request):
if request.method == 'POST':
form = CreationUserForm(request.POST)
newEmployee = Employee()
newEmployee.name = form[employeeName]
newEmployee.email = form[employeeEmail]
newEmployee.save()
return HttpResponseRedirect(reverse('app:home'))
And then I created in forms.py
class CreationUserForm(forms.Form):
employeeName = forms.CharField(label='employeeName', max_length=254)
employeeEmail = forms.CharField(label='employeeEmail', max_length=254)
So I don't understand why I get this error : name 'employeeName' is not defined
For my point of view it is...
I tried with form.employeeName too, but it considered as a non existant attribute.
Thank you for helping :)
In your addUser method, both the employeeName and employeeEmail are variables, which are not defined. You want to be accessing the keys via the strings.
def addUser(request):
if request.method == 'POST':
form = CreationUserForm(request.POST)
newEmployee = Employee()
newEmployee.name = form['employeeName']
newEmployee.email = form['employeeEmail']
newEmployee.save()
return HttpResponseRedirect(reverse('app:home'))
also a Django suggestion - before accessing the attributes of the form, it is often useful to check that the input is valid by calling if form.is_valid() as defined here: https://docs.djangoproject.com/en/2.2/ref/forms/api/

Multiple instances in one form

Trying to implement poll-creating system, where I can create questions with choices (previously I did this all in the admin, and had to create an individual choice object for every choice)
Here's my models:
class Question(models.Model):
has_answered = models.ManyToManyField(User, through="Vote")
question_text = models.CharField(max_length=80)
date = models.DateTimeField(auto_now=True)
def __str__(self):
return self.question_text
class Choice(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE)
choice_text = models.CharField(max_length=100)
votes = models.IntegerField(default=0)
def __str__(self):
return self.choice_text
So right now here's the template:
<form method="post" action="">{% csrf_token %}
{{ question_form.question_text }}
<br><br>
<!--{{ choice_form.choice_text|placeholder:"Choice" }}-->
<input class="choice" name="choice_text" placeholder="Choice" type="text" />
<input class="choice" name="choice_text" placeholder="Choice" type="text" />
<input class="choice" name="choice_text" placeholder="Choice" type="text" />
<img src="{% static 'images/plus.png' %}" class="add_choice" />
<br>
<button class="submit" type="submit">Create question</button>
</form>
As you can see I'm not sure whether using multiple {{ choice_form.choice_text|placeholder:"Choice" }} is possible. So I paste multiple input fields and tried to get all of them by using getList(). However I get this error:
'QueryDict' object has no attribute 'getList'
Any idea why? Here's my views:
def questions(request):
question_form = QuestionForm(request.POST or None)
choice_form = ChoiceForm(request.POST or None)
if request.POST:
choice = request.POST.getList('choice_text')
print(choice)
if request.user.is_authenticated():
if question_form.is_valid():
print('valid question')
#question = question_form.save(commit=False)
return render(request, 'questions.html', {'question_form': question_form, 'choice_form': choice_form})
So how exactly should I go about this, for grabbing every choice input? Eventually I want to make all these choices map to the question that was entered. But as I said I'm sure sure whether it's possible to have multiple instances of the same field in one form.
Try using getlist instead of getList.
Also consider using forms, specifically the MultipleChoiceField could be useful in your scenario.

django poplulate html form

How to set the html form fields without using django-forms.
If you do not wish to use django.forms, but get data from a model and display it into a html form, you could do something like this:
views.py
from django.shortcuts import render_to_response, redirect
from myApp.models import MyModel
def editForm(request, model_pk):
model = MyModel.objects.get(pk=model_pk)
return render_to_response('formUpdate.html',{ 'model' : model })
def updateForm(request, model_pk):
model = MyModel.objects.get(pk=model_pk)
model.firstname = request.POST['firstname']
model.lastname = request.POST['lastname']
model.save()
return redirect('home', message='your name has been updated')
template - formUpdate.html
{% extends "base.html" %}
{% block content %}
<form action="/updateForm/{{ model.id }}/" method="post">
First name: <input type="text" name="firstname" value="{{ model.firstname }}" /><br />
Last name: <input type="text" name="lastname" value="{{ model.lastname }}" /><br />
<input type="submit" value="submit" />
</form>
{% end block %}
models.py
from django.db import models
class MyModel(models.Model):
firstname = models.CharField(max_length=20)
lastname = models.CharField(max_length=20)
urls.py
from django.conf.urls.defaults import *
urlpatterns = patterns('',
(r'^$', 'views.home', name="home"),
(r'^editForm/(?P<model_pk>\d+)/$', 'views.editForm'),
(r'^updateForm/(?P<model_pk>\d+)/$', 'views.updateForm'),
)
This is very similar to how forms are processed in PHP or similar, the model is passed into the template where the existing values are rendered. The id or pk (primary key) of the model is passed to the view via the URL and then updated values then returned to the storing view in the POST data where they can be retrieved and the updated values stored in the database.
One of the beauties of Django is how it balances speed of development with plugability - pretty much any of it's parts can be replaced or altered.
Having said this, is there a reason why you don't want to use django.forms? To my understanding a form simply performs most of the hard work in the example above for you, this is what django.forms are for. They also have other features, to help prevent malicious access of your web app, for example, OOTB. It is fairly easy to create ajax helper methods to retrieve and update them also.
You can do that as you would create a normal form in html. Just be careful to place the {% csrf_token %}. And the name of the input in the form, as they will be used in the view.
Eg:
<form method="post" action="#the url for the view">
{% csrf_token %}
...
...
<!-- fields that you want Eg: -->
<label for="username">User name:</label>
<input type="text" name="username" id="username" />
...
...
<input type="submit" value="Submit" />
</form>
Hope this helped.

Saving data using Django ModelForms

I used this code previously it worked fine and i was suggested to use ModelForm by another member, it did make sense to use the form.is_valid() function etc.. so thought of giving it a try.
I went through some other examples on the internet but mine does not seem to work for some reason, or may be I am not doing it right, I get the following when I print the form in the view, and it goes to the else statement, so my form does not get saved
<input id="id_product" type="text" name="product" value="aassddf" maxlength="250" />
FAIL
My model.py
from django.db import models
from django.forms import ModelForm
class Category(models.Model):
name = models.CharField(max_length=250)
def __unicode__(self):
return self.name
class Product(models.Model):
category = models.ForeignKey(Category)
product = models.CharField(max_length=250)
quantity = models.IntegerField(default=0)
price = models.FloatField(default=0.0)
def __unicode__(self):
return self.product
class ProductForm(ModelForm):
class Meta:
model = Product
My views.py
from models import *
from django.shortcuts import render_to_response
from django.http import HttpResponseRedirect
def index(request):
...
...
def add_product(request):
if request.method == 'POST':
form = ProductForm(request.POST)
print form['product']
if form.is_valid():
form.save()
return HttpResponseRedirect('/product')
else:
print 'FAIL'
return HttpResponseRedirect('/product')
My html
<form method="post" action="add_product/">
{% csrf_token %}
<label for="category">Category</label>
<select name="category" id="category">
{% for category in category_list %}
<option> {{ category.name }} </option>
{% endfor %}
</select>
<label for="product">Product</label>
<input type="text" name="product" id="product">
<label for="quantity">Quantitiy</label>
<input type="text" name="quantity" id="quantity">
<label for="price">Price</label>
<input type="text" name="price" id="price">
<input type="submit" value="Add New product" id="create">
</form>
Is there a better way i could save the data, using ModelForms ??
Thanks in advance for the help.
You should read the documentation. If the form is not valid, it will have a whole set of errors associated with it, which will tell you exactly why. But you just throw that away, and redirect to /product. The docs show exactly how to redisplay the form with the errors.
Also you should not write HTML form field tags directly in your template: use the form object from the view - {{ form.product }}, etc - as these will be repopulated with the appropriate values on redisplay.
Thanks to Daniel Roseman and Anuj Gupta I think I finally re-worked on my code on got it working in a standard way so it will generate the html form and validate errors.
So for anyone else who is trying to work django forms here is the code I worked on.
My model.py is was almost the same one i posted on the question but i removed
class ProductForm(ModelForm):
class Meta:
model = Product
I created a new form.py here is the code-
from django import forms
from models import Category
class ProductForm(forms.Form):
# Put all my Categories into a select option
category = forms.ModelChoiceField(queryset=Category.objects.all())
product = forms.CharField()
quantity = forms.IntegerField()
price = forms.FloatField()
My views.py changed had a lot of changes -
def add_product(request):
success = False
if request.method == "POST":
product_form = ProductForm(request.POST)
if product_form.is_valid():
success = True
category = Category.objects.get(name=product_form.cleaned_data['category'])
product = product_form.cleaned_data['product']
quantity = product_form.cleaned_data['quantity']
price = product_form.cleaned_data['price']
new_product = Product(category = category, product = product, quantity = quantity, price = price )
new_product.save()
new_product_form = ProductForm()
ctx2 = {'success':success, 'product_form':new_product_form}
return render_to_response('product/add_product.html', ctx2 , context_instance=RequestContext(request))
else:
product_form = ProductForm()
ctx = {'product_form':product_form}
return render_to_response('product/add_product.html', ctx , context_instance=RequestContext(request))
Finally in my html page i used {{ product_form.as_p }} so it created the forms dynamically
{% if success %}
<h3> product added successfully </h3>
{% endif %}
<form method="post" action=".">
{% csrf_token %}
{{ product_form.as_p }}
<input type="submit" value="Add New product" id="create">
<input type="reset" value="reset" id="reset">
</form>
This may not be the perfect solution, but for a starter like me this sounds good, and at times you just get lost while reading the docs lol, hope it helps some one.
Cheers
Try:
<form method="post" action="add_product/">
{% csrf_token %}
{{ form.as_p }}
</form>
in your template, instead of hand-coding the form's input tags. This shortcut will generate the form html for you, as well as print validation errors.
Make sure you return the form object to the template when:
There is no request.POST (form has not been submitted)
form.is_valid() fails (form has validation errors)
Of course, this is only to get you started. You really should read the docs

Categories

Resources