I changed ModelChoiceField to be shown as a TextInput.
I have a field named 'filename' of this type: models.ForeignKey('Filename', on_delete=models.SET_NULL, null=True, blank=True) in a class as follow:
models.py
class Event(models.Model):
name = models.CharField('Name', max_length=100, blank=True, default='')
filename = models.ForeignKey('Filename', on_delete=models.SET_NULL, null=True, blank=True)
class Filename(models.Model):
name = models.CharField('Name', max_length=50)
def __str__(self):
return self.nome
This is part of my 'forms.py' I use show form in frontend after defining the template (myappname/templates/myappname/event_edit.html)
forms.py
class EventEditForm(forms.ModelForm):
def __init__(self, data=None, *args, **kwargs):
if data is not None:
data = data.copy()
if data['filename']:
f, f_created = Filename.objects.get_or_create(nome=data['filename'])
data['filename'] = m.id
super(EventEditForm, self).__init__(data=data, *args, **kwargs)
self.fields['filename'] = forms.ModelChoiceField(queryset=Filename.objects.all(), widget=forms.TextInput(attrs={'class': 'form-control', 'value':self.instance.filename}))
self.fields['filename'].required = False
class Meta:
model = Event
fields = ['name', 'filename']
and this is my event_edit.html:
<form method="post" class="form-horizontal">
{% csrf_token %}
{% for field in event_form %}
<div class="form-group form-group-lg">
<label for="{{ field.id_for_label }}" class="col-sm-2 control-label">{{field.label}}</label>
<div class="col-sm-6">
{{ field }}
</div>
<div class="col-sm-4">
{{ field.errors }}
</div>
</div>
{% endfor %}
<div class="form-group">
<div class="col-sm-10">
<button type="submit" class="btn btn-primary btn-lg center-block">Save</button>
</div>
</div>
</form>
The problem is that if I override ModelChoiceField to be a TextInput the 'filename' field shows id instead of showing field name.
Otherwise, If I leave it as a Choice Field it correctly shows value instead of id.
How can I solve this issue?
Based on your comments and the code in EventEditForm, you want a form that will:
display the Event.name and the linked Filename.name
use the submitted name to update Event.name
use the submitted filename to lookup or create a Filename and update Event.filename
This should work:
class EventEditForm(forms.ModelForm):
"""
Calling form.save() will:
* update the Event.name
* update the Event.filename with a Filename instance
found or created using the supplied name
"""
fname = forms.CharField(
label='Filename',
required=False,
widget=forms.TextInput(attrs={'class': 'form-control'}),
)
class Meta:
model = Event
fields = ['name',]
widgets = {
'name': forms.TextInput(attrs={'class': 'form-control'}),
}
def __init__(self, *args, **kwargs):
super(EventEditForm, self).__init__(*args, **kwargs)
self.initial['fname'] = self.instance.filename
def save(self, commit=True):
instance = super(EventEditForm, self).save(commit=False)
cleaned_fname = self.cleaned_data['fname']
if cleaned_fname:
f, f_created = Filename.objects.get_or_create(name=cleaned_fname)
instance.filename = f
else:
instance.filename = None
if commit:
instance.save()
return instance
Related
I am trying to use a modelchoicefield from the form in a formset_factory but i dont understand the error and don't know how to solve it.
(edit added the models.py)
models.py
class Order(Model):
user = ForeignKey(User, on_delete=SET_NULL, null=True)
fee = ForeignKey(Fee, on_delete=SET_NULL, null=True)
route = ForeignKey(Route, on_delete=SET_NULL, null=True)
price_rate = ForeignKey(PriceRate, on_delete=SET_NULL, null=True)
pallet_amount = IntegerField()
status = BooleanField()
postal_code = CharField(max_length=6)
city = CharField(max_length=255)
street = CharField(max_length=255)
delivery_from = DateTimeField()
delivery_until = DateTimeField(null=True)
created_at = DateTimeField(auto_now_add=True, blank=True)
updated_at = DateTimeField(auto_now=True)
deleted_at = DateTimeField(null=True, blank=True)
views.py
def routecreate_view(request):
orderformset = formset_factory(OrdersRouteForm, can_delete=False, extra=1)
if request.method == 'POST':
form = RouteForm(request.POST)
formset = orderformset(request.POST)
if form.is_valid() and formset.is_valid():
# process the data in form.cleaned_data as required
messages.success(request,
"You succesfully created an route.")
return HttpResponseRedirect(reverse('planner.dashboard'))
else:
form = RouteForm()
formset = orderformset()
return render(request, 'planner/route.html', {'form': form, 'formset': formset})
forms.py
class OrdersRouteForm(forms.ModelForm):
route = ModelChoiceField(
queryset=Order.objects.filter(status=1, delivery_until__gte=datetime.datetime.now(), deleted_at=None),
label='Order')
class Meta:
model = Order
fields = ("route",)
def __init__(self, *args, **kwargs):
super(OrdersRouteForm, self).__init__(*args, **kwargs)
for visible in self.visible_fields():
visible.field.widget.attrs['class'] = 'form-control m-2'
self.fields['route'].label_from_instance = self.label_from_instance
#staticmethod
def label_from_instance(obj):
return "pallets: %s, %s, %s, %s" % (obj.pallet_amount, obj.street, obj.city, obj.postal_code)
template:
{% extends 'base.html' %}
{% block base %}
<div class="container rounded bg-white mt-5 mb-5">
<div class="row">
<div class="col-md-5 border-right mx-auto">
planner//route
<div class="p-3 py-5">
<form id="form-container" method="POST">
{% csrf_token %}
{{ form }}
{{ formset }}
<button id="add-form" type="button">Add Another Bird</button>
<button class="btn btn-danger profile-button mt-3" onclick="window.history.back()">Cancel
</button>
<button class="btn btn-primary float-end mt-3" type="submit">Order</button>
</form>
</div>
</div>
</div>
</div>
{% endblock %}
error:
Cannot assign "<Order: Order object (2)>": "Order.route" must be a "Route" instance.
The error occurs when i fill the formset with request.POST and then try to send the formset to the template.
I have tried an inlineformset and modelformset and didnt get it to work. ANY solution is welcome.
The problem seemed to be with the modelform. I removed this from the code:
class Meta:
model = Order
fields = ("route",)
I don't understand why this caused the problem and if anyone knows and can explain it please feel free to do so.
hope it helps anyone else with this problem.
this is my code and I try to show the label but it is not displaying
this is my form file
forms.py
class ReviewForm(ModelForm):
class Meta:
model = Review
fields = ['value', 'body']
labels = {'value': 'Place your vote', 'body': 'Add a comment with your vote'}
def __init__(self, *args, **kwargs):
super(ReviewForm, self).__init__(*args, **kwargs)
for name, field in self.fields.items():
field.widget.attrs.update({'class': 'input'})
this is my views file and the function for this form
views.py
def project(request, pk):
projectObj = Project.objects.get(id=pk)
form = ReviewForm()
context = {
'project': projectObj,
'form': form
}
return render(request, 'projects/single-project.html', context)
this is the model for the review section
models.py
class Review(models.Model):
VOTE_TYPE = (
('up', 'Up Vote'),
('down', 'Down Vote')
)
owner = models.ForeignKey(Profile, on_delete = models.CASCADE, null=True)
project = models.ForeignKey(Project, on_delete=models.CASCADE)
body = models.TextField(null=True, blank=True)
value = models.CharField(max_length=200, choices=VOTE_TYPE)
created = models.DateTimeField(auto_now_add=True)
id = models.UUIDField(default = uuid.uuid4, unique=True, primary_key=True, editable=False)
class Meta:
# every user can only have single comment on each project
unique_together = [['owner', 'project']]
def __str__(self):
return self.value
and the html file to display the form
html file
<form class="form" action="{% url 'project' project.owner.id %}" method="POST">
{% csrf_token %}
{% for field in form %}
<div class="form__field">
<label for="formInput#textarea">{{field.label}}</label>
{{field}}
</div>
{% endfor %}
<input class="btn btn--sub btn--lg" type="submit" value="Comments" />
</form>
I try to show form.label but it is not displaying
the label is contained in the label_tag property in the field:
<form class="form" action="{% url 'project' project.owner.id %}" method="POST">
{% csrf_token %}
{% for field in form %}
<div class="form__field">
<label for="formInput#textarea">{{field.label_tag}}</label>
{{field}}
</div>
{% endfor %}
<input class="btn btn--sub btn--lg" type="submit" value="Comments" />
</form>
Are you sure for your labels property of Meta class of ModelForm, i do not known this property. You probably need to redefine your field with label you want to, or update field label in the init function of your form.
class ReviewForm(ModelForm):
class Meta:
model = Review
fields = ['value', 'body']
labels = {'value': 'Place your vote', 'body': 'Add a comment with your vote'}
def __init__(self, *args, **kwargs):
super(ReviewForm, self).__init__(*args, **kwargs)
for name, field in self.fields.items():
field.widget.attrs.update({'class': 'input'})
I am building a Create a Recipe form using crispy forms and I am trying to use a datalist input field for users to enter their own ingredients, like 'Big Tomato' or select from GlobalIngredients already in the database like 'tomato' or 'chicken'. However, regardless of whether I enter a new ingredient or select a pre-existing one, I am getting the following error: "Select a valid choice. That choice is not one of the available choices.". How do I fix this error?
Visual:
models.py
class Recipe(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
websiteURL = models.CharField(max_length=200, blank=True, null=True)
image = models.ImageField(upload_to='image/', blank=True, null=True)
name = models.CharField(max_length=220) # grilled chicken pasta
description = models.TextField(blank=True, null=True)
notes = models.TextField(blank=True, null=True)
serves = models.CharField(max_length=30, blank=True, null=True)
prepTime = models.CharField(max_length=50, blank=True, null=True)
cookTime = models.CharField(max_length=50, blank=True, null=True)
class Ingredient(models.Model):
name = models.CharField(max_length=220)
def __str__(self):
return self.name
class GlobalIngredient(Ingredient):
pass # pre-populated ingredients e.g. salt, sugar, flour, tomato
class UserCreatedIngredient(Ingredient): # ingredients user adds, e.g. Big Tomatoes
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
class RecipeIngredient(models.Model):
recipe = models.ForeignKey(Recipe, on_delete=models.CASCADE)
ingredient = models.ForeignKey(Ingredient, null=True, on_delete=models.SET_NULL)
description = models.TextField(blank=True, null=True)
quantity = models.CharField(max_length=50, blank=True, null=True) # 400
unit = models.CharField(max_length=50, blank=True, null=True) # pounds, lbs, oz ,grams, etc
forms.py
class RecipeIngredientForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(RecipeIngredientForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
#self.helper.form_id = 'id-entryform'
#self.helper.form_class = 'form-inline'
self.helper.layout = Layout(
Div(
Div(Field("ingredient", placeholder="Chickpeas - only write the ingredient here"), css_class='col-6 col-lg-4'),
Div(Field("quantity", placeholder="2 x 400"), css_class='col-6 col-md-4'),
Div(Field("unit", placeholder="grams"), css_class='col-5 col-md-4'),
Div(Field("description", placeholder="No added salt tins - All other information, chopped, diced, whisked!", rows='3'), css_class='col-12'),
css_class="row",
),
)
class Meta:
model = RecipeIngredient
fields = ['ingredient', 'quantity', 'unit', 'description']
labels = {
'ingredient': "Ingredient",
"quantity:": "Ingredient Quantity",
"unit": "Unit",
"description:": "Ingredient Description"}
widgets={'ingredient': forms.TextInput(attrs={
'class': 'dropdown',
'list' : 'master_ingredients',
'placeholder': "Chickpeas - only write the ingredient here"
})}
views.py
#login_required
def recipe_create_view(request):
ingredient_list = Ingredient.objects.all()
form = RecipeForm(request.POST or None)
# Formset = modelformset_factory(Model, form=ModelForm, extra=0)
RecipeIngredientFormset = formset_factory(RecipeIngredientForm)
formset = RecipeIngredientFormset(request.POST or None)
RecipeInstructionsFormset = formset_factory(RecipeInstructionForm, extra=0)
instructionFormset = RecipeInstructionsFormset(request.POST or None, initial=[{'stepName': "Step 1"}], prefix="instruction")
context = {
"form": form,
"formset": formset,
"instructionFormset": instructionFormset,
"ingredient_list": ingredient_list
}
if request.method == "POST":
print(request.POST)
if form.is_valid() and formset.is_valid() and instructionFormset.is_valid():
parent = form.save(commit=False)
parent.user = request.user
parent.save()
# formset.save()
#recipe ingredients
for form in formset:
child = form.save(commit=False)
print(child.ingredient)
globalIngredient = Ingredient.objects.filter(name=child.ingredient.lower()) # not truly global as this will return user ingredients too
if (globalIngredient):
pass
else:
newIngredient = UserCreatedIngredient(user=request.user, name=child.ingredient.lower())
newIngredient.save()
if form.instance.ingredient.strip() == '':
pass
else:
child.recipe = parent
child.save()
# recipe instructions
for instructionForm in instructionFormset:
instructionChild = instructionForm.save(commit=False)
if instructionForm.instance.instructions.strip() == '':
pass
else:
instructionChild.recipe = parent
instructionChild.save()
context['message'] = 'Data saved.'
return redirect(parent.get_absolute_url())
else:
form = RecipeForm(request.POST or None)
formset = RecipeIngredientFormset()
instructionFormset = RecipeInstructionsFormset()
return render(request, "recipes/create.html", context)
create.html
<!--RECIPE INGREDIENTS-->
{% if formset %}
<h3 class="mt-4 mb-3">Ingredients</h3>
{{ formset.management_form|crispy }}
<div id='ingredient-form-list'>
{% for ingredient in formset %}
<div class='ingredient-form'>
{% crispy ingredient %}
</div>
{% endfor %}
<datalist id="master_ingredients">
{% for k in ingredient_list %}
<option value="{{k.name|title}}"></option>
{% endfor %}
</datalist>
</div>
<div id='empty-form' class='hidden'>
<div class="row mt-4">
<div class="col-6">{{ formset.empty_form.ingredient|as_crispy_field }}</div>
<div class="col-6">{{ formset.empty_form.quantity|as_crispy_field }}</div>
<div class="col-6">{{ formset.empty_form.unit|as_crispy_field }}</div>
<div id="ingredientIdForChanging" style="display: none;"><div class="col-12">{{ formset.empty_form.description|as_crispy_field }}</div><button type="button"
class="btn btn-outline-danger my-2" onclick="myFunction('showDescription')"><i class="bi bi-dash-circle"></i> Hide
Description</button></div><button type="button"
class="btn btn-outline-primary col-5 col-md-3 col-lg-3 col-xl-3 m-2" id="ingredientIdForChanging1"
onclick="myFunction('showDescription')"><i class="bi bi-plus-circle"></i> Add a
Description Field</button>
</div>
</div>
<button class="btn btn-success my-2" id='add-more' type='button'>Add more ingredients</button>
{% endif %}
You can create your own TextInput and TypedModelListField field to handle this. I think what you're looking for is something which allows the user to both search and provide a recommended selection of choices but validate the input against a model (Ingredient).
I've created one here:
class TypedModelListField(forms.ModelChoiceField):
def to_python(self, value):
if self.required:
if value == '' or value == None:
raise forms.ValidationError('Cannot be empty')
validate_dict = {self.validate_field: value}
try:
value = type(self.queryset[0]).objects.get(**validate_dict))
except:
raise forms.ValidationError('Select a valid choice. That choice is not one of the available choices.')
value = super().to_python(value)
return value
def __init__(self, *args, **kwargs):
self.validate_field= kwargs.pop('validate_field', None)
super().__init__(*args, **kwargs)
class ListTextWidget(forms.TextInput):
def __init__(self, dataset, name, *args, **kwargs):
super().__init__(*args)
self._name = name
self._list = dataset
self.attrs.update({'list':'list__%s' % self._name,'style': 'width:100px;'})
if 'width' in kwargs:
width = kwargs['width']
self.attrs.update({'style': 'width:{}px;'.format(width)})
if 'identifier' in kwargs:
self.attrs.update({'id':kwargs['identifier']})
def render(self, name, value, attrs=None, renderer=None):
text_html = super().render(name, value, attrs=attrs)
data_list = '<datalist id="list__%s">' % self._name
for item in self._list:
data_list += '<option value="%s">' % item
data_list += '</datalist>'
return (text_html + data_list)
Within the RecipeIngredientForm add the following definition:
ingredient = TypedModelListField(
queryset=Ingredient.objects.all(),
validate_field='name')
And then in RecipeIngredientForm within the __init__ function. Include the following after the super() is called.
self.fields['ingredient'].widget = ListTextWidget(
dataset=Ingredient.objects.all(),
name='ingredient_list')
With ecogels comment I was able to understand what was causing the issue and with a combination of Lewis answer and this answer I managed to get this working with the following code.
fields.py
from django import forms
class ListTextWidget(forms.TextInput):
def __init__(self, data_list, name, *args, **kwargs):
super(ListTextWidget, self).__init__(*args, **kwargs)
self._name = name
self._list = data_list
self.attrs.update({'list':'list__%s' % self._name})
def render(self, name, value, attrs=None, renderer=None):
text_html = super(ListTextWidget, self).render(name, value, attrs=attrs)
data_list = '<datalist id="list__%s">' % self._name
for item in self._list:
data_list += '<option value="%s">' % str(item).title()
data_list += '</datalist>'
return (text_html + data_list)
forms.py
from .fields import ListTextWidget
class RecipeIngredientForm(forms.ModelForm):
ingredientName = forms.CharField(required=True)
def __init__(self, *args, **kwargs):
super(RecipeIngredientForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.layout = Layout(
Div(
Div(Field("ingredientName", placeholder="Chickpeas - only write the ingredient here"), css_class='col-6 col-lg-4'),
Div(Field("quantity", placeholder="2 x 400"), css_class='col-6 col-md-4'),
Div(Field("unit", placeholder="grams"), css_class='col-5 col-md-4'),
Div(Field("description", placeholder="No added salt tins - All other information, chopped, diced, whisked!", rows='3'), css_class='col-12'),
css_class="row",
),
)
self.fields['ingredientName'].widget = ListTextWidget(data_list=Ingredient.objects.all(), name='ingredient-list')
class Meta:
model = RecipeIngredient
fields = ['ingredientName', 'quantity', 'unit', 'description']
labels = {
'ingredientName': "Ingredient",
"quantity:": "Ingredient Quantity",
"unit": "Unit",
"description:": "Ingredient Description"}
create.html:
<!--RECIPE INGREDIENTS-->
{% if formset %}
<h3 class="mt-4 mb-3">Ingredients</h3>
{{ formset.management_form|crispy }}
<div id='ingredient-form-list'>
{% for ingredient in formset %}
<div class='ingredient-form'>
{% crispy ingredient %}
</div>
{% endfor %}
</div>
<div id='empty-form' class='hidden'>
<div class="row mt-4">
<div class="col-6">{{ formset.empty_form.ingredientName|as_crispy_field }}</div>
<div class="col-6">{{ formset.empty_form.quantity|as_crispy_field }}</div>
<div class="col-6">{{ formset.empty_form.unit|as_crispy_field }}</div>
<div id="ingredientIdForChanging" style="display: none;"><div class="col-12">{{ formset.empty_form.description|as_crispy_field }}</div><button type="button"
class="btn btn-outline-danger my-2" onclick="myFunction('showDescription')"><i class="bi bi-dash-circle"></i> Hide
Description</button></div><button type="button"
class="btn btn-outline-primary col-5 col-md-3 col-lg-3 col-xl-3 m-2" id="ingredientIdForChanging1"
onclick="myFunction('showDescription')"><i class="bi bi-plus-circle"></i> Add a
Description Field</button>
</div>
</div>
<button class="btn btn-success my-2" id='add-more' type='button'>Add more ingredients</button>
{% endif %}
views.py changes:
form = RecipeForm(request.POST or None)
# Formset = modelformset_factory(Model, form=ModelForm, extra=0)
RecipeIngredientFormset = formset_factory(RecipeIngredientForm)
formset = RecipeIngredientFormset(request.POST or None)
RecipeInstructionsFormset = formset_factory(RecipeInstructionForm, extra=0)
instructionFormset = RecipeInstructionsFormset(request.POST or None, initial=[{'stepName': "Step 1"}], prefix="instruction")
URLForm = RecipeIngredientURLForm(request.POST or None)
context = {
"form": form,
"formset": formset,
"URLForm": URLForm,
"instructionFormset": instructionFormset
}
models.py
class Products(models.Model):
Name = models.CharField(max_length=100, verbose_name='Name of Product')
Category = models.CharField(max_length=100, verbose_name='Product Category')
Description = models.CharField(max_length=220, verbose_name='Product Description')
class Categories(models.Model):
Title = models.CharField(max_length=100, verbose_name='Category Title')
Description = models.CharField(max_length=100, verbose_name='Category Description')
Picture = models.ImageField(default='/gifts.png', upload_to='ffff/')
def __str__(self):
return self.Title
forms.py
class EditProduct(forms.ModelForm):
class Meta:
model = Products
fields = ['Name', 'Category', 'Description', 'Weight', 'Size', 'Cost', 'Personalised', 'Keywords',
'Picture1']
widgets = {
'Category': Select(),
}
def __init__(self, *args, **kwargs):
super(EditProduct, self).__init__(*args, **kwargs)
self.fields['Category'] = forms.ModelChoiceField(queryset=Categories.objects.all().order_by('Title'))
I've created records in models.py Categories (eg Title = 1, Title, 2, Title =3)
In models.py Products i have created some records (eg Name=Hat, Category=1; Name=Cap, Category=3)
I can add Product records easily with crispy forms and my drop down list appears for Category, select the choice and form saves. All works great
But when i try to EDIT the record, i use instance= and it brings the contents of the record back, but i also want a drop down list for category in the edit section, but if i put a drop-down list in, then it doesn't populate that field with existing value, i need to reselect it
My views.py
def products_edit(request, item_id):
pp = Products.objects.get(id=item_id)
my_form = EditProduct(instance=pp)
if 'first' in request.POST:
if request.method == 'POST':
my_form = EditProduct(request.POST, request.FILES, instance=pp)
if my_form.is_valid():
my_form.save()
messages.success(request, f'Thank you the Product has been amended!')
return redirect('frontpage-products')
context = {
'my_form': my_form,
'results': Products.objects.all().order_by('Name')
}
return render(request, 'frontpage/products_edit.html', context)
and my html
<form method="POST" class="form-section" enctype="multipart/form-data">
<div class="page_font search">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">Edit Product</legend>
{{ my_form|crispy }}
</fieldset>
<div class="form-group">
<button class="btn btn-primary" type="submit" name="first">UPDATE</button>
</div>
</div>
</form>
How do i populate the drop-down list with existing value?
I'm getting an issue with my Django form validation. I would like to display form errors and make all fields required. I don't know why my fields can accept blank while blank is not defined in my model file.
This is my model :
class Customer(models.Model):
email = models.CharField(max_length=150, verbose_name=_('e-mail'), null=False)
first_name = models.CharField(max_length=70, verbose_name=_('first name'), null=False)
last_name = models.CharField(max_length=70, verbose_name=_('last name'), null=False)
country = models.ForeignKey(Country, verbose_name=_('country'))
institution = models.CharField(max_length=255, verbose_name=_('institution'), null=True)
creation_date = models.DateTimeField(auto_now_add=True, verbose_name=_('creation date'), null=False)
modification_date = models.DateTimeField(auto_now=True, verbose_name=_('modification date'), null=False)
class Meta:
verbose_name = _('customer')
verbose_name_plural = _('customer')
def __str__(self):
return f"{self.email}"
This is my form :
class CustomerForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(CustomerForm, self).__init__(*args, **kwargs)
self.fields['country'].empty_label = _('Select a country')
self.fields['country'].queryset = self.fields['country'].queryset.order_by(
'name')
for key in self.fields:
self.fields[key].required = True
class Meta:
model = Customer
fields = ['email', 'first_name', 'last_name', 'country', 'institution']
widgets = {
'email': forms.TextInput(attrs={'placeholder': _('name#example.com')}),
'first_name': forms.TextInput(attrs={'placeholder': _('First Name')}),
'last_name': forms.TextInput(attrs={'placeholder': _('Last Name')}),
'institution': forms.TextInput(attrs={'placeholder': _('Agency, company, academic or other affiliation')}),
}
You can find here my view with Django CBV :
class HomeView(CreateView):
""" Render the home page """
template_name = 'app/index.html'
form_class = CustomerForm
def get_context_data(self, **kwargs):
kwargs['document_list'] = Document.objects.all().order_by('publication__category__name')
return super(HomeView, self).get_context_data(**kwargs)
def post(self, request, *args, **kwargs):
if request.method != 'POST':
return HttpResponseRedirect(self.get_success_url())
form = self.form_class(request.POST)
email = request.POST['email']
country_id = request.POST['country']
country = Country.objects.get(id=country_id)
for checkbox in request.POST.getlist('DocumentChoice'):
document = Document.objects.get(id=checkbox)
token = self.gen_token(email, document.edqm_id)
Download.objects.create(email=email, country=country, pub_id=checkbox, token=token,
expiration_date=now + timedelta(minutes=10))
if not form.is_valid():
print('form invalid')
continue
return HttpResponseRedirect(self.get_success_url())
And finally my template :
{% extends "publication/base_backend.html" %}
{% load staticfiles %}
{% load i18n %}
{% load crispy_forms_tags %}
{% block main %}
<form method="post" id="customerform" novalidate>
{% csrf_token %}
<h3>{% trans 'Your information' %}</h3>
<hr>
<div class="col-sm-12 col-md-12 col-lg-12">
{{ form.email|as_crispy_field:"bootstrap" }}
</div>
<br />
<br />
<br />
<br />
<div class="alert alert-info col-sm-12 col-md-12 col-lg-12" role="alert">
<small>{% trans "The fields below are optional if you have already requested a publication:" %}</small>
</div>
<div class="col-sm-5 col-md-5 col-lg-5">
{{ form.first_name|as_crispy_field:"bootstrap" }}<br>
{{ form.country|as_crispy_field:"bootstrap" }}
</div>
<div class="col-sm-5 col-md-5 col-lg-5 col-sm-offset-2 col-md-offset-2 col-lg-offset-2">
{{ form.last_name|as_crispy_field:"bootstrap" }}<br>
{{ form.institution|as_crispy_field:"bootstrap" }}
</div>
<div class="col-md-12">
<br />
<br />
</div>
<input type="submit" class="btn btn-default" value="{% trans 'Save' %}"/>
{% trans 'Cancel' %}
</form>
Issues :
According to required fields, I don't know why my form doesn't display missing values errors when I want to submit it.
I have to display fields as shown in my template because I have to make bootstrap design.
In order to display form errors, I have to write {{form.email.errors}} for example but nothing appears.
Thank you by advance