Django formset with crispy - submit buttons not submitting - django

I'm using a FormSet with crispy, and have but a submit button on each row, however hitting submit does not update records currently.
I've searched and found some similar answers which suggest the submit isn't inside the form, but mine are. Also that a form action is missing, but none of my other crispy forms have actions and they work without issue.
Are there any other reasons seen from the code below that would cause the records to not save?
forms.py
class ChangeGroupForm(FormHelper):
def __init__(self, *args, **kwargs):
super(ChangeGroupForm, self).__init__(*args, **kwargs)
self.form_method = 'post'
self.css_class = 'form-inline'
self.form_id = 'changegroup_form'
self.form_show_labels = False
self.layout = Layout(
Div(
Div(
Div(
Field('group', placeholder='Group', css_class="form-control mb-2 mr-sm-2"),
css_class='col-lg-3'
),
Div(
Field('gps', placeholder='gps coords', css_class="form-control mb-2 mr-sm-2"),
css_class='col-lg-8'
),
Div(
HTML("""<input type="submit" name="submit" value="Save" class="btn btn-primary mt-1"/>"""),
css_class='col-lg-1'
),
css_class='row'
),
)
)
self.render_required_fields = True
views.py
#login_required
def db_change_groups(request):
change_form = modelformset_factory(ChangeGroup, fields=('group','gps'))
change_form_helper = ChangeGroupForm()
return render(request, 'home/db_change_groups.html', {
"change_form": change_form,
"change_form_helper": change_form_helper,
})
template.html
{% crispy change_form change_form_helper %}
rendered html
<form id="changegroup_form" method="post"> <input type="hidden" name="csrfmiddlewaretoken"
value="7v0000CPl3G70M6HLfF2FAiwefdfsdgdfwewdf7Gp4nay1hFqZ1Y34SBUA000mHBZQ54">
<div> <input type="hidden" name="form-TOTAL_FORMS" value="10" id="id_form-TOTAL_FORMS"> <input type="hidden"
name="form-INITIAL_FORMS" value="9" id="id_form-INITIAL_FORMS"> <input type="hidden"
name="form-MIN_NUM_FORMS" value="0" id="id_form-MIN_NUM_FORMS"> <input type="hidden"
name="form-MAX_NUM_FORMS" value="1000" id="id_form-MAX_NUM_FORMS"> </div>
<div>
<div class="row">
<div class="col-lg-3">
<div id="div_id_form-0-group" class="form-group">
<div class="controls "> <input type="text" name="form-0-group" value="A" maxlength="50"
class="form-control mb-2 mr-sm-2 textinput textInput form-control" placeholder="Group"
id="id_form-0-group"> </div>
</div>
</div>
<div class="col-lg-8">
<div id="div_id_form-0-gps" class="form-group">
<div class="controls "> <input type="text" name="form-0-gps" maxlength="255"
class="form-control mb-2 mr-sm-2 textinput textInput form-control" placeholder="gps coords"
id="id_form-0-gps"> </div>
</div>
</div>
<div class="col-lg-1"> <input type="submit" name="submit" value="Save" class="btn btn-primary mt-1" />
</div>
</div>
</div> <input type="hidden" name="form-0-id" value="1" id="id_form-0-id">
<div>
<div class="row">
<div class="col-lg-3">
<div id="div_id_form-1-group" class="form-group">
<div class="controls "> <input type="text" name="form-1-group" value="B" maxlength="50"
class="form-control mb-2 mr-sm-2 textinput textInput form-control" placeholder="Group"
id="id_form-1-group"> </div>
</div>
</div>
<div class="col-lg-8">
<div id="div_id_form-1-gps" class="form-group">
<div class="controls "> <input type="text" name="form-1-gps" maxlength="255"
class="form-control mb-2 mr-sm-2 textinput textInput form-control" placeholder="gps coords"
id="id_form-1-gps"> </div>
</div>
</div>
<div class="col-lg-1"> <input type="submit" name="submit" value="Save" class="btn btn-primary mt-1" />
</div>
</div>
</div>
</div> <input type="hidden" name="form-9-id" id="id_form-9-id">
</form>

You need to attach somthing like this to your view
def db_change_groups(request):
....
if request.method == "POST":
form = ChangeGroupForm(request.POST)
if form.is_valid():
# Access cleaned data with
group = form.cleaned_data['group']
# Then you can save this to a model.
# return success template or something
else:
# Check for errors.
If you created the form with ModelForm instead of FormHelper you could use form.save() which you automatically save it to the model.

Related

how to customize the image filed returned by UpdateView

i use the UpdateView to update the products informations in my future webstore
in my temblate .
when i open my template i find a that it renders me the image link
edit_product.html
<form method="post">
<div class="form-group">
<label>Name</label>
{{form.name}}
</div>
<div class="form-group">
<label>Description</label>
{{form.description}}
</div>
<div class="form-group">
<label>Price</label>
{{form.nominal_price}}
</div>
<div class="form-group">
<label>Image</label>
<img src="{{form.instance.photo.url}}" width="200"/>
</div>
<div class="form-group">
{{form.photo}}
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
output
<form method="post">
<div class="form-group">
<label>Name</label>
<input type="text" name="name" value="flawless legs" maxlength="255" required="" id="id_name">
</div>
<div class="form-group">
<label>Description</label>
<textarea name="description" cols="40" rows="10" required="" id="id_description">Epilateur de jambes pour femmes</textarea>
</div>
<div class="form-group">
<label>Price</label>
<input type="number" name="nominal_price" value="199" min="0" required="" id="id_nominal_price">
</div>
<div class="form-group">
<label>Image</label>
<img src="/media/products/images/449165_ALTMORE2.jpeg" width="200">
</div>
<div class="form-group">
Currently: products/images/449165_ALTMORE2.jpeg<br>
Change:
<input type="file" name="photo" accept="image/*" id="id_photo">
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
what should i do to remove this Currently: products/images/449165_ALTMORE2.jpeg<br>
I found a tricky solution :
i replaced the
<div class="form-group">
{{form.photo}}
</div>
in my html file by an input type file <input type="file" name="photo" accept="image/*" id="id_photo"> and i edited my views
views.py
class ProductUpdateView(RedirectToPreviousMixin, UpdateView):
model = Product
form_class = ProductUpdateForm
template_name = 'admin/product_update.html'
def get_object(self):
return Product.objects.get(name=self.kwargs['product_name'])
def form_valid(self, form):
form = form.save(commit=False)
self.photo = form.photo
form.save()
return HttpResponseRedirect(self.get_success_url())

request.FILES is always empty

When I try to post a Django form containing a file field, the file field is being passed as part of the request.POST rather than request.FILES (which is empty). This throws a MultiValueDictKeyError on submitting the form.
Form html
<form class="form-horizontal" action="{% url 'drinkConf' %}" method="post" enctype="multipart/form-data" >
{% csrf_token %}
<!-- Text input-->
<label class="col-md-4 control-label" for="date">Date</label>
<div class="col-md-4">
<input id="date" name="date" type="text" placeholder="" class="form-control input-md" required="">
</div>
<!-- Textarea -->
<label class="col-md-4 control-label" for="notes">Notes</label>
<div class="col-md-4">
<textarea class="form-control" id="notes" name="notes"></textarea>
</div>
<!-- Multiple Radios (inline) -->
<label class="col-md-4 control-label" for="rating">Rating</label>
<div class="col-md-4">
<label class="radio-inline" for="rating-0">
<input type="radio" name="rating" id="rating-0" value=1 checked="checked">
1
</label>
<label class="radio-inline" for="rating-1">
<input type="radio" name="rating" id="rating-1" value=2>
2
</label>
<label class="radio-inline" for="rating-2">
<input type="radio" name="rating" id="rating-2" value=3>
3
</label>
<label class="radio-inline" for="rating-3">
<input type="radio" name="rating" id="rating-3" value=4>
4
</label>
<label class="radio-inline" for="rating-4">
<input type="radio" name="rating" id="rating-4" value=5>
5
</label>
</div>
<label class="form-label" for="image">Upload an image</label>
<input type="file" class="form-control" id="image" name="image" />
<!-- Button (Double) -->
<label class="col-md-4 control-label" for="Submit"></label>
<div class="col-md-8">
<input class="btn btn-success" type="submit" value="Submit" />
<button id="Cancel" name="Cancel" class="btn btn-inverse">Cancel</button>
</div>
</div>
</form>
My view
#login_required
def DrinkBeerConfirm(request):
if request.method == 'POST':
if request.POST['date']:
cellar_id = request.session['cellar'] #Get cellar record ID
cellarEntry = Cellar.objects.get(pk=cellar_id)
journal = Journal() #make journal entry
journal.user = request.user
journal.beer = cellarEntry.beer
journal.date = request.POST['date']
journal.notes = request.POST['notes']
journal.rating = request.POST['rating']
journal.image = request.FILES['image']
journal.servingType = request.POST['servingType']
beer = beer.objects.get(id = cellarEntry.beer) #update beer ratings
currentRating = beer.rating * beer.numRatings
beer.numRatings = beer.numRatings + 1
beer.rating = currentRating / beer.numRatings
""" if cellarEntry.container == 'KG': #update stock quantity for keg
cellarEntry.vol = cellarEntry.vol - serving_qty
if cellarEntry.vol <= 0:
cellarEntry.delete()
else:
cellarEntry.save()
#display a toast here and delete entry
else:
cellarEntry.qty = cellarEntry.qty - 1 """
if cellarEntry.qty <= 0:
cellarEntry.delete()
else:
cellarEntry.save()
journal.save() #Save journal, beer and cellar records
beer.save()
As far as I can tell, this is all correct: I have enctype="multipart/form-data" set for the form, and the form fields for the file and submit look OK. I feel like I'm missing something obvious...
I guess you incorrect close tag , it affects to POST request.
Check that.

Django error: didn't return an HttpResponse object. It returned None instead

I have the following form:
class PrestataireProfilForm(forms.ModelForm):
class Meta:
model = Prestataire
fields = ["user", "name", "address", "phone", "fax", "city"]
def __init__(self, *args, **kwargs):
super(PrestataireProfilForm, self).__init__(*args, **kwargs)
self.fields['city'].widget.attrs.update({'class' : 'custom-select'})
self.fields['city'].label = ""
And this is my view:
#login_required
def prestataire_profil(request):
prestataire = Prestataire.objects.filter(user=request.user).first()
is_prestataire = request.user.groups.filter(name='Prestataire').exists()
form = PrestataireProfilForm(request.POST or None, instance=prestataire)
if request.method == 'POST':
context = {
'profil': prestataire,
'is_prestataire': is_prestataire,
'form': form
}
if form.is_valid():
prestataire = form.save(commit=False)
prestataire.save()
context = {
'profil': prestataire,
'is_prestataire': is_prestataire
}
# return render(request, 'dashboard/prestataires/profil.html', context)
return redirect('prestataire_profil')
else:
context = {
'profil': prestataire,
'is_prestataire': is_prestataire,
'form': form
}
return render(request, 'dashboard/prestataires/profil.html', context)
And this is my html form:
<form method='POST'>
{% csrf_token %}
<div class="form-group row">
<label for="name" class="col-4 col-form-label">Nom d'utilisateur</label>
<div class="col-8">
<input value="{{ profil.user.username }}" id="name" name="name" placeholder="Nom d'utilisateur" class="form-control here" required="required" type="text" disabled>
</div>
</div>
<div class="form-group row">
<label for="name" class="col-4 col-form-label">Nom*</label>
<div class="col-8">
<input value="{{ profil.user.last_name }}" id="name" name="name" placeholder="Nom" class="form-control here" required="required" type="text">
</div>
</div>
<div class="form-group row">
<label for="name" class="col-4 col-form-label">Prénom*</label>
<div class="col-8">
<input value="{{ profil.user.first_name }}" id="name" name="name" placeholder="Prénom" class="form-control here" required="required" type="text">
</div>
</div>
<div class="form-group row">
<label for="name" class="col-4 col-form-label">Raison sociale*</label>
<div class="col-8">
<input value="{{ profil.name }}" id="name" name="name" placeholder="Raison sociale" class="form-control here" required="required" type="text">
</div>
</div>
<div class="form-group row">
<label for="address" class="col-4 col-form-label">Adresse</label>
<div class="col-8">
<input value="{{ profil.address }}" id="address" name="address" placeholder="Adresse" class="form-control here" type="text">
</div>
</div>
<div class="form-group row mb-0">
<label for="address" class="col-4 col-form-label">Ville</label>
<div class="col-8">
{{ form.city|as_crispy_field }}
</div>
</div>
<div class="form-group row">
<label for="phone" class="col-4 col-form-label">Téléphone</label>
<div class="col-8">
<input id="phone" name="phone" placeholder="Téléphone" class="form-control here" type="text">
</div>
</div>
<div class="form-group row">
<label for="fax" class="col-4 col-form-label">Fax</label>
<div class="col-8">
<input value="" id="fax" name="fax" placeholder="Fax" class="form-control here" type="text">
</div>
</div>
<div class="form-group row">
<div class="offset-4 col-8">
<button name="submit" type="submit" class="btn btn-primary">Update My Profile</button>
</div>
</div>
</form>
When I click on the submit button, it gives me the following error:
Exception Type: ValueError
Exception Value: The view dashboard.views.prestataire_profil didn't return an HttpResponse object. It returned None instead.
The data does not change, and there is no information whatsoever on the debug to see what went wrong. As you can notice in the view, I commented the return render line. I changed it to the return redirect, but same issues!
Please help! Thank you.
Salut !
What I think is that your form is not valid (have you checked it was?). You treated the case if form.is_valid(), but what if it is not? Then you are not returning anything! So, if in all cases you are going to redirect to prestataire_profil, you should do:
#login_required
def prestataire_profil(request):
[...]
if request.method == 'POST':
[...]
if form.is_valid():
[...] # do your stuff
# return redirect('prestataire_profil') <--- wrong indentation
return redirect('prestataire_profil') # <--- there, it will return something anyway
else:
[...]
return render(request, 'dashboard/prestataires/profil.html', context)
A try... except... finally... statement would be a better thing to do, because the way you did won't prevent you to return None instead of an expected HttpResponse object.

Sign up View in Django with Bootsrap

I am a self learned programmer (beginner) trying to write a Signup Class Based View. Through some tutorials I have been able to write a code which as follows:
from django.shortcuts import render, redirect
from django.contrib.auth import authenticate, login
from django.views import generic
from django.views.generic import View
from .forms import UserForm
class UserFormView (View):
form_class = UserForm
template_name = "signup.html"
#display signup blank form
def get(self, request):
form = self.form_class(None)
return render(request, self.template_name, {'form': form})
#process form data
def post(self, request):
form = self.form_class(request.POST)
if form.is_valid():
user = form.save(commit=False)
#cleaned (normalized) data
username = form.cleaned_data['username']
password = form.cleaned_data['password']
user.set_password(password)
user.save()
# Returns User objects if credentials are correct
user = authenticate(username=username, password=password)
if user is not None:
login(request, user)
return redirect("home")
return render(request, self.template_name, {'form': form})
Here is the forms.py:
from django.contrib.auth.models import User
from django import forms
class UserForm (forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput)
class Meta:
model = User
fields = ['first_name', 'last_name', 'username', 'email', 'password' ]
Now, I have a signup.html page designed using bootstrap. I am now stuck how to integrate my views to the html page. Using {{ form }} in a plane html is working bt not in bootstrap designed page. Please help
signup.html:
<div class="container">
<div class="row">
<div class="col-xs-12 col-sm-8 col-md-6 col-sm-offset-2 col-md-offset-3" style="margin-top: 70px">
<form role="form" method="post" action="">{% csrf_token %}
<h2>Welcome to Artivism <small>Sign up</small></h2>
<hr class="colorgraph" style="height: 7px; border-top: 0; background: grey; border-radius: 5px;">
<div class="row">
<div class="col-xs-12 col-sm-8 col-md-6">
{% for field in form %}
<div class="form-group">
<input type="text" name="first_name" id="first_name" class="form-control input-lg" placeholder="First Name" tabindex="1" value="{{User.first_name}}">
</div>
</div>
<div class="col-xs-12 col-sm-6 col-md-6">
<div class="form-group">
<input type="text" name="last_name" id="last_name" class="form-control input-lg" placeholder="Last Name" tabindex="2" value="{{User.last_name}}">
</div>
</div>
</div>
<div class="form-group">
<input type="text" name="user name" id="user_name" class="form-control input-lg" placeholder="User Name" tabindex="3" value="{{User.username}}">
</div>
<div class="form-group">
<input type="email" name="email" id="email" class="form-control input-lg" placeholder="Email Address" tabindex="4" value="{{User.email}}">
</div>
<div class="row">
<div class="col-xs-12 col-sm-6 col-md-6">
<div class="form-group">
<input type="password" name="password" id="password" class="form-control input-lg" placeholder="Password" tabindex="5" value="{{User.password}}">
</div>
</div>
<span class="help-block">By clicking Sign Up, you agree to our Terms and that you have read our Data Use Policy, including our Cookie Use.</span>
<hr class="colorgraph" style="height: 7px; border-top: 0; background: grey; border-radius: 5px;"">
<div class="row">
<div class="col-xs-12 col-md-6 col-md-offset-3"><input type="submit" value="Sign Up" class="btn btn-primary btn-block btn-lg"></div>
</div>
</form>
</div>
Include the following form in your signup.html page and let me know if it works for you:
<form method="post" action="{% url 'signup' %}" class="form-horizontal">
{% csrf_token %}
{% for field in form %}
<div class="form-group">
<label class="col-sm-2 control-label" for="id_{{ field.name }}">{{ field.label }}</label>
<div class="col-sm-10">
<input class="form-control" type="{{ field.field.widget.input_type }}"
name="{{ field.name }}"
id="id_{{ field.name }}"
value="{{ field.value }}" >
</div>
</div>
{% endfor %}
<input type="submit" value="Sign Up" class="btn btn-primary pull-right">
</form>
In your case, the simple solution would be to replace your form inputs with the following ones (this should work if your form fields are ['first_name', 'last_name', 'username', 'email', 'password']):
<input type="text" name="first_name" id="id_first_name" class="form-control input-lg" placeholder="First Name" tabindex="1">
<input type="text" name="last_name" id="id_last_name" class="form-control input-lg" placeholder="Last Name" tabindex="2">
<input type="text" name="username" id="id_username" class="form-control input-lg" placeholder="Username" tabindex="3">
<input type="email" name="email" id="id_email" class="form-control input-lg" placeholder="Email Address" tabindex="4">
<input type="password" name="password" id="id_password" class="form-control input-lg" placeholder="Password" tabindex="5">

field alignments in django crispy forms and bootstrap 3?

I am using django-crispy-forms and Bootstrap 3 in my template rendering.
Here is how my form looks like:
As you can notice, the fields are not aligned correctly. I want them to be inline. please provide suggestions on how to fix this:
My crispy form code is below:
class SortFieldsForm(forms.Form):
latest_year=forms.BooleanField(label="latest year")
newest_entry=forms.BooleanField(label="newest post")
price_order=forms.ChoiceField(
widget=forms.RadioSelect,
label="price order",
choices=(('lowest_price','lowest '),('highest_price','highest'),),
initial="lowest_price",
)
def __init__(self, *args, **kwargs):
self.helper = FormHelper()
self.helper.form_class = 'form-inline'
self.helper.field_template='bootstrap3/layout/inline_field.html'
self.helper.form_method = 'post'
self.helper.form_action = '.'
super(SortFieldsForm, self).__init__(*args, **kwargs)
self.helper.layout = Layout(
InlineRadios('price_order'),
'newest_entry',
'latest_year',
Submit('submit', 'Submit', css_class='button white'),
)
And the generated HTML code:
<form action="." id="id-exampleForm" class="form-inline" method="post" >
<div id="div_id_price_order" class="form-group">
<label for="id_price_order" class="control-label requiredField">
price order
<span class="asteriskField">*</span>
</label>
<div class="controls ">
<label class="radio-inline">
<input type="radio" checked="checked" name="price_order" id="id_price_order_1" value="lowest_price" >lowest</label>
<label class="radio-inline">
<input type="radio" name="price_order" id="id_price_order_2" value="highest_price" >highest</label>
</div>
</div>
<div id="div_id_newest_entry" class="checkbox">
<label for="id_newest_entry" class=" requiredField">
<input class="checkboxinput checkbox" id="id_newest_entry" name="newest_entry" type="checkbox" />
newest post
</label>
</div>
<div id="div_id_latest_year" class="checkbox">
<label for="id_latest_year" class=" requiredField">
<input class="checkboxinput checkbox" id="id_latest_year" name="latest_year" type="checkbox" />
latest year
</label>
</div>
<input type="submit" name="submit" value="Submit" class="btn btn-primary button white" id="submit-id-submit"/>
</form>
This has nothing to do with crispy-forms itself, but rather that you have a label on the radio inputs that is pushing the actual inputs down. You need to add a margin-top style to div_id_newest_entry, submit-id-submit, and div_id_latest_year. For example (your use case may vary a bit), in your CSS file:
#div_id_newest_entry,
#div_id_latest_year,
#submit-id-submit {
margin-top: 25px;
}