I am trying to set default values for my form fields in my Django application, but nothing I do seemed to work. I am using Django 2.2.3.
This is my code in views.py:
def my_view(request, template_name="path/to/template"):
form = MyForm(request.POST, initial={
'field_one': field_one_default,
'field_two': field_two_default,
})
try:
if request.method == 'POST':
if form.is_valid():
field_one = form.cleaned_data['field_one']
field_two = form.cleaned_data['field_two']
my_model.field_one = field_one
my_model.field_two = field_two
my_model.save()
return redirect('redirected_page')
return render(request, template_name, {'form': form})
return render(request, template_name, {'form': form})
except Http404 as e:
return Http404("An error occurred.")
This is my code in forms.py:
class MyForm(forms.Form):
field_one_choices = [
('Choice One', 'Choice One'),
('Choice Two', 'Choice Two'),
('Choice Three', 'Choice Three'),
]
field_one = forms.ChoiceField(choices=field_one_choices, required=True)
field_two = forms.IntegerField(
validators=[MaxValueValidator(100), MinValueValidator(1)],
required=True
)
And this is my code in the template:
{% load fontawesome_5 %}
{% load bootstrap4 %}
<div class="container spacing-top">
<form method="post">{% csrf_token %}
{% bootstrap_form form %}
<input class="btn btn-info" type="submit" value="Save">
<a class="btn btn-secondary" href="{% url 'another_page_url' %}">Cancel</a>
</form>
</div>
I have also tried setting the default values in the forms.py, but that did not work either:
field_one = forms.ChoiceField(choices=field_one_choices, required=True, initial=field_one_default)
field_two = forms.IntegerField(
validators=[MaxValueValidator(100), MinValueValidator(1)],
required=True,
initial=field_two_default
)
Any help is greatly appreciated! Thanks in advance!
So I finally found my mistake. Reading the Django documentation tells me the following:
This is why initial values are only displayed for unbound forms. For bound forms, the HTML output will use the bound data.
This part of the documentation explains the meaning of bound and unbound forms, giving form = NameForm(request.POST) as an example of a bound form.
Therefore, to solve the posted problem, I changed my views.py code as such:
def my_view(request, template_name="path/to/template"):
form = MyForm(request.POST or None, initial={
'field_one': field_one_default,
'field_two': field_two_default,
})
...
Related
I am a beginner in Django/Python and whenever I try to submit my form the is_valid() method returns false. I have tried to display the errors using form.errors but it returns nothing or {}. When i try running the following code:
form.non_field_errors()
field_errors = [(field.label, field.errors) for field in form]
I get [('', []), ('Required', [])]
form.py
class ApplicationForm(forms.ModelForm):
email = forms.EmailField(label='', max_length=100, required=True, widget=forms.TextInput(
attrs={'class': 'form-group form-control input-lg ', 'placeholder': 'Email'}), )
required = forms.ModelMultipleChoiceField(queryset=Requirements.objects.all(), widget=forms.CheckboxSelectMultiple)
class Meta:
model = Requirements
fields = ['email', 'required']
views.py
def application_form(request):
try:
form = ApplicationForm()
context = {'form': form}
if request.method == 'GET':
return render(request, 'requirements/job_specs.html', context)
if request.method == 'POST':
print(form.is_valid(), form.errors)
if form.is_valid():
form.save()
return JsonResponse({'created': True})
form.non_field_errors()
field_errors = [(field.label, field.errors) for field in form]
print(field_errors)
return JsonResponse(form.errors.as_json(), safe=False)
except Exception as e:
print(e)
form = ApplicationForm(request.POST or None)
context = {'form': form}
return render(request, 'requirements/job_specs.html', context)
HTML
<form method="POST" id="application-form">
{% csrf_token %}
{{ form }}
<div class="bg-light row" >
<div class="" id="btn-box">
<div class="col-md-12 d-grid gap-2 col-6 ">
<button type="submit" class="btn btn-primary btn-lg">Save</button>
</div>
</div>
</div>
</form>
I have tried to apply solutions from similar posts such as Django forms is not valid or Django forms is not valid but none have helped to solve the problem. Any help will be highly appreciated
After a few hours of looking over the code, i finally found what was wrong with it. I simply had to add request.POST or None in form = ApplicationForm() and it worked like a charm.
In my project, i have a template where i'm trying to put two forms for different use cases. I've never come across this problem before, so i don't really know where to go from here to use two forms in the same page.
At first i thought of creating another view to handle each form, but i think that this solution would create problems with the rendering of my templates, other than not being sustainable if i should have this problem again with another template.
After making some research, i found a solution but it works for class based views, but i'd like to avoid that since my view is already a function based view, and i would have to make a lot of changes in my code. However, if CBV is the best way to go, i can make the change.
Every advice is appreciated
First field
class FirstForm(forms.ModelForm):
firstfield = forms.CharField()
secondfield = forms.CharField()
class Meta:
model = MyModel
fields = ("firstfield", "secondfield")
def save(self, commit=True):
send = super(FirstForm, self).save(commit=False)
if commit:
send.save()
return send**
Second Form
class SecondForm(forms.ModelForm):
firstfield = forms.FloatField()
secondfield = forms.Floatfield()
thirdfield = forms.CharField()
class Meta:
model = MyModelTwo
fields = ("firstfield", "secondfield", "thirdfield")
def save(self, commit=True):
send = super(SecondForm, self).save(commit=False)
if commit:
send.save()
return send
Template
<h3> First Form </h3>
<form method="post" novalidate>
{% csrf_token %}
{% include 'main/includes/bs4_form.html' with form=form %}
<button type="submit" class="btn btn-danger" style="background-color: red;">SUBMIT</button>
</form>
<h3> Second Form </h3>
<form method="post" novalidate>
{% csrf_token %}
{% include 'main/includes/bs4_form.html' with form=form %}
<button type="submit" class="btn btn-danger" style="background-color: red;">SUBMIT</button>
</form>
views.py
def myview(request):
# if this is a POST request we need to process the form data
if request.method == 'POST':
# create a form instance and populate it with data from the request:
form = FirstForm(request.POST)
# check whether it's valid:
if form.is_valid():
# process the data in form.cleaned_data as required
# ...
# redirect to a new URL:
send = form.save()
send.save()
messages.success(request, f"Success")
# if a GET (or any other method) we'll create a blank form
else:
form = FirstForm()
return render(request,
"main/mytemplate.html",
context={"form":form})
I have been told to use a context in my view, but i don't know how to integrate it in my view. Is this a doable solution, or is there a better way to do this?
context = {
'first_form': TradingForm(request.POST or None),
'second_form': LimitSellForm(request.POST or None),
}
Here's one approach. Add a name attribute to your buttons, like this:
<button name="button1" type="submit" class="btn btn-danger" style="background-color: red;">SUBMIT</button>
...
<button name="button2" type="submit" class="btn btn-danger" style="background-color: red;">SUBMIT</button>
Then in your view, you can check which form has been submitted by looking for the button name in the post:
def myview(request):
if request.method == 'POST':
if 'button1' in request.POST:
form1 = FirstForm(request.POST)
if form1.is_valid():
# do what needs to be done and redirect
if 'button2' in request.POST:
form2 = form = SecondForm(request.POST)
if form2.is_valid():
# do what needs to be done and redirect
else:
form1 = FirstForm()
form2 = SecondForm()
return render(request, "main/mytemplate.html",
context={'form1': form1, 'form2': form2})
you can use TemplateView instead for normal view function and add this below
def get_context_data(self, **kwargs):
context = {
'first_form': TradingForm(request.POST or None),
'second_form': LimitSellForm(request.POST or None),
}
you can check in the documentation:
https://docs.djangoproject.com/en/2.2/ref/class-based-views/base/#templateview
I am creating a form using ModelForm to let the users upload a file along with a description . The is_valid() function isn't returning true and I am really confused. I have searched and there are many questions with same title as mine but they don't solve my problem.
here is forms.py:
class PostForm(forms.ModelForm):
document = forms.FileField(widget=forms.FileInput)
class Meta:
model = FeedModel
fields = ['description', 'document']
Here is models.py:
class FeedModel(models.Model):
description = models.CharField(max_length=255, blank=True)
document = models.FileField()
like = models.IntegerField(default=0)
dateTime = models.DateTimeField(auto_now=True, auto_created=True)
user = models.ForeignKey(User, on_delete=models.CASCADE, default=0)
def get_absolute_url(self):
u=self.user
return reverse('home:feed',u.primary_key)
Here is views.py:
class PostView(CreateView):
form_class = PostForm
template_name = 'home/feedModel_form.html'
def get(self, request, *args, **kwargs):
form=self.form_class(None)
return render(request, self.template_name, {'form':form })
def post(self, request, *args, **kwargs):
logger = logging.getLogger(__name__)
form=self.form_class(request.POST)
if form.is_valid():
user=request.user
self.object=form.save(commit=False)
self.object.user=user
self.object.save()
logger.error("voila")
redirect({'home:feed'}, user.id)
return render(request, self.template_name, {'form':form })
def feedview(request, user_id):
user = User.objects.get(pk=user_id)
return render(request, 'home/feed.html', {'user': user})
Here is feedModel_form.html:
{% extends 'home/navbar.html' %}
{% block body %}
<div class="form">
<form action="" method="post" enctype="multipart/form-data">
{% csrf_token %}
{% include 'home/form.html' %}
<button type="submit" class="button button-block" `
name="reg_btn">Post</button>`
</form>
</div>
{% endblock %}
Here is form.html:
{% for field in form %}
<div class="field-wrap">
<label>
{{ field.label_tag }}<span class="req">*</span>
</label>
<div>{{ field }}</div>
</div>
{% endfor %}
To see why the form isn't valid, you should check form.errors.
One error will be because you have not passed request.FILES to the form.
form=self.form_class(request.POST, request.FILES)
There may be other errors as well. If you used {{ form }} in your template, Django would include the errors automatically. Since you are rendering the fields manually, it's up to you to include the errors.
The key problem here is that you have overridden post. That means that you're missing out on lots of the code from CreateView.
In your case, it looks like you could remove the post method, and simply override form_valid instead.
def form_valid(self, form):
self.object=form.save(commit=False)
self.object.user=user
self.object.save()
# Note that you had {'home:feed'} here which was incorrect
return redirect('home:feed', user_id)
Your document field expects an uploaded file and is required. In order for the form to actually get the file, you have to also pass it the uploaded file in views.py:
form = self.form_class(data=request.POST, files=request.FILES)
I'm trying to get a simple form working. Oddly, other forms I wrote in this app are working fine, but this one wont show the fields. Can anyone tell me what I'm missing? Here are the files
views.py:
def newnote(request, record_id):
if request.method == 'POST':
form = NoteForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect('/tracker/all/')
else:
form = NoteForm()
return render(request, 'tracker/noteform.html', {'form': form})
models.py
class Note(models.Model):
record = models.ForeignKey(Record, on_delete=models.CASCADE)
note_text = models.CharField('Notes', max_length=2000)
note_date = models.DateField('Date Entered')
forms.py
class NoteForm(forms.Form):
class Meta:
model = Note
fields = ['note_text',
'note_date'
]
template (noteform.html)
<form action="/tracker/newnote/" method="post">
<div id="fields">
{% csrf_token %}
{{ form }}
<input type="submit" value="Submit" />
</div>
</form>
One other note, I have commented out the div id called "fields", to rule out CSS as the issue.
Your form is based on form.Form, which doesn't know anything about models, doesn't expect a Meta class, and expects all its fields to be declared manually - since you have not declared any fields, nothing will show on the template.
It should inherit forms.ModelForm instead.
I need form where user can create article with several images. I use django-multiupload app for image field. I can select several images but when I try to submit the form I have message under the image field: "Field is empty and field is required". Where is my mistake? Why I have such message when image field is not empty?
Also maybe someone can advice good examples or apps to save several images. I would be very grateful for any help.
models.py:
class Article(models.Model):
description = models.TextField(_('Description'))
class Image(models.Model):
article= models.ForeignKey(Article, on_delete=models.CASCADE)
image = models.FileField(_('Image'), upload_to='images/%Y/%m/%d/')
forms.py:
class ArticleForm(forms.ModelForm):
class Meta:
model = Article
fields = ('description', )
image = MultiFileField()
def save(self, commit=True):
instance = super(ArticleForm, self).save(commit)
for each in self.cleaned_data['image']:
Image.objects.create(image=each, article=instance)
return instance
views.py:
def article_add(request):
data = dict()
if request.method == 'POST':
article_form = ArticleForm(request.POST, request.FILES)
if article_form.is_valid():
article = article_form.save(commit=False)
******
article.save()
data['form_is_valid'] = True
articles = Article.objects.all
context = {'articles': articles}
context.update(csrf(request))
data['html_article'] = render_to_string('project/article_list.html', context)
else:
data['form_is_valid'] = False
else:
article_form = ArticleForm()
context = {'article_form': article_form}
data['html_article_form'] = render_to_string('project/article_add.html', context, request=request)
return JsonResponse(data)
article_add.html:
{% load widget_tweaks %}
<form method="post" action="{% url 'article_add' %}" class="article-add-form">
{% csrf_token %}
{% for field in article_form %}
<div class="form-group{% if field.errors %} has-danger{% endif %}">
<label class="form-control-label" for="{{ field.id_for_label }}">{{ field.label }}</label>
{% render_field field class="form-control" %}
{% for error in field.errors %}
<div class="form-control-feedback">{{ error }}</div>
{% endfor %}
</div>
{% endfor %}
<button type="submit">Submit</button>
</form>
Try adding "min_num" constraint on the image field,
image = MultiMediaField(min_num=1, media_type='image')
EDIT
def article_add(request):
if request.method == 'POST':
article_form = ArticleForm(request.POST, request.FILES)
if article_form.is_valid():
article = article_form.save(commit=False)
******
article.save()
#assume you have already a view in the name 'article_list'.
return redirect('article_list')
else:
article_form = ArticleForm()
context = dict(article_form=article_form)
return render(request, 'project/article_add.html', context)
The problem maybe because you were trying to render two templates in a single view, also when using django template rendering render is a shortcut function, which is mostly preferred to use, rather than string converting and parsing into json.
Also, 'article_list' must be another view, which shows the list of all the articles, after adding a new article, you should consider redirecting to the list view. Here you were trying to render multiple templates, in a single view. You could make of something like this in your list view,
def article_list(request):
articles = Article.objects.all()
context = dict(articles=articles)
return render(request, 'project/article_list.html', context)
Although, these are my personal opinion regarding the code you just shared. Try this approach...