How do you get the DJango form data that were appended? - django

How do you get all row data of the forms that were appended? I have a form with 5 numbers per row, and some 'N' number of rows that are selected by the user is appended.
Form:
class locker(forms.Form):
num0 = forms.IntegerField(label='', min_value=1, max_value=25, required=True)
num1 = forms.IntegerField(label='', min_value=1, max_value=25, required=True)
num2 = forms.IntegerField(label='', min_value=1, max_value=25, required=True)
num3 = forms.IntegerField(label='', min_value=1, max_value=25, required=True)
num4 = forms.IntegerField(label='', min_value=1, max_value=25, required=True)
View:
# Render form
...
count = 3
newForm = locker()
context.update({ 'locker': newForm, 'lockerCount': range(count) })
...
Template:
# Display form
...
<div class="lockers">
<form name="longForm" action="" method="post">
{% csrf_token %}
{% for i in lockerCount %}
{{ locker }}<br />
{% endfor %}
<br />
<input type="submit" value="submit" class="small-button">
</form>
</div>
...
I've tried various methods searched from google, and the closest I got was:
...
data = form.cleaned_data.items()
for q in data:
...
but it's getting only the last row of numbers.
Looking at the console, I do see all the data (below). I'm trying to get all rows of the form, each row containing 5 sets of integers. Please help.
[29/Sep/2022 23:19:42] "POST /main/ HTTP/1.1" 200 10113
[29/Sep/2022 23:20:43] "GET /main/?csrfmiddlewaretoken=w3YIsEf1Af2hX4IRfPIVShZCdUjh9EEnbu2o8UGbI8XFbcTif6f1FlviC3KoHDM8&num0=7&num1=6&num2=21&num3=5&num4=11&num0=22&num1=4&num2=6&num3=19&num4=10&num0=9&num1=14&num2=20&num3=3&num4=25 HTTP/1.1" 200 7687

Got it figured out. I was rendering the form in wrong way. Using the 'formset_factory' to create the formset solved it.
View:
# Render form
...
count = 3
lockerSet = formset_factory(locker, extra=count, max_num=10)
context.update({ 'lockerSet': lockerSet })
...
Template:
# Display form
...
<div class="lockers">
<form name="longForm" action="" method="post">
{% csrf_token %}
{{ lockerSet.management_form }}
{% for form in lockerSet %}
{{ form }}<br />
{% endfor %}
<br />
<input type="submit" value="submit" class="small-button">
</form>
</div>
...
Then I was able to access all the data like this:
lockerSet = formset_factory(locker, extra=count, max_num=10)
formSet = formset(request.POST)
if formSet.is_valid():
for form in formSet:
m0 = form.cleaned_data['num0']
m1 = form.cleaned.data['num1']
...

Related

Django M2M Form

i try to do checkboxes in form for M2M field, but have this error, have no idea how to fix it. Google didn't help me, i tried.
When i render objects as list, i can select few objects and save it, so problem is not in views.py ,but it doesn't work with checkboxes.
My code:
forms.py
class CheckoutForm(forms.ModelForm):
class Meta:
model = Checkout
fields = ('dishes', 'user')
def __init__(self, *args, **kwargs):
super(CheckoutForm, self).__init__(*args, **kwargs)
self.fields["dishes"].widget = CheckboxSelectMultiple()
self.fields["dishes"].queryset = Dish.objects.all()
so only way that i can see an form error:
render form fields - send a empty form - put back {{ form.as_p }} - i can see an error "field is required"
page.html
<form class="p-2" action="{% url 'make_order' %}" method="POST" enctype="multipart/form-data">
{% csrf_token %}
<select name="user">
<option value="{{ user.id }}">{{ user }}</option>
</select>
<div
class="row row-cols-1 row-cols-md-5 g-2"
style="margin-left: -40px"
>
{% for dish in dishes %}
<div class="col">
<div class="card" style="width: 14rem">
<img
class="card-img-top"
style="width: 220px; height: 240px"
src="{{ dish.image.url }}"
alt="Card image cap"
/>
<div class="card-body">
<h5 class="card-title">{{ dish.name }}</h5>
<p class="card-text">Description: {{ dish.description }}</p>
<p class="card-text">Ingredients: {{ dish.ingredients }} g</p>
<p class="card-text">Serving size: {{ dish.serving_size }} g</p>
<p class="card-text">Price: {{ dish.price }} UAH</p>
<input
type="checkbox"
class="btn btn-primary"
name="dishes"
id="{{ dish.id }}"
value="{{ dish.id }}"
/>Add to cart
</div>
</div>
</div>
{% endfor %}
<input type="submit" value="ADD" class="btn btn-primary" />
</form>
views.py
class OrderView(LoginRequiredMixin, CreateView):
model = Checkout
template_name = "food_order/make_order.html"
form_class = CheckoutForm
success_url = "/order/"
login_url = "/login/"
raise_exception = True
def form_valid(self, form):
print('i am here')
instance = form.save(commit=False)
instance.user = self.request.user
instance.save()
dishes = form.cleaned_data["dishes"]
for dish in dishes:
dish, created = Dish.objects.get_or_create(name = dish)
dish.save()
instance.dishes.add(dish)
instance.save()
print(instance.dishes)
print(instance)
form.save_m2m()
return super(OrderView, self).form_valid(form)
def get_context_data(self, **kwargs):
context = super(OrderView, self).get_context_data(**kwargs)
context["dishes"] = Dish.objects.all()
context["orders"] = Checkout.objects.all()
return context
I don't think you need to be tinkering with __init__ here when setting the widget. It may be overwriting your values for a modelform.
Try:
class CheckoutForm(forms.ModelForm):
class Meta:
model = Checkout
fields = ('dishes', 'user',)
widgets = {'dishes': forms.CheckboxSelectMultiple() }
This should work as m2m fields have the ModelMultipleChoiceField by default. If you want to make it all explicit, you can go with:
class CheckoutForm(forms.ModelForm):
dishes = forms.ModelMultipleChoiceField(
queryset=Dish.objects.all(),
widget=forms.CheckboxSelectMultiple,
)
class Meta:
model = Checkout
fields = ('dishes', 'user',)
If you are formatting the checkboxes by hand
make sure they have name="dishes" (assuming dishes is the name of the field in your Checkout model) and value="<the dish id>"
You may also need to grab the values submitted with request.POST.getList('dishes'), otherwise you will ony get one value submitted

Django: Formset just saves the first form

I have a Formset that allow so uploadoad multiple images with a description:
def bilddokumentation_form(request, auftrag):
auftrag = Auftrag.objects.get(id=auftrag)
BilddokumentationFormSet = formset_factory(BilddokumentationForm, extra=1)
formset = BilddokumentationFormSet(request.POST or None, request.FILES or None)
if formset.is_valid():
for form in formset.cleaned_data:
name = form['name']
bild = form['bild']
Bilddokumentation.objects.create(
name=name,
bild=bild,
auftrag=auftrag,
user=request.META['USER'],
)
else:
print(formset.errors)
return render(request, 'auftragsverwaltung/bilddokumentation_add.html', {'item_forms': formset, 'auftrag': auftrag})
But only the first form will be saved. The second form doesn't appear in the cleaned_data.
This is the template:
<script type="text/html" id="item-template">
<div id="item-__prefix__">
{{ item_forms.empty_form }}
</div>
</script>
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ item_forms.management_form }}
<div id="items-form-container">
{% for item_form in item_forms %}
<div id="item-{{ forloop.counter0 }}">
{{ item_form.id }}
{{ item_form.as_p }}
</div>
{% endfor %}
</div>
weiteres Bild hinzufügen
<input type="submit" class="btn btn-primary" value="Bilder hinzufügen">
</form>
<script>
$(document).ready(function() {
$('.add-item').click(function(ev) {
ev.preventDefault();
var count = $('#items-form-container').children().length;
var tmplMarkup = $('#item-template').html();
var compiledTmpl = tmplMarkup.replace(/__prefix__/g, count);
$('div#items-form-container').append(compiledTmpl);
// update form count
$('#id_item_items-TOTAL_FORMS').attr('value', count+1);
// some animate to scroll to view our new form
$('html, body').animate({
scrollTop: $("#add-item-button").position().top-200
}, 800);
});
});
</script>
And the form:
class BilddokumentationForm(ModelForm):
class Meta:
model = Bilddokumentation
exclude = ['user', 'datum', 'auftrag']
widgets = {
'name': Textarea,
}
I can see that the second form is in the POST data, but it wont appear in the cleaned_data.
What would be the correct way to do it? And why does Django discard the second form?

setting initial values for more then one form

I have looked at some examples but none of them have worked for me.
What i have is List of Locations and the user has the choice to add them to a group. First step is he gives the group a name. And then he can choose from the locations which are already in the database, to add them to the group name.
To put it simple i want to loop 3 form elements for each location, and attach initial values for each location, so it can be stored inside a group.
This is what i want to see:
<form>
<input type="text" label="group_name">
First Location
<input type="hidden" value="street_name">
<input type="hidden" value="location_name">
<input type="checkbutton">
Second location
<input type="hidden" value="street_name2">
<input type="hidden" value="location_name2">
<input type="checkbutton">
and so on
<input type="submit" value="Create this Group">
</form>
I have tried it like this:
Froms.py is currently missing the check input for True and False.
FORMS.py:
class GroupAddForm(forms.ModelForm):
groupname = forms.CharField(label='',widget=forms.HiddenInput(attrs={'rows': '4', 'class': 'form-control'}))
page_name = forms.CharField(label='' ,widget=forms.HiddenInput(attrs={'rows': '4', 'class': 'form-control'}))
page_street = forms.CharField(label='' ,widget=forms.HiddenInput(attrs={'rows': '4', 'class': 'form-control'}))
class Meta:
model = GroupManagement
fields = ['groupname', 'page_name', 'page_street']
VIEW:
def page_groups(request):
email =request.user.email
locationdata = LocationData.objects.filter(email=email).values_list(
'id',
'name',
'street',
'postal_code',
'tel',
'website',
'description',
'fb_page_id'
)
form = []
for items in locationdata:
name = items[1]
form = GroupAddForm(request.POST or None, initial={"page_name": name})
print(form)
context = {
'locationdata': locationdata,
'form': form,
}
return render(request, 'page_groups.html', context)
OR in the Template:
<form method="POST" action=""> {% csrf_token %}
{% for items in locationdata %}
{{items.1}}
{{form.fields.page_name.value|default:items.1}}
{{form}}
{% endfor %}
</form>
Inside the View only the last element is attached to the form.
The initial Value inside the Template doesn't work at all.
Fixed it myself.
for items in locationdata:
name = items[1]
form = GroupAddForm(request.POST or None, initial={"page_name": name})
forms.append(form)
<form method="POST" action=""> {% csrf_token %}
{% for items in forms %}
{{items}}
{% endfor %}
</form>

Creating multiple objects using the same form

Hi I have just read through, http://collingrady.wordpress.com/2008/02/18/editing-multiple-objects-in-django-with-newforms/, and am trying to apply it to my own django app.
I have created a view which lets me use a single form to create and store 2 objects that are related to each other
I am getting a post error but can't seem to find what is causing it.
After clicking add a blank white page is shown along with the error message below, which is in red in the terminal.
'[28/May/2014 02:57:25] "POST /members HTTP/1.1" 405 0'
Models
class MemberRole(models.Model,get_fields):
name = models.CharField(max_length = 20)
def __unicode__(self):
return self.name
class Member(models.Model,get_fields):
first_name = models.CharField(max_length = 20)
role = models.ForeignKey(MemberRole, null = True, blank = True)
Forms
class MemberForm(forms.ModelForm):
class Meta:
model = Member
exclude = ('role',)
class MemberRoleForm(forms.ModelForm):
class Meta:
model = MemberRole
View fucntion
def add_member(request):
model_url = 'member-list'
if request.method == "POST":
rform = MemberRoleForm(request.POST, instance=MemberRole())
mform = MemberForm(request.POST, instance=Member())
if rform.is_valid() and mform.is_valid():
new_role = rform.save()
new_member = mform.save()
return HttpResponseRedirect('member-list')
else:
rform = MemberRoleForm(instance=MemberRole())
mform = MemberForm(instance=Member())
return render_to_response('create_model.html', {'role_form': rform, 'member_form': mform, 'model_url': model_url,},context_instance=RequestContext(request))
snippet of create_model.html
<form action="{% url model_url %}" method="POST">
{% csrf_token %}
{% if model_url == 'member-list' %}
{% for field in member_form %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field.label_tag }} {{ field }}
</div>
{% endfor %}
{% for field in role_form %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field.label_tag }} {{ field }}
</div>
{% endfor %}
{% endif %}
<input id="save_contact" type="submit" value="Add"/>
</form>
I've solved it, it was due to some errors in url naming
View
model_url = 'member-add'
return HttpResponseRedirect('members')
URLS
url(r'^members', ModelListView.as_view(model = Member,page_name = 'Members',edit_link = 'updatemember/'), name='member-list'),
url(r'^addmember', 'inventory.views.add_member', name = 'member-add'),

Django Rendering template objects error

I have a problem with the way I structured my function.
My function renders 2 forms. A form to change the primary picture for a whiteboard and a form to delete a picture from a particular whiteboard
Both forms displays a dropbox that list all whiteboards for the students to pick and when the students pick a whiteboard . it's displays all the objects.
The form that set a primary picture for a whiteboard works perfectly because it display all picture objects but when I choose a value from the dropbox under the delete picture.
The function doesn't return all the pictures objects underneath the delete picture header but it instead displays all the picture under the primary forms.
I think the problem is with my if forms.is_valid(): and my if formss.is_valid(): because when a form is submitted . It only get POST into the if forms.is_valid():
my views.py
def WhiteBoardEditor(request):
if not request.user.is_authenticated():
return HttpResponseRedirect(reverse('world:LoginRequest'))
picture = {}
pict = {}
if request.method == "POST":
forms = BoardPictureForm(request.user,request.POST,)
formss = PictureDeleteForm(request.user,request.POST,)
if forms.is_valid():
board = forms.cleaned_data['board']
if board:
boards = forms.cleaned_data['board']
picture = Picture.objects.filter(board=boards)
return render(request,'boardeditor.html',{'picture':picture,'boardpicture':BoardPictureForm(request.user),'picturedelete':PictureDeleteForm(request.user)})
if formss.is_valid():
pooh = formss.cleaned_data['board']
if pooh:
pooh = formss.cleaned_data['board']
pict = Picture.objects.filter(board=pooh)
return render(request,'boardeditor.html',{'pict':pict,'boardpicture':BoardPictureForm(request.user),'picturedelete':PictureDeleteForm(request.user)})
return render(request,'boardeditor.html',{'boardpicture':BoardPictureForm(request.user),'picturedelete':PictureDeleteForm(request.user)})
my boardeditor.html
<h1> Set a primary picture for a whiteboard</h1>
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{ boardpicture.as_p }}
<input type = "submit" value= "save" />
</form>
{% for p in picture %}
<li>{{p.description}}
{% endfor %}
<h1> Delete picture from whiteboard</h1>
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{ picturedelete.as_p }}
<input type = "submit" value= "save" />
</form>
</form>
{% for pi in pict %}
{ pi.description }}
{% endfor %}
my forms.py
class BoardPictureForm(forms.ModelForm):
def __init__(self, user, *args, **kwargs):
super(BoardPictureForm, self).__init__(*args, **kwargs)
self.fields['board'].queryset = Board.objects.filter(user=user)
class Meta:
model = Picture
fields = ('board',)
class PictureDeleteForm(forms.ModelForm):
def __init__(self, user, *args, **kwargs):
super(PictureDeleteForm, self).__init__(*args, **kwargs)
self.fields['board'].queryset = Board.objects.filter(user=user)
class Meta:
model = Picture
fields = ('board',)
Your two forms use the same field which is the board. That's why when you submit the second form, the first form is the one process.
To fix your problem, you need to specify the action in every form. Notice that in my answer, I add input in hidden format with the process value. And in your view, I create if and else statement for that process so that when you submit the form the system will know which form must be executed.
if request.method == "POST":
forms = BoardPictureForm(request.user,request.POST,)
formss = PictureDeleteForm(request.user,request.POST,)
if request.POST['process'] == 'primary':
if forms.is_valid():
board = forms.cleaned_data['board']
if board:
boards = forms.cleaned_data['board']
picture = Picture.objects.filter(board=boards)
return render(request,'boardeditor.html',{
'picture':picture,
'boardpicture':BoardPictureForm(request.user),
'picturedelete':PictureDeleteForm(request.user)
})
elif request.POST['process'] == 'delete':
if formss.is_valid():
pooh = formss.cleaned_data['board']
if pooh:
pooh = formss.cleaned_data['board']
pict = Picture.objects.filter(board=pooh)
return render(request,'boardeditor.html',{
'pict':pict,
'boardpicture':BoardPictureForm(request.user),
'picturedelete':PictureDeleteForm(request.user
)}
elif request.POST['process'] == 'third':
//other form here
<h1> Set a primary picture for a whiteboard</h1>
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{ boardpicture.as_p }}
<input type = "hidden" name="process" value= "primary" />
<input type = "submit" value= "save" />
</form>
{% for p in picture %}
<li>{{p.description}}
{% endfor %}
<h1> Delete picture from whiteboard</h1>
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{ picturedelete.as_p }}
<input type = "hidden" name="process" value= "delete" />
<input type = "submit" value= "save" />
</form>
</form>
{% for pi in pict %}
{ pi.description }}
{% endfor %}
Edit2: Ah, I've misunderstood this question - the following isn't relevant to the question, but still useful to the OP
I suspect it's because your not generating well-formed HTML. Try changing the "picture" part in boardeditor.html to be
<ul>
{% for p in picture %}
<li>{{p.description}}</li>
{% endfor %}
</ul>
Edit: also,
{% for pi in pict %}
{{ pi.description }} <!-- added an opening curly brace -->
{% endfor %}
And you have a redundant </form> towards the bottom