When the page loads I am seeing the error of - "This field is required" with the input form 'Title' highlighted with the red board. I would expect that this should only show after the Save button is pressed. I can toggle the message on and off with self.helper.form_tag but the behavior seems incorrect to me, it seems as though it is trying to submit before I click save.
Am I doing something wrong or is this expected behavior? If it is expected is there a way to change it to only show the warnings after Save?
forms.py
from django import forms
from .models import Request, RequestDocument
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Field, Div, Layout
class RequestForm(forms.Form):
title = forms.CharField(widget=forms.TextInput(attrs={'placeholder': 'title'}))
rfp_No = forms.CharField(widget=forms.TextInput(attrs={}), required=False)
company_Name = forms.CharField(widget=forms.TextInput(attrs={}), required=False)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.helper = FormHelper()
#self.helper.form_tag = False
self.helper.help_text_inline = True
self.helper.layout = Layout(
Div(Field('title'), css_class='col-md-12', ),
Div(
Div(Field('rfp_No'), css_class='col-md-6', ),
Div(Field('company_Name'), css_class='col-md-6', ),
css_class='row',
),
)
create.html
{% extends "base.html" %}
{% load crispy_forms_tags %}
{% block content %}
<form method="post">
{% csrf_token %}
{% crispy form %}
<button type="submit" class=" d-block btn btn-lg btn-success mt-4 w-50 mx-auto">
Save
</button>
</form>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-3.3.1.min.js"></script>
<script>
$(document).ready(function(){
$(".active").removeClass("active");
$("#link-create").addClass("active");
});
</script>
adding self.helper.form_show_errors = False to the init hides the errors but this the block actual errors from showing such as if the max length was exceeded.
I eventually figured this out by splitting the POST and GET methods in my form.
forms.py
form = RequestForm()
if request.method == 'POST':
##Do Post Stuff
elif request.method == 'GET':
##Do Get Stuff
else:
context = {
}
return render(request, "requests/create.html", context)
Related
I use HTMX to allow the a user to add multiple documents to upload, each document has a Boolean field and I cannot get the value from the Boolean field correctly. I'd want to get a list of can_share so I can loop over them in order to save each with it's corresponding document, Ideally can_share = document_form.cleaned_data.getlist('can_share')
can_share = document_form.cleaned_data['can_share']
returns only one True/False value even if there are multiple instances.
can_share = request.POST.getlist('can_share')
returns nothing if the checkbox is not selected, even though I have tried to set the initial to False.
forms.py
class RequestDocumentForm(forms.ModelForm):
can_share = forms.BooleanField(initial=False, required=False)
class Meta:
model = RequestDocument
fields = ['document', 'can_share']
widgets = {
'document': ClearableFileInput(attrs={'multiple': False, 'required': False}),
}
def __init__(self, *args, **kwargs):
super(RequestDocumentForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_tag = False
self.helper.disable_csrf = True
self.helper.layout = layout.Layout(
Div(
Div(
Div(Field('document'), css_class='col-md-11', ),
Div(Field('can_share'), css_class='col-md-1', ),
css_class='row',
),
),
)
create.html
{% load crispy_forms_tags %}
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{% crispy form %}
<button hx-get="/rq/create/add-doc/" hx-trigger='click'
hx-target='#add-document' hx-swap='beforeend swap:0.2s'>Add Document
</button>
<div id='add-document'>
</div>
<button type="submit" class="d-block btn mt-4 w-50 mx-auto">
Save Request
</button>
add-document-partial-html
{% load crispy_forms_tags %}
{% load static %}
<div id='request-container'>
<div class="row">
<div class="col-md-12">
{% crispy document_form %}
</div>
</div>
view.py
def upload_docuements_view(request):
template = "requests/create.html"
if request.method == 'POST':
document_form = RequestDocumentForm(request.POST or None, request.FILES or None)
context = {
'document_form': document_form
}
files = request.FILES.getlist('document')
# can_share = request.POST.getlist('can_share')
if document_form.is_valid():
can_share = document_form.cleaned_data['can_share']
## code to save
return redirect('/')
else
document_form = RequestDocumentForm()
context = {
'document_form': document_form
}
return render(request, template, context)
I'm trying to render this form:
class LoadForm(forms.Form):
class Meta:
model = Load
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_tag = False
self.helper.layout = Layout(
Row(
'whouse',
'supplier',
'company',
'product',
'quantity',
'unit_price',
'load_date',
)
)
with the following view:
def load(request):
form = LoadForm()
context = {
'form': form,
'title': 'Nuovo Carico',
}
return render(request, 'warehouse/load.html', context)
and the following template:
{% extends "masterpage.html" %}
{% load static %}
{% block headTitle %}
<title>{{title}}</title>
{% endblock %}
{% block contentHead %}
{% endblock %}
{% block contentBody %}
{% load document_tags %}
{% load custom_tags %}
{% load crispy_forms_tags %}
<FORM method="POST" autocomplete="off">
{{ form.media }}
{% csrf_token %}
<div class="alert alert-info">
{{ title }}
</div>
{% crispy form %}
<input type="submit" class="btn btn-primary margin-left" value="CARICA">
</FORM>
{% endblock %}
For some strange reason the form will not show up, I just see the title and the input button. I've tried the very simple form.as_p with no crispy, but still nothing...
By looking at the sourse code on the browser I see there is a div with class 'form-row' but not form in it...
looks strange.
Any help?
thank you very much.
Carlo
Your form class is defined as follows: class LoadForm(forms.Form): Note that here this is a Form and not a ModelForm hence using a Meta class and specifying model makes no difference. Instead you want to use a ModelForm [Django docs] and you also need to specify either fields or exclude in the Meta:
class LoadForm(forms.ModelForm): # `ModelForm` here
class Meta:
model = Load
fields = '__all__' # All fields
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_tag = False
self.helper.layout = Layout(
Row(
'whouse',
'supplier',
'company',
'product',
'quantity',
'unit_price',
'load_date',
)
)
Call form in template like this. First the name of the form you have in context plus pipe crispy. It works for me.
</div>
{{form|crispy}}
<input type="submit" class="btn btn-primary margin-left" value="CARICA">
I am making a Django form but not able to pass the form as a "POST" method. When I press the submit button, the form information is sent as "GET" which I can see by printing on the terminal. Hence the if condition in the code remains false. Please help me figure out what is going wrong here.
Below is the code for the rendering the template.
# Code for the /template.py#
{% block content %}
<div class="container">
<div class="row">
<div class="col-sm-8">
<h1>Please answer the question</h1>
<form method="post">
{% crispy user_form user_form.helper %}
<p><input type="submit" class='btn btn-primary' value="Submit"
method = "post"></p>
{% csrf_token %}
</form>
</div>
</div>
</div>
{% endblock %}
Below is the code in the views.py file.
# /*Code for the /views.py*/
def launch_survey(request, pagelink):
pagelink_html = pagelink+".html"
user_form = FormQuestionaire()
print(request.method)
if (request.method == 'post'):
print("We are not here")
user_form = FormQuestionaire(request.POST)
if user_form.is_valid():
print('Validation Success')
print("NAME: "+user_form.cleaned_data['First_name'])
return render(request, "modern_business/"+pagelink_html, {'user_form':user_form})
Below is the code in the forms.py file.
# /*FORMS.PY*/
from django import forms
from firstapp.models import Questionaire
from crispy_forms.helper import FormHelper
from django.core import validators
class FormQuestionaire(forms.ModelForm):
helper = FormHelper()
helper.form_show_labels = True
helper.form_class = 'form-group row'
helper._form_method = "post"
CHOICES = [('1', 'First'), ('2', 'Second')]
choice_field = forms.ChoiceField(choices=CHOICES,
widget=forms.RadioSelect,
label = "Do you like this website?", initial = '1',
required = True,)
mult_field
= forms.ChoiceField
(widget=forms.CheckboxSelectMultiple,
choices=CHOICES,
label = "Do you like our Checkbox?", required = True,)
class Meta:
model = Questionaire
fields = ['First_name', 'Last_name', 'email', 'paid']
labels = {'First_name': ('Enter Your first name') ,
'Last_name': ('Enter your last name'),
'Enter your email': ('Whether it is paid'),}
print(request.method) always prints GET even though form is set to POST.
The method is always in all caps.
if request.method == 'POST':
I try to enhance my all auth's signup form with Crispy-form but it's not working :)
I modify the allauth form in the forms.py to hide the labels and add the button
My current problem is that the "self.helper.layout = Layout" in the forms.py makes the fields to disappear in the template, but if I comment the self.helper.layout = Layout, I don't have a button to validate my form x(
I would like to have my fields and a working submit button for my form,
Thanks for your help!
details below
forms.py
from django import forms
from allauth.account.forms import SignupForm
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, ButtonHolder, Submit,Field
from crispy_forms.bootstrap import FormActions
class MySignupForm(SignupForm):
def __init__(self, *args, **kwargs):
super(MySignupForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_show_labels = False
self.helper.layout = Layout(
FormActions(
Submit('submit', 'Sign-up', css_class = 'btn-primary')
),
)
I also define in my settings.py that I was using a custom form as signup
# CUSTOM : Allauth Setup part
AUTHENTICATION_BACKENDS = (
# Needed to login by username in Django admin, regardless of `allauth`
'django.contrib.auth.backends.ModelBackend',
# `allauth` specific authentication methods, such as login by e-mail
'allauth.account.auth_backends.AuthenticationBackend',
)
ACCOUNT_EMAIL_REQUIRED = True
ACCOUNT_AUTHENTICATED_LOGIN_REDIRECTS = False
SOCIALACCOUNT_QUERY_EMAIL = ACCOUNT_EMAIL_REQUIRED
#Since users don't have account on the landing page, sign up redirect to thank you page
LOGIN_REDIRECT_URL = '/thank-you'
ACCOUNT_FORMS = {'signup': 'public.forms.MySignupForm'}
I overrided the allauth template with this version
{% extends "base.html" %}
{% load socialaccount %}
{% load crispy_forms_tags %}
{% load i18n %}
{% block head_title %}{% trans "Signup" %}{% endblock %}
{% block content %}
<section id="contact">
<div class="row">
<div class="container">
<div class="col-lg-12 text-center">
<h1 class="section-heading">{% trans "Sign Up" %}</h1>
</div>
<form class="signup" id="signup_form" method="post" action="{% url 'thankyou' %}">
{% crispy form %}
</form>
</div>
</div>
</section>
{% endblock %}
{% crispy form %} already declares by itself <form></form>.
I think this double declaration of <form> confuses the browser.
replace:
<form class="signup" id="signup_form" method="post" action="{% url 'thankyou' %}">
{% crispy form %}
</form>
by:
{% crispy form %}
and insert into forms.py:
class MySignUpForm(SignupForm):
def __init__(self, *args, **kwargs):
super(MySignUpForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_id = 'signup_form'
self.helper.form_class = 'signup'
self.helper.form_method = 'post'
self.helper.form_action = reverse('thankyou')
# and then the rest as usual:
self.helper.form_show_labels = False
self.helper.add_input(Submit('signup', 'Sign Up'), css_class='btn btn-primary'))
Hi Stackoverflow people,
I would like to style a formset with the crispy app, but it causes some grieve.
A very simple model should be presented four times.
class ItemPicture(models.Model):
item = models.ForeignKey('Item')
picture = ThumbnailerImageField(_('Image'),
upload_to='pictures/', null=True, blank=True,)
The form class is also straightforward:
class ItemPictureForm(forms.ModelForm):
class Meta:
model = ItemPicture
fields = ('picture',)
def __init__(self, *args, **kwargs):
self.helper = FormHelper()
self.helper.form_tag = False
self.helper.layout = Layout(
Fieldset(_('Add pictures'),'picture', ),
ButtonHolder(
Submit('save', _('Add'), css_class='btn btn-primary '),
Reset('reset', _('Cancel'), css_class='btn')))
super(ItemPictureForm, self).__init__(*args, **kwargs)
In my views.py, I generate the formset:
class ItemUploadPictures(FormView):
ItemPictureFormSet = formset_factory(ItemPictureForm, extra=4)
form_class = ItemPictureFormSet
template_name = 'item_upload_pictures.html'
success_url = reverse_lazy('dashboard')
My trouble is that crispy expects {% crispy formset formset.form.helper %} in the template, but it seems that the passed-through variable is form.
{% crispy form %} works, but no helper attributes will be displayed. How can I pass the entire formset information to the template?
Thank you for your suggestions.
Have you tried
{% crispy formset form.form.helper %}
forms.py
class ItemPictureForm(forms.ModelForm):
class Meta:
model = ItemPicture
fields = ('picture',)
def __init__(self, *args, **kwargs):
self.helper = FormHelper()
self.helper.form_tag = False
self.helper.layout = Layout(
Fieldset(_('Add pictures'),'picture', ),
# These need to be removed because they cant be prevented from duplicating
# ButtonHolder(
# Submit('save', _('Add'), css_class='btn btn-primary '),
# Reset('reset', _('Cancel'), css_class='btn')
))
super(ItemPictureForm, self).__init__(*args, **kwargs)
manage_pictures.html
{% load crispy_forms_tags i18n %}
<form action="" method="post">
{% csrf_token %}
{% crispy formset formset.form.helper %}
<div class="form-actions">
<input type="submit" name="save" value="{% trans "Add" %}" class="btn btn-primary" id="submit-id-save">
<input type="button" name="reset" value="{% trans "Cancel" %}" class="btn" id="button-id-cancel">
</div>
</form>
{% crispy formset formset.form.helper %}
Maybe this library serves your needs: https://github.com/runekaagaard/django-crispy-forms-fancy-formsets