Crispy form render manytomanyfield as checkboxes - django

I have a manytomany object in a model form which I want to be rendered as select fields under each other, but whatever I try, i keep getting them next to each other with crispy django forms
class ContactForm(forms.ModelForm):
choice = forms.ModelMultipleChoiceField(label=_('Request'), widget=forms.CheckboxSelectMultiple(),required=False,
queryset=ContactFormChoices.objects.all())
name = forms.CharField(label=_('Name'))
email = forms.EmailField(required=False, label=_('E-mail'))
phone_number = forms.CharField(required=False, label=_('Phone number'))
message = forms.CharField( widget=forms.Textarea , label=_('Message'))
def __init__(self, *args, **kwargs):
super(ContactForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_class = 'form-horizontal'
self.helper.layout = Layout(
Field('name', css_class='input-xlarge'),
Field('email', css_class='input-xlarge'),
Field('phone_number', css_class='input-xlarge'),
Field('message', rows="3", css_class='input-xlarge'),
#'choice',
Field('choice'),
FormActions(
Submit('submit', _('Submit'), css_class="btn-primary")
)
)
class Meta:
model = ContactData
fields = ['name','message','email','phone_number','choice']
and the model:
class ContactFormChoices(models.Model):
'''
The contact form options to show
'''
text = models.CharField(max_length=256)
active = models.BooleanField(default=True)
def __unicode__(self):
return self.text
class ContactData(models.Model):
'''
The contact data (when customer fills in the contact form,
this is mailed and saved here
'''
name = models.CharField(max_length=256,help_text=_("Name"))
phone_number= models.CharField(max_length=256,null=True,blank=True,default=None)
email = models.EmailField(max_length=256,null=True,blank=True,default=None)
choice = models.ManyToManyField(ContactFormChoices,blank=True,default=None)
message = models.TextField()
def __unicode__(self):
return self.name
it looks like this:
Anybody any suggestion?

wow, after searching and trying a lot.... the answer seem to be very simple:
helper.layout = Layout(
Field('name', css_class='input-xlarge'),
Field('email', css_class='input-xlarge'),
Field('phone_number', css_class='input-xlarge'),
Field('message', rows="3", css_class='input-xlarge'),
PrependedText('choice', ''),
FormActions(
Submit('submit', _('Submit'), css_class="btn-primary")
)
)
and partly duplicate to this question and answer: BooleanField checkbox not render correctly with crispy_forms using bootstrap

Related

django can't relabel empty label in TypedChoiceField

I can't seem to relabel the empty label in a form's ModelChoiceField.
I have tried. (note I am using django crispy forms for the form layout - shouldn't interfere with this)
Forms.py
class PaymentForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['payment_day'].empty_label = 'test something'
self.helper = FormHelper(self)
self.helper.label_class = 'sr-only'
self.helper.form_tag = False
self.helper.layout = Layout(
......
PrependedText('payment-day', '<i class="fa fa-calendar"></i>', placeholder="What"),
)
class Meta:
model = DirectDebit
fields = [
......
'payment_day',
]
models.py
class DirectDebit(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL)
......
DAYS_OF_MONTH_CHOICES = [(i, i) for i in range(32)]
payment_day = models.IntegerField(choices=DAYS_OF_MONTH_CHOICES)
time_stamp = models.DateField(auto_now=True)
By the time you set empty_label it may be too late, as the field's choices have already been calculated. Try reassigning the queryset to itself, to see whether that triggers the choices to be recalculated.
super().__init__(*args, **kwargs)
self.fields['payment_day'].empty_label = 'test something'
self.fields['payment_day'].queryset = self.fields['payment_day'].queryset
Solved with:
self.fields['payment_day'].choices = [('', '---- Please select your payment day ----')] + list(
self.fields['payment_day'].choices[1:])

Pass parameters to Django class meta

I am trying to display a form with Django, but I want to remove a field if the user language is 'en'. I would like to avoid doing it in Javascript or doing a second template just for it. So I wonder if it possible to pass parameter to the Meta() class of my UserForm() class. That way I could pass the user and check with an if statement his language.
Here is what I have so far:
class UserForm(forms.ModelForm):
first_name = forms.CharField(required=True, label=_('*First name'))
last_name = forms.CharField(required=True, label=_('*Last name'))
postal_code = FRZipCodeField(required=False, label=_('My postcode'))
birthday = forms.DateField(
widget=forms.DateInput(format='%d/%m/%Y'),
required=False,
input_formats=['%d/%m/%Y'],
label=_('My birthday'))
def __init__(self, *args, **kwargs):
super(UserForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.layout = Layout(
Field('gender'),
Field('first_name'),
Field('last_name'),
Field('birthday'),
Field('country'),
Field('language'),
Field('payment_preference'),
Div('addr1', css_class='hidden', css_id='addr1_container'),
Div('addr2', css_class='hidden', css_id='addr2_container'),
Div('addr3', css_class='hidden', css_id='addr3_container'),
Div('postal_code', css_class='hidden', css_id='pc_container'),
Div('city', css_class='hidden', css_id='city_container'),
ButtonHolder(
Submit('save', _('update'), css_class='pull-right'),
)
)
class Meta():
model = User
fields = (
"first_name", "last_name", "gender", "birthday", "country",
"payment_preference", "addr1", "addr2", "addr3", "postal_code",
"city", "language",)
With an if, I could set two different fields variable in the Meta() class and so show two different forms for each user language.
You can't pass it into the Meta, but you can pass it into the __init__ and hide the field you want to hide:
class UserForm(forms.ModelForm):
# ... as before
def __init__(self, user, *args, **kwargs):
super(UserForm, self).__init__(*args, **kwargs)
if user.language == 'en':
self.fields['field_name'].widget = forms.HiddenInput()
# ... as before
Then when you call the form, pass the user as the first argument:
form = UserForm(request.user, ...)

Django does not render my forms' fields

I have this model in models.py:
class Life_events(models.Model):
patient = models.ForeignKey(Demographic)
HSCT_date = models.DateField('HSCT date',null=True,blank=True)
HSCT_outcome = models.CharField('HSCT outcome',max_length=100, null=True, blank=True)
partaker_in_clinical_trial= models.CharField('Partaker in clinical trial',max_length=200, null=True, blank=True)
date_of_input= models.DateField(null=True,blank=True)
def __str__(self):
return str(self.patient)
My forms.py contains:
class LifeEventsForm(forms.Form):
def __init__(self, *args, **kwargs):
super(LifeEventsForm, self).__init__(*args, **kwargs)
self.helper=FormHelper(self)
self.helper.field_class = 'col-md-8'
self.helper.label_class = 'col-md-3'
self.helper.layout = Layout(
Fieldset (
'<b>HSCT</b>',
Div(
#HTML(u'<div class="col-md-2"></div>'),
Div('HSCT_date',css_class='col-md-6'),
Div('HSCT_outcome',css_class="col-md-6"),
Div('partaker_in_clinical_trial', css_class='col-md-6'),
css_class='row',
),
),
FormActions(
Submit('submit', "Save changes"),
Submit('cancel',"Cancel")
),
)
self.helper.form_tag = False
self.helper.form_show_labels = True
class Meta:
model = Life_events
exclude = ['patient', 'date_of_input']
My views.py has:
my_life_ev = LifeEventsForm(prefix='life_ev')
return render_to_response('input.html', {'frm_life_ev': my_life_ev,}, context)
And my template file input.html has:
{%crispy frm_life_ev%}
When I render my template I can't see the form fields but only the word 'HSCT' which I have in Fieldset. My html code does not contain the fields at all.
Any ideas please?
Your form inherits from forms.Form, which does not know anything about models and ignores the Meta class. You should inherit from forms.ModelForm.
You need to declare a ModelForm. A simple Form won't do.
class LifeEventsForm(forms.ModelForm)

django crispy forms - how to group the fields?

My form is here:
class SortFieldsForm(forms.Form):
LatestyearModel=forms.BooleanField(label="latest year")
LowestPrice=forms.BooleanField(label="lowest price")
HighestPrice=forms.BooleanField(label="highest price")
Newest_Entry=forms.BooleanField(label="latest date")
def __init__(self, *args, **kwargs):
self.helper = FormHelper()
self.helper.form_id = 'id-exampleForm'
self.helper.form_class = 'form-inline'
self.helper.form_method = 'post'
self.helper.form_action = 'sort_posting'
#self.helper.add_input(Submit('submit', 'Submit'))
super(SortFieldsForm, self).__init__(*args, **kwargs)
self.helper.layout = Layout(
#Fieldset(
# 'price',
# 'LowestPrice',
# 'HighestPrice',
),
PrependedText('LowestPrice', ''),
PrependedText('HighestPrice', ''),
PrependedText('Newest_Entry', ''),
PrependedText('LatestyearModel', ''),
ButtonHolder(
Submit('submit', 'Submit', css_class='button white')
)
)
Currently the form shows as this:
I want to group lowest price and highest price in one radioselect,
latest date and latest year as checkboxes neatly aligned with submit button next to the field. Not below them as it currently now.
Any pointers/tips?
Try this out:
class SortFieldsForm(forms.Form):
LatestyearModel=forms.BooleanField(label="latest year")
LowestPrice=forms.BooleanField(label="lowest price")
HighestPrice=forms.BooleanField(label="highest price")
Newest_Entry=forms.BooleanField(label="latest date")
def __init__(self, *args, **kwargs):
self.helper = FormHelper()
self.helper.form_id = 'id-exampleForm'
self.helper.form_class = 'form-inline'
self.helper.form_method = 'post'
self.helper.form_action = 'sort_posting'
#self.helper.add_input(Submit('submit', 'Submit'))
super(SortFieldsForm, self).__init__(*args, **kwargs)
self.helper.layout = Layout(
'LowestPrice',
'HighestPrice',
'Newest_Entry',
'LatestyearModel' ,
ButtonHolder(
Submit('submit', 'Submit', css_class='button white')
)
)
You should use ChoiceField and MultipleChoiceField with labels and custom widgets RadioSelect and CheckboxSelectMultiple.
More explanation
First, some code. I said about CheckboxSelectMultiple but you can do without it. RadioSelect is actually needed for radio buttons. You can place checkboxes and radio buttons after their labels using Bootstrap horizontal form layout.
class SortFieldsForm(forms.Form):
price_order=forms.ChoiceField(widget=forms.RadioSelect, choices=(('lowest', 'Lowest first'), ('highest', 'Highest first')))
newest_entry=forms.BooleanField(label="Latest date")
latest_year=forms.BooleanField(label="Latest year")
helper = FormHelper()
helper.form_class = 'form-horizontal'
helper.label_class = 'col-lg-2'
helper.field_class = 'col-lg-8'
helper.layout = Layout(
'price_order',
'newest_entry',
'latest_year',
Submit('submit', 'Submit', css_class='button white'))
Try to do like this. I cannot guarantee if there is no typos but you can achieve your goals this way.
Also, check out links below:
https://docs.djangoproject.com/en/dev/ref/forms/widgets/
http://django-crispy-forms.readthedocs.org/en/latest/crispy_tag_forms.html#bootstrap3-horizontal-forms
Learn about bootstrap and its classes.

Datetime returning different date to input

I am having some issues with datetime and datepicker. I have a model form with 2 date picker field (To and From), the date can be selected and saved. The problem is, when I go to edit form, the dates seem to show up as either a day ahead/behind of input date or just show up the current date.
My model.py:
from_when = DateTimeField(_('From'), blank=True, null=True)
to_when = DateTimeField(_('To'), blank=True, null=True)
forms.py:
class ScheduleForm(ModelForm):
class Meta:
model = Schedule
fields = ['from_when', 'to_when',]
def __init__(self, *args, **kwargs):
super(ScheduleForm, self).__init__(*args, **kwargs)
self.name = 'scheduleform'
self.title = _('Add/Edit Schedule')
self.helper = FormHelper()
self.helper.form_tag = False
self.form_layout()
def form_layout(self):
self.helper.layout = Layout(
Div(
Div(
Div(
# use the jQuery datepicker plugin, if available
Field('from_when', css_class='datepicker'),
# use the jQuery datepicker plugin, if available
Field('to_when', css_class='datepicker'),
css_class='span4',
),
css_class='row-fluid',
),
),
)
def save(self, force_insert=False,
force_update=False, *args, **kwargs):
course = super(ScheduleForm, self).save(
commit=True, *args, **kwargs)
return course
Any ideas why this problem may occur?