I have a model named "Product" and it has an attribute like price, quantity, and remarks.
Thru the models.py, if remarks has a property of "null=True", it will return a value "None" but I want it to be a dash(-). If you will be adding a "default='-'" into the remarks column in the model, once its form is created and loaded, it has a dash('-') on it but I want nothing on the form when it's loaded. Do you have any ideas if that's possible?
Maybe you should try a clean method on the form.
def clean_<property>(self):
property = self.cleaned_data['property']
if not property:
return "-"
I haven't tested the code but it should work out
https://docs.djangoproject.com/en/4.0/ref/forms/validation/#cleaning-a-specific-field-attribute
I think you can set the custom initial value of the form
class ProductForm(forms.ModelForm):
... fields here ...
def __init__(self, *args, **kwargs):
... other code ...
initial = kwargs.pop('initial', {})
remark_value = initial.get('remarks')
initial.update("remarks", "" if remark_value == "-" else remark_value)
kwargs['initial'] = initial
super(ProductForm, self).__init__(*args, **kwargs)
You have more options but here is 2 you can do:
If you want set default="-" you have to override the form __int__() method
so the form would looks like
class MyForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
#creating
self.fields['your_field'].initial = " "
# updating
if self.instance.pk:
self.fields['your_field'].initial = self.instance.your_field
If you do not want set default you have to override the model save() method
class MyModel(models.Model):
def save(self, *args, **kwargs):
if not self.your_field:
self.your_field = "-"
return super(MyModel, self).save(*args, **kwargs)
Related
I am trying to create a form with a multiple-choice field. I have a SchoolClass model and I want to select multiple classes in the form. I can select SchoolClasses in the form but it doesn't show anything as label. I don't know how to pass a name to the choice field.
Here is the form:
class ExamForm(forms.Form):
def __init__(self, class_choices, teacher_choices,teacher, *args, **kwargs):
super(ExamForm, self).__init__(*args, **kwargs)
self.fields['classes'].choices=SchoolClass.objects.filter(school_id=teacher.school_id)
I am getting SchoolClass objects for choices
classes = forms.MultipleChoiceField(choices=(), widget = forms.CheckboxSelectMultiple,
label = "Classes for this exam.")
When I run my project it shows like that :
Blank choice fields
The choices expect an iterable of 2-tuples where the first item is the key, and the second one the rendered value.
You thus can implement this with:
def __init__(self, class_choices, teacher_choices,teacher, *args, **kwargs):
super(ExamForm, self).__init__(*args, **kwargs)
self.fields['classes'].choices = [
(s.pk, str(s))
for s in SchoolClass.objects.filter(school_id=teacher.school_id)
]
It might however be better to use a ModelMultipleChoiceField [Django-doc], since then we can simply use the queryset, so something like:
class MyForm(forms.Form):
classes = forms.ModelMultipleChoiceField(
queryset=SchoolClass.objects.none(),
widget = forms.CheckboxSelectMultiple,
label = 'Classes for this exam.'
)
def __init__(self, class_choices, teacher_choices,teacher, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['classes'].queryset = SchoolClass.objects.filter(school_id=teacher.school_id)
I have a cbv create view that displays a modelform.
I want to preselect a foreignkey field which is displayed as select choice field.
My problem is that kwargs.get('building_id') in modelform returns None
class VlanCreateForm(ModelForm):
class Meta:
model = Vlan
fields = ['number','description','network','building']
def __init__(self, *args, **kwargs):
building_id = kwargs.get('building_id')
super().__init__(*args, **kwargs)
self.fields['building'].initial = building_id
building is a foreign key to buildings. If I put a constant like self.fields['building'].initial = 1 it is working
class VlanCreateView(CreateView):
model = Vlan
form_class = VlanCreateForm
and the url is
vlan/building/<int:building_id>/create
so I call it like
vlan/building/1/create
You'll need to define the building id in get_form_kwargs
class VlanCreateView(CreateView):
...
building_id=None
def dispatch(self, request, *args, **kwargs):
# Retrieves the building id from url
self.building_id=kwargs.get("building_id")
return super().dispatch(request, *args, **kwargs)
def get_form_kwargs(self, *args, **kwargs):
kwargs=super().get_form_kwargs(*args, **kwargs)
## Sends building id to the form
kwargs["building_id"]=self.building_id
return kwargs
class VlanCreateForm(ModelForm):
class Meta:
model = Vlan
fields = ['number','description','network','building']
def __init__(self, *args, **kwargs):
self.building_id = kwargs.get('building_id')
super().__init__(*args, **kwargs)
self.fields['building'].initial = self.building_id
def post_url(self):
return reverse('app_name:url_name',kwargs={'cg_id':self.building_id} )
In form post action use this post_url for submit form.
then you got the building_id in your view kwargs
class Model_Neural_form(forms.ModelForm):
allMod = forms.ModelChoiceField(queryset=Model_Neural.objects.all())
class Meta:
model = Model_Neural
fields = ["nom_mod", "modl"]
def __init__(self, *args, **kwargs):
super(Model_Neural_form, self).__init__(*args, **kwargs)
self.fields['allMod'].label = ''
If you want to set the default initial value you should be defining initial like other form fields.
You need to set initial when you create your form like this:
allMod = forms.ModelChoiceField(
initial=instance.pk if instance else None,
queryset=Model_Neural.objects.all()
)
I have field in my model:
TYPES_CHOICES = (
(0, _(u'Worker')),
(1, _(u'Owner')),
)
worker_type = models.PositiveSmallIntegerField(max_length=2, choices=TYPES_CHOICES)
When I use it in ModelForm it has "---------" empty value. It's TypedChoiceField so it hasn't empty_label attribute., so I can't override it in form init method.
Is there any way to remove that "---------"?
That method doesn't work too:
def __init__(self, *args, **kwargs):
super(JobOpinionForm, self).__init__(*args, **kwargs)
if self.fields['worker_type'].choices[0][0] == '':
del self.fields['worker_type'].choices[0]
EDIT:
I managed to make it work in that way:
def __init__(self, *args, **kwargs):
super(JobOpinionForm, self).__init__(*args, **kwargs)
if self.fields['worker_type'].choices[0][0] == '':
worker_choices = self.fields['worker_type'].choices
del worker_choices[0]
self.fields['worker_type'].choices = worker_choices
The empty option for any model field with choices determined within the .formfield() method of the model field class. If you look at the django source code for this method, the line looks like this:
include_blank = self.blank or not (self.has_default() or 'initial' in kwargs)
So, the cleanest way to avoid the empty option is to set a default on your model's field:
worker_type = models.PositiveSmallIntegerField(max_length=2, choices=TYPES_CHOICES,
default=TYPES_CHOICES[0][0])
Otherwise, you're left with manually hacking the .choices attribute of the form field in the form's __init__ method.
self.fields['xxx'].empty_value = None would not work If you field type is TypedChoiceField which do not have empty_label property.
What should we do is to remove first choice:
class JobOpinionForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(JobOpinionForm, self).__init__(*args, **kwargs)
for field_name in self.fields:
field = self.fields.get(field_name)
if field and isinstance(field , forms.TypedChoiceField):
field.choices = field.choices[1:]
Try:
def __init__(self, *args, **kwargs):
super(JobOpinionForm, self).__init__(*args, **kwargs)
self.fields['worker_type'].empty_value = None
https://docs.djangoproject.com/en/1.3/ref/forms/fields/#typedchoicefield
I'm new to Django. I have installed an external App that is in "python2.6/site-packages/haystack". This external App have "generic forms" but I need to add a CSS class that is not in the "generic form".
How can I extend the "forms.py" the "class FacetedModelSearchForm" from the "generic form" to "forms.py" in my own App?
Here is the code from the "generic form"
class SearchForm(forms.Form):
q = forms.CharField(required=False, label=_('Search'))
def __init__(self, *args, **kwargs):
self.searchqueryset = kwargs.pop('searchqueryset', None)
self.load_all = kwargs.pop('load_all', False)
if self.searchqueryset is None:
self.searchqueryset = SearchQuerySet()
super(SearchForm, self).__init__(*args, **kwargs)
def no_query_found(self):
"""
Determines the behavior when no query was found.
By default, no results are returned (``EmptySearchQuerySet``).
Should you want to show all results, override this method in your
own ``SearchForm`` subclass and do ``return self.searchqueryset.all()``.
"""
return EmptySearchQuerySet()
def search(self):
if not self.is_valid():
return self.no_query_found()
if not self.cleaned_data.get('q'):
return self.no_query_found()
sqs = self.searchqueryset.auto_query(self.cleaned_data['q'])
if self.load_all:
sqs = sqs.load_all()
return sqs
def get_suggestion(self):
if not self.is_valid():
return None
return self.searchqueryset.spelling_suggestion(self.cleaned_data['q'])
class FacetedSearchForm(SearchForm):
def __init__(self, *args, **kwargs):
self.selected_facets = kwargs.pop("selected_facets", [])
super(FacetedSearchForm, self).__init__(*args, **kwargs)
def search(self):
sqs = super(FacetedSearchForm, self).search()
# We need to process each facet to ensure that the field name and the
# value are quoted correctly and separately:
for facet in self.selected_facets:
if ":" not in facet:
continue
field, value = facet.split(":", 1)
if value:
sqs = sqs.narrow(u'%s:"%s"' % (field, sqs.query.clean(value)))
return sqs
How can I add to the field "q" the CSS class "myspecialcssclass" extending this class in my App "forms.py"? The class that I need to extend is the "FacetedSearchForm". Any clues?
from haystack.forms import FacetedSearchForm
class CustomSearchForm(FacetedSearchForm)
q = forms.CharField(required=False, label='Search', widget=forms.widgets.TextInput(attrs={"class":"myspecialcssclass",}))
your custom form must be set in your haystack urls e.g:
from haystack.views import SearchView
urlpatterns = patterns('haystack.views',
url(r'^$', SearchView(form_class=CustomSearchForm, results_per_page=20), name='haystack_search'),
)
Also see the haystack views and forms documentation
I think this:
https://docs.djangoproject.com/en/dev/ref/forms/widgets/#customizing-widget-instances
might help.
Basically, you need to subclass FacetedSearchForm and add an argument to you widget
class MyForm(FacetedSearchForm):
q = forms.CharField(
required=False,
label='Search',
widget=forms.TextInput(attrs={'class':'myspecialcssclass'}))
And that should be it.
The form field widget attrs maps html attributes to their values. Override these attributes in a subclasses __init__ function to safely modify the field.
class MyForm(FacedSearchForm):
def __init__(self, *args, **kwargs):
super(MyForm, self).__init__(*args, **kwargs)
self.fields['q'].widget.attrs['class'] = 'myspecialcssclass'