Django adding an attribute to a model formset - django

How do I go about adding a new class attribute for each for my fields in my formset? I was thinking it would be along these lines of code but the attribute fields does not exist in a formset object.
55 # create the formset
56 ItemUserDetailsFormset = modelformset_factory(CartItemUserDetails,
57 exclude=['cart', 'cart_item'], formset=BaseItemUserDetailsFormset)
37 class BaseItemUserDetailsFormset(BaseModelFormSet):
38 def __init__(self, *args, **kwargs):
39 super(BaseItemUserDetailsFormset, self).__init__(*args, **kwargs)
40 self.fields['first_name'].widgets = forms.TextInput(attrs={"class":"required"})

You're trying to set the fields attribute on the formset. You need to set it on the form class, not the formset class.
So, you want something like...
class ItemUserDetailsForm(forms.ModelForm):
class Meta:
model = CartItemUserDetails
def __init__(self, *args, **kwargs):
super(ItemUserDetailsForm, self).__init__(*args, **kwargs)
self.fields['first_name'].widget = forms.TextInput(attrs={ 'class': 'required' })
# [...]
ItemUserDetailsFormset = modelformset_factory(CartItemUserDetails,
form=ItemUserDetailsForm,
exclude=['cart', 'cart_item'],
)
Sadly, I scanned the docs and didn't see documentation of the form keyword argument in the Django docs, but it's clearly presented if you look at the modelform_factory function itself (see line 371).
Also, if the only thing that you're changing is the widget property, and if you're using Django >= 1.2 (which you should be), there's a slightly simpler syntax on the form itself:
class ItemUserDetailsForm(forms.ModelForm):
class Meta:
model = CartItemUserDetails
widgets = {
'first_name': forms.TextInput(attrs={ 'class': 'required' }),
# [...]
}

Related

Formset Factory Make Fields Required

I am using a modelformset_factory in Django to have a user fill out an unknown number of fields.
I have made the fields required but in the HTML rendering Django does not add required to the HTML element, looking around online this seems to be a common issue but I have not seen any valid answers that apply for what I want and I feel like this should be simple.
How do I make Django add the required tag to appropriate HTML elements for a Formset?
class ItemForm(forms.ModelForm):
class Media:
js = (formset_js_path,)
class Meta:
model = PurchaseOrderItems
fields = ['name', 'vendor', 'quantity', 'price', 'description']
labels = {
'name': 'Item',
}
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# self.fields['description'] .widget.attrs['required'] = 'required'
self.empty_permitted = False
self.fields['description'] = forms.CharField(
required=False,
label='Description',
)
def clean(self):
"""
:return:
"""
cleaned_data = super().clean()
# print(cleaned_data)
ItemFormSet = modelformset_factory(
PurchaseOrderItems,
form=ItemForm,
extra=0,
min_num=1,
validate_min=True,
can_delete=True,
)
Here is the HTML rendered for the name field, no required yet in my model it certainly is, so if this form is submitted I get DB errors because of empty values:
<input type="text" name="form-0-name" maxlength="150" class="form-control" id="id_form-0-name">
According to the release notes:
Required form fields now have the required HTML attribute. Set the new
Form.use_required_attribute attribute to False to disable it. The
required attribute isn’t included on forms of formsets because the
browser validation may not be correct when adding and deleting
formsets.
So if you want to disable, from your view you must submit the form in this way. This will affect all your fields.
form = ItemForm(use_required_attribute=False)
However, if you only want to affect some you must do the previous step and also in your form add this
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['name'].widget.attrs.update({'required': ''})
self.fields['vendor'].widget.attrs.update({'required': ''})
self.fields['quantity'].widget.attrs.update({'required': ''})
self.fields['price'].widget.attrs.update({'required': ''})
self.fields['description'].widget.attrs.update({'required': 'False'})
On the other hand I see that you are not using widgets in your form you should also use them to make it work.
widgets = {
'name': forms.TextInput(),
'vendor': forms.TextInput(),
'quantity': forms.TextInput(),
'price': forms.TextInput(),
'description': forms.TextInput(),
}
I put all the fields as TextInput, but look for what is indicated according to the type of data here Field types.

Django widget not required by form despite setting

I have a form widget (for the bio field) which is not being required by the form (no validation, no HTML attribute set to required) despite me setting it explicitly in the form constructor (as suggested in this SO question). When I say it is not required, I mean I can submit the form with the field empty (which I am blocked from doing for other fields):
users/forms.py:
from wagtail.admin.rich_text import get_rich_text_editor_widget
class UpdateProfileForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(UpdateProfileForm, self).__init__(*args, **kwargs)
self.fields['bio'].required = True
class Meta():
model = _user_profiles.__model__
fields = (
'email', 'first_name', 'last_name', 'organisation',
'bio', 'city', 'country', 'photo_file'
)
widgets = {
'bio': get_rich_text_editor_widget('submission')
}
If I set a breakpoint in users/views.py I can see that all the way until the end of the stack, the form field is correctly set to 'required'=True, just like the email field which the form correctly requires, and unlike city which it does not require:
users/views.py:
> /root/.pyenv/versions/3.7.2/lib/python3.7/site-packages/django/views/generic/base.py(151)get()
150 context = self.get_context_data(**kwargs)
--> 151 return self.render_to_response(context)
152
ipdb> context['form'].fields['bio'].required
True
ipdb> context['form'].fields['email'].required
True
ipdb> context['form'].fields['city'].required
False
Any ideas why the field is not required?

Python Django ModelForm, how can I modify a form fields before rendering it depending on the model

Using a ModelForm, the model contains a value of a field I should render in the form :
class MyClass(models.Model):
my_field = models.CharField(max_length=256) # this contains the type of the form's field for example a CharField or a DateTimeField
My view :
class MyView(FormView):
form_class = CustomForm
model = MyClass
And the form class:
class MyForm(forms.ModelForm):
class Meta:
model = MyClass
fields = ?
How can I dynamically set my form's field type?
I'd list out all the possible fields you may need in fields = () then you can remove fields you don't want, change if fields are required etc, based on the value of the model field like this;
class MyForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(MyForm, self).__init__(*args, **kwargs)
if self.instance:
if self.instance.my_field == 'value':
del self.fields['my_field'] # remove 'my_field'
self.fields['name'].required = False # change required value
class Meta:
model = MyClass
fields = (
'name',
'address',
'my_field',
'some_other_field'
)
So from your view, if you want to get a value to your form you can do something like;
my_object = MyClass.objects.first()
form = MyForm(instance=my_object)
context['form'] = form
# etc, etc
Then you can get values from fields on that object like I suggested above.
You could also just pass arbitrary args/kwargs to your forms if you need to (say you don't actually have an object to check the values from, but instead want to just pass something based on other data;
# in a view;
form = MyForm(my_var='something')
# in the form;
class MyForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
my_var = kwargs.pop('my_var')
super(MyForm, self).__init__(*args, **kwargs)
if my_var == 'value':
del self.fields['my_field'] # remove 'my_field'

Django ModeForm: no fields error

I have used the code in django 1.6 but when trying it in django 1.8.6 I get:
AttributeError: 'SignupDataForm' object has no attribute 'fields'
at this line, but also generaly whenever asking for fields:
merged_field_order = list(self.fields.keys())
My SignupDataForm is a child declared like this:
class SignupDataForm(BaseUserDataForm):
reg_user_badge = forms.CharField(label="Give Points to a Friend",required=False,widget = TextInput(attrs={'placeholder': 'Username (optional)'}),validators=[validate_friendname])
class Meta(BaseUserDataForm.Meta):
model = UserData
fields = BaseUserDataForm.Meta.fields + ('terms_conditions',)
#terms_conditions is also a model field but not added to the parent definition
def __init__(self, *args, **kwargs):
super(SignupDataForm, self).__init__(*args, **kwargs)
self.fields['terms_conditions'].required = False
self.fields['gender'].widget = Select(choices=GENDER_CHOICES,attrs={'class':'signup_select',})
self.fields['password2'].widget.attrs['onblur'] ="check_pass()"
self.fields['password1'].widget.attrs['onblur'] ="check_pass()"
def clean(self):
#clean overwrite
What is weird is that if I use the parent form everything works fine, I get no error. Also if I place a print fields in the META declaration the tuple with fields is there. The shortend code for the parent is here:
class BaseUserDataForm(forms.ModelForm):
url = forms.CharField(max_length = 30, label="Don't type here (anti spam protection)",validators=[validate_name_honeypots])
class Meta:
model = UserData
fields = ('****model fields named without terms_conditions field****')
def __init__(self, *args, **kwargs):
super(BaseUserDataForm, self).__init__(*args, **kwargs)
The error occurs in another child:
class BaseSignupForm(SignupDataForm):
username = forms.CharField(label=_("Username"),
max_length=get_username_max_length(),
min_length=app_settings.USERNAME_MIN_LENGTH,
widget=forms.TextInput(
attrs={'placeholder':
_('Username'),
'autofocus': 'autofocus'}))
email = forms.EmailField(widget=forms.TextInput(
attrs={'type': 'email',
'placeholder': _('E-mail address')}))
def __init__(self, *args, **kwargs):
email_required = kwargs.pop('email_required',
app_settings.EMAIL_REQUIRED)
self.username_required = kwargs.pop('username_required',
app_settings.USERNAME_REQUIRED)
super(BaseSignupForm, self).__init__(*args, **kwargs)
# field order may contain additional fields from our base class,
# so take proper care when reordering...
field_order = ['email', 'username']
merged_field_order = list(self.fields.keys())
Does anybody know what am I doing wrong?
UPDATE - SOLVED:
Solved. Not an python ModelForm or allauth issue at all. There was a form below, partially wrapped and partially commented that I didn't see and it caused an intendention error that manifest it such a weird manner ....

how to apply additional filter on the autocomplete_light field based on the paramter passed to __init__() of a model form

I am using django autocomplete_light to autocomplete the value inserted on a ForeignKeyField. I want to apply extra filtering on the suggestions based upon the arguements passed to__init__ method.
This is my form
class CamenuForm(autocomplete_light.ModelForm):
class Meta:
model = Ca_dispensaries_item
autocomplete_fields = ('item',)
def __init__(self, *args, **kwargs):
self.category = kwargs.pop('category', None)
super(CamenuForm, self).__init__(*args, **kwargs)
self.fields['item'].queryset=Items.objects.filter(product_type__name=self.category)
for field_name in self.fields:
field = self.fields.get(field_name)
if field:
field.widget.attrs.update({
'placeholder': field.label,
'class': 'form-control'
})
Here is the registry
autocomplete_light.register(Items, search_fields=('item_name',))
Here is this line in the __init__ method which doesnt seems to work with autocomplete. Though I used filter over here, yet the suggestions are not filtered.
self.fields['item'].queryset=Items.objects.filter(product_type__name=self.category)