Django DetailView - display boolean from models as checkboxes - django

There's a number of snippets to display booleans in Django Forms as checkboxes (i.e. specifying Checkbox as a widget). For instance (assuming a boolean field defined in the model for bar):
class FooForm(forms.ModelForm):
class Meta:
model = Foo
fields = ['bar']
widgets = {
'bar' : CheckboxInput(attrs={'class': 'required checkbox form-control'}),
}
However I also need to display a (disabled) checkbox in DetailView (client says so). But I can't figure out an elegant way to do this, since I don't have a form meta for details view...
My current thinking is something like this (bootstrap checkbox):
<div class="form-check">
<label class="form-check-label">
<input type="checkbox" {% if foo.bar %}checked{% endif %} disabled>Bar
</label>
<\div>
Any way to accomplish this in a fashion closer to the Form's widgets?

in the view get you form and set initial value
get the model object and set bars initial value
form = YourForm(initial={'bar':modelObject.bar })
and then send the form to the template and simply render
like form.bar
you can disable this with many ways
like
class FooForm(forms.ModelForm):
class Meta:
model = Foo
fields = ['bar']
widgets = {
'bar' : CheckboxInput(attrs={'class': 'required checkbox form-control','disabled':'disabled or true'}),
}
or find and use any template filter to add attribute to form field

Related

Can django widget_tweaks render out input as textarea box?

I want to render out an input box as textarea with widget_tweaks in Django.
This is my code:
<div class="form-row">
<div class="form-group col-md-6">
<label>More information *</label>
{% render_field form.info class="form-control" %}
</div>
</div>
Everything is working fine, but it renders out as <input> tag. Is there any way to render it out as <textarea> without changing the models from CharField to TextField? I want to have a bigger box so there is more space to write the text. I know I can add a class that could change the size of the input box, but the textarea tag would be easier.
You can render CharField as textarea by specifying widget in your forms.py.
text = forms.CharField(widget=forms.Textarea)
or to set default width and height of textarea
text = forms.CharField(widget=forms.Textarea(attrs={"rows":3, "cols":10}))
There are two ways to incorporate this to your forms.py.
preferred way especially if you want to add widgets to multiple fields.
class MyModelForm(forms.ModelForm):
class Meta:
model = MyModel
fields= ('text', 'field2')
widgets = {
'text': forms.Textarea(attrs={"rows":3, "cols":10})),
'field2': forms.RadioSelect(attrs= {
'class': 'choice_class'})
}
Note that although widget can add class, I think it is better to add css class or id using widget-tweaks at template level rather than widget.
another way in forms.py. This way works well when you want to add widgets to one or two fields.
class MyModelForm(forms.ModelForm):
text = forms.CharField(widget=forms.Textarea(attrs={"rows":3, "cols":10})
class Meta:
model = MyModel
fields = ('text', 'field2',)

How to add datepicker and timepicker to Django forms.SplitDateTimeField?

I have a form that splits the date and time from a datetime field in the model.
class MyForm(forms.ModelForm):
class Meta:
model = MyModel
fields = ('name', 'description', 'start', 'end',)
widgets = {
'start': forms.SplitDateTimeWidget(),
'end': forms.SplitDateTimeWidget(),
}
How can I add a datepicker and timepicker to each separate input box that is rendered?
Setting:
'start': forms.SplitDateTimeWidget(attrs={'type': 'date'})
makes both inputs datepicker but I need the second one to be a timepicker..
I am using Django 2.0, bootstrap and crispy forms
forms.SplitDateTimeWidget() renders an Html input that may contain some attributes that you will need in your template:
forms.SplitDateTimeWidget(attrs={'attrs': 'attrs'})`.
# You don't need to edit the "input:type", type text is good
The rendering will be something like that
<input type='text' name='field_name_0' id='id_field_name_0' attrs='attrs'>
<input type='text' name='field_name_1' id='id_field_name_1' attrs='attrs'>
According to the documentation, New in Django 2.*
You can add seperate attributes.
# Free to add attributes that you want
'start': forms.SplitDateTimeWidget(
date_attrs({'class':'datepicker'}), # or override the ID, "id":id
time_attrs({'class':'timepicker'}),
)
Since I do not know what kind of Datetime neither Timepicker that you use in your project. So, in your js call each of them by their conventional name class...
$(".datepicker").datepicker();
$(".timepicker").timepicker();

Get object fields from ForeignKey in RadioSelect

I have a model with a ForeignKey field and a form to create and update the objects.
I choose the ForeignKeyField with a RadioSelect widget and loops through the radio inputs in the template with {% for radio in form.foreign_key_items %}{{ radio.tag }} - {{ radio.choice_label }}{% endfor %}.
My form is:
class ItemForm(ModelForm):
class Meta:
model = Item
fields = ('foreign_key_item',)
widgets = {'foreign_key_item': RadioSelect,}
But the choice_label is not enough information for the user to select the correct object.
How is it possible to print fields from the foreign_key_item objects when I print each radio?
You can compile all the appropriate information in the view and add it to the context that is rendering the form. Alternatively, you can probably use select_related.

How to write view from ModelChoiceField response?

I'm new to Django forms and am getting hung up on something that seems like it should be very simple.
I want to create a dropdown selector that directs users to detail pages, one for each year.
In models.py I have:
class Season(models.Model):
year = models.IntegerField(unique = True, max_length=4, verbose_name = "Season (year)")
…
class season_choice(forms.Form):
choice = forms.ModelChoiceField(queryset=Season.objects.all().order_by('year'), empty_label="Season")
class Meta:
model = Season
In my template:
<form action="/season_detail/{{ choice.year }}" method="get">
{{ season_choice.as_p }}
<input type="submit" value="Go" />
</form>
The dropdown selector shows up fine, producing choices formatted like so:
<select id="id_choice" name="choice">
<option selected="selected" value="">Season</option>
<option value="1">1981</option>
<option value="2">1982</option>
<option value="3">1983</option>
…
Choosing and submitting a year, for instance 1983, now takes me to /season_detail/?choice=3 when what I what is something like /season_detail/?choice=1983
I assume I need to write that into views.py, but after reading through the Django docs and searching through the forum here and trying several approaches I'm more confused than ever.
It looks like you're mixing forms.Form and forms.ModelForm in class season_choice based on your use of forms.Form but also declaring a Meta class.
If you need a different form widget than the model default, you can over ride it in the Meta class if using a ModelForm. When using ModelForms it's best practice to explicitly list the fields to be displayed so that future fields (potentially sensitive ones) are not added by default.
class SeasonForm(forms.ModelForm):
class Meta:
model = Season
fields = ['year']
widgets = {
'year': forms.widgets.Select(),
}
Django models also have a Meta class that will allow you to provide a default ordering:
class Season(models.Model):
year = ...
class Meta:
ordering = ['-year']
If you don't want the entire Model class to have that ordering, you can either change this in your view or create a proxy model, then in your form use model = SeasonYearOrdering.
class SeasonYearOrdering(Season):
class Meta:
ordering = ['-year']
proxy = True
Another item of interest is the hard coded url in your template. You can give the urls in your urls.py names. Then in your template, you can reference these names so that if your urls.py path ever changes, your templates refer to the name and not the hard coded path.
So:
<form action="/season_detail/{{ choice.year }}" method="get">
Becomes (season_detail is the name from urls.py):
<form action="{% url "season_detail" choice.year %}" method="get">
You may change the value of option by adding to_field_name='year' to the choice ModelChoicefield in the form.
So you'll get
<option value="1981">1981</option>
<option value="1982">1982</option>
<option value="1983">1983</option>

Django: Render a form field as editable text field only once and a readonly there after

I have typical profile/account settings form. So as expected you would be having a "name" field and a "domain" field(which will be used as like a website url: maddy.mywebsite.com). This domain field needs to be editable only once. Once set to one thing, will not be made editable later(since this is like a site url).
At the model level, I am comparing created_on and modified_on of that object(userprofile) and validating "domain" value saving. But at the form level, how do I customize the rendering of that field alone based on the condition I have taken ?
Note 1: I don't want to move the "domain" field to the signup page.
Note 2: I am trying to use normal forms(django.forms) and not a ModelForm.
You may try using two htmls, One for create profile and one for editing profile. Render the complete form in create profile and for editing profile if you use same django you may disable the #id_name and #id_domain filed by using either css or javascript. An implementation using js:
<script type="text/javascript">
var domain = document.getElementById("id_domain");
var name = document.getElementById("id_name");
domain.value = "{{ domain }}";
name.value = "{{ name }}";
domain.readOnly = true;
</script>
This looks tricky, you can read some of the following for some ideas:
In a Django form, how do I make a field readonly (or disabled) so that it cannot be edited?
http://lazypython.blogspot.com/2008/12/building-read-only-field-in-django.html
None of those are particularly simple though, so I'd suggest (as did #dcrodjer):
Creating two forms, one for creating, one for editing. On the editing form, remove the Domain field so it's not required/won't be saved:
# forms.py
class AddForm(ModelForm):
class Meta:
model = UserProfile
fields = ('name','domain',)
class EditForm(ModelForm):
class Meta:
model = UserProfile
fields = ('name',)
In your view, creating the appropriate form, and in your template, rendering different HTML depending on which form you've been given:
{% if form.domain %}
{{form.domain.label_tag}}: {{form.domain}} {{form.domain.errors}}
{% else %}
Domain: <input type="text" disabled="disabled" value="{{userprofile.domain}}"/>
{% endif %}