I tried creating placeholder by using the following code:
class ReceiptsForm(forms.ModelForm):
class Meta:
model = Receipts
fields = ('receipt',)
widgets = {
'receipt' : forms.FileInput(attrs={'class': 'form-control', 'placeholder': 'Maximum 3 files allowed.'}),
}
And then rendering by using the following snippet in the template:
<form action="." method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form | crispy }}
<button type="submit" class="btn btn-sm btn-primary mt-1">Submit</button>
</form>
But still the placeholder text is not appearing besides the fileinput.
What you want, is a help_text. Django defines this in regular Form.
class ReceiptsForm(forms.ModelForm):
class Meta:
model = Receipts
fields = ('receipt',)
help_texts = {
'receipt': 'YOUR HELP TEXT HERE',
}
widgets = {
'receipt' : forms.FileInput(attrs={'class': 'form-control'}),
}
Not sure you need to add form-control CSS class if you are using crispy with BOOSTRAP_PACK ?
Related
My models.py and this is my model for photos.
# home photo page
class Photos(models.Model):
photo_title = models.CharField(max_length=50, blank=False)
photo_description = models.CharField(max_length=50, blank=False)
photo_date = models.DateField(blank=False)
photo_location = models.CharField(max_length=50, blank=False)
photo_file = models.FileField(upload_to='photos', blank=False)
def __str__(self):
return self.photo_title
My forms.py this is the model form I made to render it as a form.
class UploadPhotosForm(forms.Form):
class Meta:
model = Photos
fields = '__all__'
my views.py these are my relavent imports and section I coded in view file.
from .forms import CampForm, ProjectForm, HikeForm, UploadPostsForm, UploadPhotosForm
posts = UploadPostsForm()
photo = UploadPhotosForm()
print(photo.as_p())
here this code should print the form as text into console isn't it?
But I don't have any console output. It seems like the nothing has been initialized to the photo variable isn't it?
I do not have any clue what happened.
context = {
'title': 'manage_wall',
'posts': posts,
'photo': photo,
}
return render(request, 'manager/manage_wall.html', context)
My template
{% block content %}
<div class="container">
<div class="row">
<div class="col">
<form action="" method="post">
{% csrf_token %}
{{photo.as_p}}
<input type="submit" value="Add">
</form>
</div>
<div class="col">
<form action="" method="post">
{% csrf_token %}
{{posts.as_p}}
<input type="submit" value=" Add">
</form>
</div>
</div>
</div>
{%endblock %}
As you can see here my photoForm is not rendering in the frontend can someone point out the mistake I have made not to render that form only while other forms are successfully rendering in the frontend. My Question is all other model forms rendered successfully why this is not displaying properly.
Your UploadPhotosForm is inherited from forms.Form(...)
class which does not contain model in Meta class so instead of inheriting from forms.Form class inherit from form.ModelForm(...)
here is final version of your code
class UploadPhotosForm(forms.ModelForm):
class Meta:
model = Photos
fields = '__all__'
I found the answer in models.py it should be forms.ModelForm
class UploadPhotosForm(forms.ModelForm):
class Meta:
model = Photos
fields = '__all__'
it is not rendering unless it is a ModelForm
I'm trying to style the django forms, I could apply the class to the TextInputs with widget but for the email and password it doesn't apply. Any idea why?
Also, how can I delete the text above password? The password requisites, it isn't help_text
forms.py
class SignupForm(UserCreationForm):
email = forms.EmailField()
class Meta:
model = User
fields = ['email', 'first_name', 'last_name', 'password1', 'password2']
widgets = {
'email': forms.EmailInput(attrs={'class': 'forms-group__input'}),
'first_name': forms.TextInput(attrs={'class': 'forms-group__input'}),
'last_name': forms.TextInput(attrs={'class': 'forms-group__input'}),
'password1': forms.PasswordInput(attrs={'class': 'forms-group__input'}),
'password2': forms.PasswordInput(attrs={'class': 'forms-group__input'}),
}
forms.html
<form class="forms-group__form" method="POST" enctype="multipart/form-data">
{% csrf_token %}
{% for field in form %}
{{ field.errors }} <br>
<div class="forms-group__input-field">
<label class="forms-group__label">{{ field.label_tag }}</label><br>
{{ field }}<br>
{% if field.help_text %}
<p class="help">{{ field.help_text|safe }}</p>
{% endif %}
</div>
{% endfor %}
<div class="forms-group__button-div"><input class="button submit-button forms-group__button" type="submit" value="Update Profile"></div>
</form>
Fields that are declared in the form class are not automatically generated by the ModelForm, hence declaring a widget for them in the widgets attribute of the Meta does not work. You can either forego declaring it in the class and let it be generated automatically:
class SignupForm(UserCreationForm):
email = forms.EmailField()
...
Or you can specify the widget for the field in the field itself:
class SignupForm(UserCreationForm):
email = forms.EmailField(widget=forms.EmailInput(attrs={'class': 'forms-group__input'}))
...
I want to make a form to edit a model object, with the initial data being the original data (before the change), but it doesn't show,
it was just a blank form
models.py:
class Employee(models.Model):
first_name = models.CharField(max_length=200)
last_name = models.CharField(max_length=200)
forms.py:
class EmployeeForm(forms.ModelForm):
class Meta:
model = Employee
fields = ['first_name', 'last_name']
labels = {'first_name' : 'First Name:', 'last_name' : 'Last Name:' }
input_attrs = {'class' : 'form-control'}
widgets = {
'first_name' : forms.TextInput(attrs=input_attrs),
'last_name' : forms.TextInput(attrs=input_attrs)}
views.py:
def edit(request, id):
employee = Employee.objects.get(id=id)
data = {
'first_name' : employee.first_name,
'last_name' : employee.last_name,
}
form = EmployeeForm(request.POST or None, initial=data, instance=employee)
if (form.is_valid and request.method == 'POST'):
form.save()
return HttpResponseRedirect('/form/')
response = {'employee_form' : EmployeeForm, 'employee':employee}
return render(request, 'editemployee.html', response)
editemployee.html:
<div class="form">
<div class="form-group">
<form action="" method="POST">
{% csrf_token %}
{% for form in employee_form %}
{{ form.label }}
{{ form }}
<br>
{% endfor %}
<input type="submit" value="Submit" class="btn btn-primary">
</form>
</div>
</div>
Can anyone please tell me where I went wrong? I've tried so many things but to no avail. The form works fine, but the initial data doesn't show.
Editing an existing record, no initial data is needed, it comes from the model instance.
form = EmployeeForm(request.POST or None, instance=employee)
If you need default data in those fields, you can add it in the model.
How to add bootstrap class is-invalid to Django input forms (only if the form/field is not correctly completed).
My forms.py
class BasicUserDataForm(forms.Form):
error_css_class = 'is-invalid'
user_name = forms.CharField(max_length=20, widget=forms.TextInput(attrs={'placeholder': 'Username',
'class': 'form-control'}))
My templates.html
<div class="form-group col-md-6">
<!-- Label -->
<label for="id_user_name">Username*</label>
<div class="input-group mb-0">
<div class="input-group-prepend">
<div class="input-group-text">#</div>
</div>
{{ form.user_name }}
</div>
{% if form.user_name.errors|striptags %}<small class="text-danger"><b>{{ form.user_name.errors|striptags }}</b></small>{% endif %}
</div>
I try:
1.)
class BasicUserDataForm(forms.Form):
user_name = forms.CharField(max_length=20, widget=forms.TextInput(attrs={'placeholder': 'Username',
'class': 'form-control'}))
2.)
class BasicUserDataForm(forms.Form):
user_name = forms.CharField(max_length=20, widget=forms.TextInput(attrs={'placeholder': 'Username',
'class': 'form-control {% if form.user_name.errors %}is-invalid{% endif %}'}))
3.) According to the documentation
class BasicUserDataForm(forms.Form):
error_css_class = 'is-invalid'
[...]
4.)
.error input, .error select {
border: 2px red solid;
}
It still doesn't give any results. I would like to get the effect that gives:
user_name = forms.CharField(max_length=20, widget=forms.TextInput(attrs={'placeholder': 'Username',
'class': 'form-control is-invalid'}))
Create a file, yourapp_template-filters.py and then place it in templatetags folder in your app:
from django import template
register = template.Library()
#register.filter(name='add_attr')
def add_attribute(field, css):
attrs = {}
definition = css.split(',')
for d in definition:
if ':' not in d:
attrs['class'] = d
else:
key, val = d.split(':')
attrs[key] = val
return field.as_widget(attrs=attrs)
To use it in a Django template, firstly add this widget in the top of the template, similar to the load static widget:{% load yourapp_template-filters %}
And now you can use it on any form widget as a function, like so:
{% if form.user_name.errors %}
{{ form.user_name|add_attr:"form-control is-invalid" }}
{% else %}
{{form.user_name|add_attr:"form-control"}}
{% endif %}
Try adding a Meta class to your form and assigning the proper model. For instance:
class BasicUserDataForm(forms.Form):
error_css_class = 'is-invalid'
user_name = forms.CharField(max_length=20, widget=forms.TextInput(attrs={'placeholder': 'Username', 'class': 'form-control'}))
class Meta:
model = User
#ehsan nnnnn's answer is great! I tried it, and it works.
I want to clarify and extend it a little bit.
Initialization:
Source: https://docs.djangoproject.com/en/4.0/howto/custom-template-tags/
The app should contain a templatetags directory, at the same level as models.py, views.py, etc. Do not forget to add init.py in the directory! (as stated in the doc)
Attribute declaration:
The code provided by #ehsan nnnnn is helpful if you completely override the attributes section. I have based my code entirely on #ehsan nnnnn's solution and extended it to preserve the previous attributes.
NOTE: I am using Python 3.10.1; if you are somehow still using a version before f-string or do not like f-strings, correct it to whatever your heart desires.
Here is my solution:
# templatetags\add_attr.py
from django import template
register = template.Library()
#register.filter(name='add_attr')
def add_attribute(field, css):
attrs = field.subwidgets[0].data['attrs'] # Accessing the already declared attributes
definition = css.split(',')
for d in definition:
if ':' not in d:
attrs['class'] += f" {d}" # Extending the class string
else:
key, val = d.split(':')
attrs[key] += f'{val}' # Extending the `key` string
return field.as_widget(attrs=attrs)
{% comment %} HTML template {% endcomment %}
{% if form.username.errors %}
{{form.username|add_attr:'is-invalid'}}
{% else %}
{{ form.username }}
{% endif %}
Tested on:
Python 3.10.1
Django 4.0
Bootstrap 5.1
Good morning, I'm new to Django, I'm trying to include a template form, but it does not show the fields, just the save button.
Use Django 2.1. I summarize the code, so please can you help me. since you need to reuse the form in other templates.
models.py
from django.db import models
class Area(models.Model):
nombre = models.CharField(max_length=45)
descripcion = models.CharField(max_length=100, null=True, blank=True)
def __str__(self):
return self.nombre
views.py
class AreaCreate(CreateView):
model = Area
form_class = AreaForm
template_name = 'area/area_form.html'
class AreaList(ListView):
model = Area
template_name = 'area/area_list.html'
forms.py
class AreaForm(forms.ModelForm):
class Meta:
model = Area
fields = (
'nombre',
'descripcion',
)
widgets = {
'nombre': forms.TextInput(attrs={'class': 'form-control', 'placeholder':'Area'}),
'descripcion': forms.TextInput(attrs={'class': 'form-control', 'placeholder':'DescripciĆ³n'}),
}
area_form.html
<form action="" method="POST"> {% csrf_token %}
<div class="form-row">
<div class="col-sm-4 campoform">
{{ form.nombre }}
</div>
<div class="col-sm-6 campoform">
{{ form.descripcion }}
</div>
<div class="col-sm-2 campoform">
<button class="btn btn-primary" type="submit" style="width:100%">Guardar</button>
</div>
</div>
</form>
area_list.html --- I am not adding the complete list.html code for a better understanding.
<div>{% include "area/area_form.html" %}</div>
The result in area_list.html is that it shows only the button.
Sorry for the delay in responding. I solved it by calling the form with a modal. Using the library "bootstrap_modal_forms".
#View
class GestionarAreas(generic.ListView):
model = Area
context_object_name = 'areas'
template_name = 'areas/gestionar_areas.html'
paginate_by = 10
class CrearArea(generic.CreateView):
template_name = 'areas/crear_area.html'
form_class = AreaForm
success_url = reverse_lazy('gestionar_areas')
#urls
path('', login_required(views.GestionarAreas.as_view()),name='gestionar_areas'),
path('crear/', login_required(views.CrearArea.as_view()), name='crear_area'),
#HTML
<div class="col-sm-auto">
<button class="crear-area btn btn-primary" type="button"name="button">
<span class="fa fa-plus mr-2"></span>Crear Area</button>
</div>
#Script
// Boton Crear Area
$(".crear-area").modalForm({formURL: "{% url 'crear_area' %}", successURL: ""});
// Boton Actualizar Area
$(".editar-area").each(function () {
$(this).modalForm({formURL: $(this).data('id'), successURL: ""});
});