I need to be pointed in the right direction. I 'Crispy Forms' to render a form I use with AngularJS. I would like to add the attribute ng-model="NAME" to all form fields by default.
I was thinking this could be done using a mixin added to my form i.e. AngularJSFormMixin:
class ProfileAuthenticationForm(AngularJSFormMixin, AuthenticationForm):
def __init__(self, *args, **kwargs):
super(ProfileAuthenticationForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_method = 'post'
# turn off HTML5 validation
self.helper.attrs = {'novalidate': ''}
self.helper.form_show_labels = False
self.helper.layout = Layout(
Field('username', placeholder="E-mail", autocomplete='off'),
Field('password', placeholder="Password", autocomplete='off'),
HTML('<input type="submit" name="Login" ng-click="submit()" css_class="btn btn-primary btn-block" />'),
)
but I'm unsure what to do from here with AngularJSFormMixin. Is there a way to auto add ng-model="NAME" to every field by default?
I've never worked with crispy forms before but this is what I have done in the __init__ on my model forms to add a ng-model attribute with a value to it. My 'get-error-elements' directive is used to show errors of the form to the user:
def __init__(self, *args, **kwargs):
super(MyForm, self).__init__(*args, **kwargs)
for field in self:
field.field.widget.attrs.update({'ng-focus': ''})
field.field.widget.attrs.update({
'ng-model': 'formName.{0}'.format(field.name),
'get-error-elements': '',
})
Related
I have trouble setting up a form with a ModelMultipleChoiceField where the queryset depends on the user. My goal is to implement an export function.
My view looks like this:
class ExportView(FormView):
template_name = 'ExportTemplate.html'
def get(self, request, *args, **kwargs):
self.form_class = ExportForm(user = request.user)
return render(request, self.template_name, {'form': self.form_class})
def get_success_url(self):
return '/addrbook/'
def form_valid(self, form):
# This method is called when valid form data has been POSTed.
# It should return an HttpResponse.
return super().form_valid(form)
form:
class ExportForm(forms.Form):
def __init__(self, user, *args, **kwargs):
usersContacts = ContactManager().getAllUsersContacts()
self.contactList = forms.ModelMultipleChoiceField(queryset = usersContacts[str(user)])
print(usersContacts[str(user)])
super(ExportForm, self).__init__(*args, **kwargs)
I verified that the queryset is not empty, it contains a list of model objects.
My template looks like this:
<form method="post">{% csrf_token %}
{{ form }}
<input type="submit">
</form>
the only thing that gets rendered is the submit button.
Another thing that left me completely unsure of python basics is that this code:
class ExportForm(forms.Form):
contactList = forms.ModelMultipleChoiceField(queryset = [])
def __init__(self, user, *args, **kwargs):
usersContacts = ContactManager().getAllUsersContacts()
self.contactList.queryset = usersContacts[str(user)]
print(usersContacts[str(user)])
super(ExportForm, self).__init__(*args, **kwargs)
returned the runtime error:
'ExportForm' object has no attribute 'contactList'
How is it possible? the contactList member is part of the ExportForm class definition and 'self' should point to an object of that class.
Could someone explain to me why the form field is rendered empty and/or point me to a better way to pass the user to the form?
Edit: here are the changes i made to the answer to get it working, although i now stumbled upon a different problem(the field expects a queryset, and not a list of model objects):
View:
class ExportView(FormView):
template_name = 'ExportTemplate.html'
form_class = ExportForm
def get_form_kwargs(self):
kwargs = super(ExportView, self).get_form_kwargs()
kwargs['user'] = self.request.user
return kwargs
form:
class ExportForm(forms.Form):
contactList = forms.ModelMultipleChoiceField(queryset = Contact.objects.none())
def __init__(self, *args, **kwargs):
user = kwargs['user']
kwargs.pop('user', None)
super(ExportForm, self).__init__(*args, **kwargs)
usersContacts = ContactManager().getAllUsersContacts()
self.fields['contactList'].queryset = usersContacts[str(user)]
print(self.fields['contactList'].queryset)
First of all, you should pass the user to the form every time you instantiate it, not just in the get method. The way to do this with FormView is to override get_form_kwargs.
def get_form_kwargs(self):
kwargs = super(ExportForm, self).get_form_kwargs()
kwargs[user] = self.request.user
return kwargs
You can then remove your get() method.
Then, in your form class, you should use the none() method instead of an empty list to get an empty queryset. In the __init__ method you can pop the user from kwargs, and then call super() before you edit the fields. You edit the contactList field via self.fields instead of self.contactList. Note that the recommended style for field names in Django is contact_list instead of contactList.
class ExportForm(forms.Form):
contactList = forms.ModelMultipleChoiceField(queryset=YourModel.objects.none())
def __init__(self, *args, **kwargs):
user = kwargs.pop('user')
super(ExportForm, self).__init__(*args, **kwargs)
usersContacts = ContactManager().getAllUsersContacts()
self.fields['contactList'].queryset = usersContacts[str(user)]
You haven't shown the ContactManager() code, but using str(user) as the dictionary key looks fragile. It would probably be better to use user.pk or user.username instead.
In Django I have the below code which is creating a username and password form on an HTML Page:
<div class="control-group">
{{ form.username }}
</div>
<div class="control-group">
{{ form.password }}
</div>
I want to add "Username" and "Password" placeholder text within the field, and then when the user clicks on the field the word dissapears. What is the best way to achieve this ?
You must use the placeholder properties
class LoginForm(forms.Form):
username = forms.CharField(label='username')
password = forms.CharField(label='password')
def __init__(self, *args, **kwargs):
super(LoginForm, self).__init__(*args, **kwargs)
self.fields['username'].widget.attrs['placeholder'] = 'username'
self.fields['password '].widget.attrs['placeholder'] = 'password'
or
class LoginForm(forms.Form):
username = forms.CharField(label='username',widget=forms.TextInput(attrs={'placeholder':'username'}))
password = forms.CharField(label='password',widget=forms.PasswordInput(attrs={'placeholder':'password'}))
In case it might help someone, I wanted to use the help_text property of a model as the placeholder. This is the simplest way I could figure it out, based on aziminia's answer:
class MyForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
for _, value in self.fields.items():
value.widget.attrs['placeholder'] = value.help_text
class Meta:
model = models.MyModel
fields = (...)
I hope you do have a forms.py file in your project. While creating your form, you can use following to set placeholder for your fields:
username = forms.CharField(label='username',
widget=forms.TextInput(attrs={'placeholder': 'username'}))
If you have ModelForm in your project you can implement as:
class MyForm(forms.ModelForm):
class Meta:
model = User
widgets = {
'username': forms.TextInput(attrs={'placeholder': 'username'}),
..........
}
In case if you want to have field name as a placeholder, you can use code below:
class LoginForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(LoginForm, self).__init__(*args, **kwargs)
for k,v in self.fields.items():
v.widget.attrs['placeholder'] = k.capitalize()
Otherwise please refere to this answer.
I have a cripsy django form.
What is the best way to hide the field label in the template when I use {% cripsy form %}?
I do not want the user to see MY_FIELD_1 and MY_FIELD_2.
class mYForm(forms.ModelForm):
MY_FIELD_1 = forms.BooleanField()
MY_FIELD_2 = forms.BooleanField()
def __init__(self, *args, **kwargs):
...
...
self.helper = FormHelper()
self.helper.layout = Layout(
Field('MY_FIELD_1',),
Field('MY_FIELD_2',),
)
...
If you want to remove all labels from your form when using the crispy forms FormHelper then you can use:
self.helper.form_show_labels = False
If you want to remove labels from certain fields then you can do
self.fields['some_field'].label = False
Where some_field is the name of the field whose label you want to remove.
I want to build several forms in Django with django-crispy using a common layout. I read the crispy documentation about composing layouts, but I cannot made it all by myself, because I get the message error:
append() takes exactly one argument (2 given).
See my code below:
# a class with my common element
class CommonLayout(forms.Form, Layout):
code = forms.CharField(
label='Serial Number',
max_length=12,
required=True,
)
def __init__(self, *args, **kwargs):
super(CommonLayout, self).__init__(*args, **kwargs)
self.helper = FormHelper(self)
self.helper.form_method = 'POST'
self.helper.layout = Layout (
Field('code', css_class='form-control', placeholder='Read the Serial Number'),
)
#the class with the form
class CollectionForms(forms.Form):
def __init__(self, *args, **kwargs):
super(CollectionForms, self).__init__(*args, **kwargs)
self.helper = FormHelper(self)
self.helper.form_action = 'collection'
self.helper.layout.append(
CommonLayout(),
FormActions(
StrictButton('Pass', type="submit", name="result", value="True", css_class="btn btn-success"),
)
)
So, I need help to get this right and pass to another forms.
You're creating a CommonLayout form class and you're trying to have other forms inherit the layout of that form.
One way to achieve this is to make CollectionForms inherit from CommonLayout, like so:
#the class with the form
class CollectionForms(CommonLayout):
def __init__(self, *args, **kwargs):
super(CollectionForms, self).__init__(*args, **kwargs)
self.helper.form_action = 'collection'
self.helper.layout.append(
FormActions(
StrictButton('Pass', type="submit", name="result", value="True", css_class="btn btn-success"),
)
)
Notice that this inherits the Layout() object from the CommonLayout form, and extends this. You aren't re-initializing a FormHelper object within your CollectionForms class, you're modifying the FormHelper object created from the CommonLayout form class. Your previous example did not inherit the FormHelper from CommonLayout, it created a new Layout() object, which is the root of your problem.
I have a form that is displaying well only for the label text that I don't want and I have tried all I could to let it off my form but it won't just go...
forms.py:
class sign_up_form(forms.ModelForm):
class Meta:
model = Users
fields =['email']
widgets = {
'email': forms.EmailInput(attrs={
'id': 'email',
'class': 'form-control input-lg emailAddress',
'name': 'email',
'placeholder': 'Enter a valid email'})}
I have tried:
views.py:
from django.shortcuts import render
from mysite.forms import sign_up_form
def register(request):
sign_up = sign_up_form(auto_id=False)
context = {'sign_up_form': sign_up}
return render(request, 'mysite/register.html', context)
I need my widgets as defined above.
In ModelForms there will be default labels so you have to over-ride where you don't need labels
you can define it like this
class sign_up_form(forms.ModelForm):
email = forms.CharField(widget=forms.Textarea, label='')
class Meta:
model = Users
fields =['email']
This method will not include labels for your form, other method depends on rendering in template. You can always avoid labels from form
<label>MY LABEL</label> instead of {{ form.field.label }}
In __init__ method set your field label as empty.This will remove label text.
def __init__(self, *args, **kwargs):
super(sign_up_form, self).__init__(*args, **kwargs)
self.fields['email'].label = ""
If you're wanting to remove all labels, you can use:
class sign_up_form(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
for key, field in self.fields.items():
field.label = ""