can't override django Form widget attributes correctly - django

I want to change the name of the widget but then i have two names inside the input
class DocumentForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
# to delete colon after field's name
kwargs.setdefault('label_suffix', '')
super(DocumentForm, self).__init__(*args, **kwargs)
class Meta:
model = Document
name = "document"
fields = ('id',
'comment',
'private',
'position',
'marked')
# fields = '__all__'
marked = forms.IntegerField(
required=False,
widget=forms.NumberInput(
attrs={
'name': "asdasdjasdasjdldsa",
'id': "device_documents___name___marked",
'class': 'check preview_image',
'onchange': 'cbChange(this)',
'mazen': "document_set-__name__-position"
},
)
)
but if i print this i have two name name="marked" and name="asdasdjasdasjdldsa" how to delete the first one?
print(f["marked"])
<input type="number" name="marked" name="asdasdjasdasjdldsa" id="device_documents___name___marked" class="check preview_image" onchange="cbChange(this)" mazen="document_set-__name__-position">

Django needs the name of the field to match the class definition. Otherwise it wouldn't be possible to process the submitted form data. Your only way of changing the widget's name attribute is to change the form field definition.
You didn't say why you want the name attribute to change. If you really wanted to hack it. You could create a custom widget with a template that uses the desired name.

Related

Django custom form attrs removes css class

I'm dealing with an RTL CharField so I impelemted the below in my admin.py:
class CustomPostForm(forms.ModelForm):
class Meta:
model = Post
fields = ['title', 'slug', 'lead', 'body', 'status', 'is_featured']
widgets = {'title': forms.TextInput(attrs={'dir': 'rtl'})}
#admin.register(Post)
class PostAdmin(admin.ModelAdmin):
form = CustomPostForm
This works fine except that when I look at the form in the Admin site the width of the RTL field is less than the next LTR field:
And if I remove the whole custom form, then both fields look the same:
So I inspect the code and realize that the slug field has a css class called vTextField and if I change the custom form's attrs both fields look the same:
widgets = {'title': forms.TextInput(attrs={'dir': 'rtl', 'class': 'vTextField'})}
So my question is, is it normal or intentional for Django to remove CSS class if attrs is used and my approach in putting the class back is correct, or I'm missing something here?
You are replacing attrs {'class': 'vTextField'} with {'dir': 'rtl'}. So yes, original attrs is replaced with yours. It's normal and expected.
Add the attribute inside init method:
class CustomPostForm(forms.ModelForm):
class Meta:
model = Post
fields = ['title', 'slug', 'lead', 'body', 'status', 'is_featured']
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['title'].widget.attrs['dir'] = 'rtl'

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.

how to add search_fields in django forms

I was making a django forms and there is a field owner which is related with ForeignKey by User model , Sometimes name of user is same so I want to search it by their email address , How can I add searching of email field in forms like this search_fields = ['email'].
class GroupForm(forms.ModelForm):
class Meta:
model = Group
fields = ('name', 'owner', 'club', 'moderator', 'group_type', 'country')
def __init__ (self, *args, **kwargs):
# brand = kwargs.pop("brand")
super(GroupForm, self).__init__(*args, **kwargs)
language_results = User.objects.all()
# self.fields["owner"].widget = forms.widgets.CheckboxSelectMultiple()
# self.fields["owner"].widget = autocomplete.ModelSelect2()
self.fields["owner"] = forms.ModelMultipleChoiceField(
queryset=User.objects.all(),
required=True,
widget = forms.SelectMultiple(attrs={
'placeholder': "Choose the users(s)",
'class': 'chzn-select',
'multiple tabindex': '6',
}))
you just use a CharField and add that form in your template;and after submiting that search you get the value entred by the user and use the objects filter to return the corresponding result.

customize error message 'please fill out this form' in Django

I have written this function in Django to override the 'label suffix and form field error message. Within the same function, the lebel suffix is working (the colon is removed) but the error message did not replaced by with customized one.
Here is the form class with the function:
class User_accountModelForm(forms.ModelForm):
# to remove colons from the labels:
def __init__(self, *args, **kwargs):
kwargs.setdefault('label_suffix', '')
super(User_accountModelForm, self).__init__(*args, **kwargs)
# changing error messages:
for field in self.fields.values():
field.error_messages = {'required':'The field {fieldname} is required'.format(fieldname=field.label)}
class Meta:
model = User_account
fields = ['first_name', 'other fields']
any help or clue is appreciated
To override the forms error messages, add it to the forms Meta; see also the ModelForm docs:
class User_accountModelForm(ModelForm):
class Meta:
model = User_account
fields = ['first_name', 'other fields']
error_messages = {
'first_name': {
# for example:
'max_length': _("This writer's name is too long."),
},
}

How to make UserCreationForm email field required

I am a newbie in Django.
I would like the email field in the subclassed UserCreationForm to be required.
I have tried the commented methods but none has worked so far. I have tried the solution from this but to no avail. Any help would be appreciated.
class MyRegistrationForm(UserCreationForm):
captcha = NoReCaptchaField()
#email = forms.EmailField(required=True, widget=forms.TextInput(attrs={'class': 'mdl-textfield__input'}))
class Meta:
model = User
fields = ('first_name', 'last_name', 'username', 'email', 'password')
#email = {
# 'required': True
#}
widgets = {
'first_name': forms.TextInput(attrs={'class': 'mdl-textfield__input'}),
'last_name': forms.TextInput(attrs={'class': 'mdl-textfield__input'}),
'username': forms.TextInput(attrs={'class': 'mdl-textfield__input'}),
#'email': forms.TextInput(attrs={'class': 'mdl-textfield__input'})
}
def save(self, commit=True):
user = super(MyRegistrationForm, self).save(commit=False)
user.first_name = self.cleaned_data["first_name"]
user.last_name = self.cleaned_data["last_name"]
user.username = self.cleaned_data["username"]
user.email = self.cleaned_data["email"]
#user.user_level = self.cleaned_data["user_level"]
if commit:
user.save()
return user
def __init__(self, *args, **kwargs):
super(MyRegistrationForm, self).__init__(*args, **kwargs)
self.fields['password1'].widget.attrs['class'] = 'mdl-textfield__input'
self.fields['password2'].widget.attrs['class'] = 'mdl-textfield__input'
#self.fields['email'].required=True
This solved the problem: email = forms.CharField(required=True, widget=forms.EmailInput(attrs={'class': 'validate',}))
I checked Django's User model and it has required=False. So, I think you cannot achieve what you are looking for with the default User model based on note section of "Overriding the default fields" in the django documentation. I have inluded the snippet
ModelForm is a regular Form which can automatically generate certain
fields. The fields that are automatically generated depend on the
content of the Meta class and on which fields have already been
defined declaratively. Basically, ModelForm will only generate fields
that are missing from the form, or in other words, fields that weren’t
defined declaratively.
Fields defined declaratively are left as-is, therefore any
customizations made to Meta attributes such as widgets, labels,
help_texts, or error_messages are ignored; these only apply to fields
that are generated automatically.
Similarly, fields defined declaratively do not draw their attributes
like max_length or required from the corresponding model. If you want
to maintain the behavior specified in the model, you must set the
relevant arguments explicitly when declaring the form field.
For example, if the Article model looks like this:
class Article(models.Model):
headline = models.CharField(
max_length=200,
null=True,
blank=True,
help_text='Use puns liberally',
)
content = models.TextField() and you want to do some custom validation for headline, while keeping the blank and help_text values
as specified, you might define ArticleForm like this:
class ArticleForm(ModelForm):
headline = MyFormField(
max_length=200,
required=False,
help_text='Use puns liberally',
)
class Meta:
model = Article
fields = ['headline', 'content'] You must ensure that the type of the form field can be used to set the contents of the corresponding
model field. When they are not compatible, you will get a ValueError
as no implicit conversion takes place.
So try this,
from django.forms import EmailField
from django.core.validators import EMPTY_VALUES
# I used django [emailfield code][2] as reference for the code of MyEmailField
# Also, following comment in django [custom form fields document][2]:
# If the built-in Field classes don’t meet your needs, you can easily create custom Field classes. To do this, just create a subclass of django.forms.Field. Its only requirements are that it implement a clean() method and that its __init__() method accept the core arguments mentioned above (required, label, initial, widget, help_text).
# You can also customize how a field will be accessed by overriding get_bound_field().
class MyEmailField(forms.EmailField):
def __init__(self, *args, **kwargs):
super(MyEmailField, self).__init__(*args, strip=True, **kwargs)
# Clean would be called when checking is_clean
def clean(self,value):
if value in EMPTY_VALUES:
raise Exception('Email required')
value = self.value.strip()
return super(MyEmailField, self).clean(value)
class MyRegistrationForm(UserCreationForm):
captcha = NoReCaptchaField()
# All available arguments listed in django [core fields argument document][2]. Currently they are required, label, label_suffix, initial, widget, help_text, error_messages, validators, localize, disabled
email = MyEmailField(required=True)
class Meta:
model = User
fields = ('first_name', 'last_name', 'username', 'email', 'password')
# other part of your code
PS: I have not tested this code but based on the documentation I think this should take you in a good direction.
Few more references:
Django auth.user with unique email
How to make email field unique in model User from contrib.auth in Django
https://simpleisbetterthancomplex.com/tutorial/2016/07/22/how-to-extend-django-user-model.html
Add this to your forms.py file:
class Userform(UserCreationForm):
email = forms.EmailField(required=True)
class meta:
model = User
fields = ('name','email')