How add a * after required fields in django modelform? - django

i have a django modelform that some of it's fields are required. i'm using {{ form.as_p }} and i'm not accessing the fields individually.
so how can i add a star (*) for that required fields in the form ?

If you will not be accessing the fields individually (such as using {{ form.as_p }}), then you can add a property to your ModelForm:
class FooForm(forms.ModelForm):
required_css_class = 'required'
That will define all fields that are required as having the 'required' class
Then you can add the asterisk using CSS :
<style type="text/css">
.required:after { content: '*'; }
</style>

The easiest way is to change the label
class Form(ModelForm):
model = <model>
labels = {
"<field_name>": "<label>*",
}
or you can set an id for the field using widgets and set a label for that id:
class Form(ModelForm):
model = <model>
widgets = {
"<field_name>": "<widget_obj>(attrs={"id": "<id>"})*",
}

Related

How to specify custom CSS classes for WTForms custom fields / subfields

How do I specify sperate custom classes for subfields in a multi-field WTFForm field / custom field?
I created a form with one field that is a custom field to make list box of checkboxes:
class MultiCheckboxField(SelectMultipleField):
widget = widgets.ListWidget(prefix_label=False)
option_widget = widgets.CheckboxInput()
That field is placed on a form:
class Categories(FlaskForm):
categories = MultiCheckboxField()
The form is rendered with Jinga:
#app.route('/test/', methods=['GET'])
def test():
form = Categories()
form.categories.choices = categorylist()
return render_template('test.html', form=form )
I specify a custom class name in the template that gets assigned to the element correctly
{{ form.categories(class = 'custom class') }}
That renders the UL with the desired class name to the <ul> but not the underlying <li> items in the list. I want to specify a different class name to the <li> elements:
<ul class = "custom class">
<li></li>
I want to set a different custom class for the underlying elements in the custom field, in this case a <li> element, but could be something else for another custom field. I am stumped where to hook in this custom sub-field class name in the process. Any help is appreciated.
Ideally:
<ul class = 'custom class'>
<li class = 'another custom class'>
Any help is greatly appreciated.

how can I add attribute to field label in Django forms?

I have a solution that I add form fields in the template individually like {{form.title}}, {{form.summary}}, and so on, and then hardcoding the label in the template. is there any better way to add attributes to field labels using Django and actually I don't know the cons of my current solution
==== here i putted code with model form change label ===
class UserCreateForm(forms.ModelForm):
class Meta:
model = User
fields = ['username','first_name','last_name','email', 'password', 'is_active','is_staff','is_superuser']
widgets = {
'username':forms.TextInput(attrs={'class':'form-control input_for_form','placeholder':'Enter Username','autofocus':True}),
'first_name':forms.TextInput(attrs={'class':'form-control input_for_form','placeholder':'Enter Firstname'}),
'last_name':forms.TextInput(attrs={'class':'form-control input_for_form','placeholder':'Enter Lastname'}),
'email':forms.EmailInput(attrs={'class':'form-control input_for_form','placeholder':'Enter E-Mail'}),
'password':forms.TextInput(attrs={'class':'form-control input_for_form','placeholder':'Enter Password'}),
'is_active':forms.CheckboxInput(attrs={'class':'mx-auto','id':'toggle'}),
'is_staff':forms.CheckboxInput(attrs={'class':'mx-auto','id':'is_staff_user'}),
'is_superuser':forms.CheckboxInput(attrs={'class':'mx-auto','id':'is_super_user'}),
}
labels = { # === this is for customize field label ===
'username':'Username',
'first_name':'Firstname',
'last_name':'Lastname',
'email':'E-Mail',
'password':'Password',
'is_active':'Active',
'is_staff':'Staff',
'is_superuser':'Super',
}
=== in html you can render like this ===
<div class="mb-3">
<label class="form-label">{{form.username.label}}</label>
{{form.username}}
</div>

Add ID field to ModelForm

I need to add ID field to my form, and I'm getting so mad
Currently I have :
class ProductVideoForm(forms.ModelForm):
class Meta:
model = ProductVideo
translatable_fields = get_translatable_fields(ProductVideoTranslation)
fields = [
"product",
"id", #added!!!!
"type",
"placeholder",
] + translatable_fields
widgets = {
"placeholder": ImageInput(),
}
trans_fields_per_lang = get_trans_fields_per_lang(translatable_fields)
I added ID to fields, and the template is:
{{ video_formset.management_form }}
Why Is ID not displayed ??
actually, I just need display it, not updated.
Yea ok, but by default django will not display editable=False fields in forms.
What you are looking for is disabled param.
https://docs.djangoproject.com/en/4.1/ref/forms/fields/#disabled

django form field displayed out of order

I have this form and model for a group:
class GroupForm(forms.ModelForm):
class Meta:
model = Group
fields = ('leader', 'description', 'size', 'max_size', 'motto')
widgets = {
'size': forms.CheckboxInput(attrs={'id': 'size'}),
'max_size': forms.TextInput(attrs={'type': 'hidden', 'id': 'maxSize'}),
}
The creator of the group has an option to check yes for size and on doing so, I used javascript to change the type of max_size to show.
In my create_group.html template:
<script>
let size = document.getElementById('size')
let maxSize = document.getElementById('maxSize')
let checked = false
size.onclick = () => {
checked = !checked
if (checked === true) {
maxSize.type = 'show'
} else {
maxSize.type = 'hidden'
}
}
</script>
Now, this works fine, the only problem is that the fields are displayed out of order.
When the page loads, max_size is false and its field is not displayed. Which is good. However, when the user checks that group has a size, and, subsequently, the max_size has a display of show, the field shows up after the motto field and not in its correct order according to fields = ('leader', 'description', 'size', 'max_size', 'motto').
Furthermore, the max_size field is included inside the motto element itself and not as its own field:
vs. the other fields which are all in their own <p></p>.
I'm guessing that {{form.as_p}} etc. render all the visible fields first, then the hidden ones.
You can explicitly render the fields in the order you want in your template. Rather than hardcoding the order in your template, maybe this (I've never tried this):
FIELD_ORDER = ( ('leader', 'description', 'size', 'max_size', 'motto')
class GroupForm(forms.ModelForm):
class Meta:
model = Group
fields = FIELD_ORDER
Pass to your template a list of fields explicitly in the order you want:
fields_in_order = [ form[x] for x in FIELD_ORDER ]
In the template
{% for field in fields_in_order %}
{{field}}
{% endfor %}
Or, you can make the hiding of this field something done by JS
If anyone else comes across this issue, it's also possible to just use js and css. Right now, I'm using javascript to see if size is checked and if it is then maxSize.style.display = 'block' vs maxSize.style.display = 'none' if size isn't checked.
Then I had the issue of django's form label still being visible. To fix that I saw an answer on dev.to which you can see for yourself.
My issue now is that I don't know how to add a label that is only visible when the form field is visible.

Django Autocomplete Light - FK Field Results not Forwarding

I'm following along in the DAL documentation to add a filtered field to my form, but the forwarding isn't working to connect one field to the other:
Forms.py
class PurchaseForm(forms.ModelForm):
commodity = forms.ModelChoiceField(
queryset=Commodity.objects.all(),
widget=autocomplete.ModelSelect2(url='commodity-autocomplete'),
required=False,
)
class Meta:
model = Purchase
fields = ["variety"]
widgets = {
'variety': autocomplete.ModelSelect2(url='variety-autocomplete', forward=['commodity'],
}
Views.py
class VarietyAutocompleteView(autocomplete.Select2QuerySetView):
def get_queryset(self):
qs = Variety.objects.all()
commodity = self.forwarded.get('commodity', None)
print("Commodity:" + str(commodity))
if commodity:
qs = qs.filter(commodity=commodity)
if self.q:
qs = qs.filter(name__istartswith=self.q)
return qs
I'd like my Variety choices to be filtered by their foreign key relationship to Commodity objects. Both autocomplete fields are working on their own just fine, but the choice from the commodity field is not being forwarded to the VarietyAutocompleteView (my print command prints Commodity:None). Is this perhaps because I am passing a foreign key object? Or have I set this up incorrectly somehow?
I had to scrap DAL and move to Bootstrap Combobox. It turned out to be really easy to implement, provided you are using the Bootstrap libraries.
This is how it is set up:
Add class combobox to the select widget:
forms.py
from django import forms
from Business.models import Company, Branch
from .models import Variety
class PurchaseForm(forms.ModelForm):
variety = forms.ModelChoiceField(
queryset=Variety.objects.all(),
widget=forms.Select(attrs={'class': 'combobox'}),
required=False
)
class Meta:
model = Purchase
fields = [
"invoice", "contract_date", ...
]
Then, insert the simplest javascript snip ever:
inventory_report.html
....
<td style="padding-bottom: 10px">
<div>Supplier:</div>
<div>{{ view.purchase_form.supplier }}</div>
</td>
....
{% block scripts %}
<script type="text/javascript" src="http://code.jquery.com/ui/1.10.3/jquery-ui.js"></script>
<script type="text/javascript" src="{% static 'js/bootstrap-combobox.js' %}"></script>
$(document).ready(function(){
// Set Text Autofields on New Contract
$('.combobox').combobox();
});
</script>
{{ view.purchase_form.media }}
{% endblock %}
That's all there is to it.
I'll add for anyone else like me who is thinking "yeah, but I still really don't want to change" - that in practice the line:
'variety': autocomplete.ModelSelect2(url='variety-autocomplete', forward=['commodity'])
Really did not work for me either, but changing it to something like:
'variety': autocomplete.ModelSelect2(url='variety-autocomplete', forward=('commodity', ))
Did work. Notice that it's a tuple so you need to have a "," there to make it work, as it's supposed to be an iterable value.
I didn't dig much further into why an array is part of the docs and yet doesn't work, but that was the critical change that make my variant work.
Also - I was using a formset (so there were prefixes) and that proved to not be a problem.