How to render a bound Django model form as HTML-safe? - django

I am trying to return a bound form that has been modified and has some arbitrary text and HTML inserted into it. I have done some research and have been able to successfully insert some arbitrary text into a bound form but I haven't found any way to render the injected HTML as HTML. It renders as plain text. How can I achieve my goal?
Here is the code:
# views.py
def multi_text(request):
if request.method == 'POST':
data = request.POST.copy()
form = MultilineForm(data=data)
if form.is_valid():
cd = form.cleaned_data
form.data['text'] = '<i>Hello hello</i>'
return render(request, 'multi_text.html', {'form': form})
else:
form = MultilineForm()
return render(request, 'multi_text.html', {'form': form})
# forms.py
class MultilineForm(ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['text'].widget.attrs.update({'class': 'form-control'}, verbose_name='Text', placeholder='Type your text here...')
self.data['text'] = '...'
class Meta:
model = Multiline
fields = ['text']
widgets = {
'text': Textarea(attrs={}),
}
# template.html
<form method="post" action="" class="form">
{% csrf_token %}
{{ form.text.as_widget }}
<span class="input-group-btn">
<input type="submit" value="Check" class="form-control btn btn-primary">
</span>
</form>

Related

Form fields not showing when including form template

The form fields don't show when including form in another template. This is the form:
class ClinicSearchForm(forms.Form):
q = forms.CharField()
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['q'].label = 'Search for'
self.fields['q'].widget.attrs.update(
{'class': 'form-control'})
This is the template:
<form method="get">
{{ form.as_p }}
<input type="submit" class="btn btn-primary my-1" value="Search">
</form>
And the view:
def clinic_search(request):
form = ClinicSearchForm
results = []
if 'q' in request.GET:
form = ClinicSearchForm(request.GET)
if form.is_valid():
q = form.cleaned_data['q']
results = Clinic.objects.filter(name__icontains=q)
context = {
'form' : form,
'results' : results,
}
return render(request, 'guide/clinic/clinic_search.html', context)
I'm including the form with the include tag but I only get rendered the button, not the field.
The form shows when in its own url, but not when included in another template (this other template has no other forms).
What am I missing?

django model based forms - why isn't form valid?

I'm trying to make model based form but something went wrong.
model:
class Topic(models.Model):
name = models.CharField(max_length=200)
icon = models.ImageField(upload_to = 'images/')
form:
class TopicCreationForm(ModelForm):
class Meta:
model = Topic
fields = '__all__'
view:
def TopicCreateView(request):
form = TopicCreationForm()
if request.method == 'POST':
form = TopicCreationForm(request.POST)
if form.is_valid():
form.save()
return redirect('home')
else:
print('aaa') # It displays in console
context = {'form':form}
return render(request, 'blog/topic_form.html', context)
my form html part
<form method="POST">
{% csrf_token %}
<fieldset >
<legend> New Topic</legend>
{{ form|crispy }}
</fieldset>
<div>
<input type="submit" value="submit" class="button-33" role="button">
</div>
</form>
where did i make mistake ?
You need to pass both request.POST and request.FILES [Django-doc], so:
def topic_create(request):
if request.method == 'POST':
form = TopicCreationForm(request.POST, request.FILES)
if form.is_valid():
form.save()
return redirect('home')
else:
print('aaa') # It display in console
else:
form = TopicCreationForm()
context = {'form':form}
return render(request, 'blog/topic_form.html', context)
In the HTML form, you need to specify that the files should be encoded with the enctype="…" attribute [mdn]:
<form method="post" enctype="multipart/form-data">
…
</form>

Django dropdown form submission invalid

Hey i am trying to use modelchoicefield to get a dropdown list in html. But the submission of form yields a invalid form. My code is given below.
views.py
class SubjectSelectFormView(View):
form_class = SubjectSelectForm
template_name = 'study/select_subject.html'
def get(self, request):
form = self.form_class(user=request.user)
return render(request, self.template_name, {'form':form})
def post(self, request):
form = self.form_class(request.POST)
if form.is_valid():
subject = models.Subject.objects.get(name=form['name'])
return HttpResponseRedirect('study:quiz', subject.subject_id)
else:
return HttpResponse('<h1>Failed</h1>')
forms.py
class SubjectSelectForm(forms.Form):
name = forms.ModelChoiceField(queryset=Subject.objects.all().order_by('name'), widget=forms.Select())
def __init__(self, *args, **kwargs):
user = kwargs.pop('user', None)
super(SubjectSelectForm,self).__init__(*args, **kwargs)
self.fields['name'].queryset = Subject.objects.filter(user_id=user)
html
{% extends 'basic_home_app/base.html' %}
{% block content %}
<br>
<form class="form-horizontal" action="" method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Start">
</form>
{% endblock %}
First you should always render the same template with the bound form when a posted form is found to not be valid, this way you can display errors to the user:
def post(self, request):
form = ...
if form.is_valid():
...
else:
return render(request, self.template_name, {'form':form})
Inside your template, you can display errors using either:
{{ form.errors }} # all form errors
{{ form.non_field_errors }} # form errors that aren't for one specific field, use this if you're displaying the field errors separately
or
{{ form.name.errors }} # just the errors for one specific field
Second, I assume you want to initialise your form the same way when it's posted as when it's first displayed (empty) to the user via the get() request:
def post(self, request):
form = self.form_class(request.POST, user=request.user) # note the user
Otherwise your form.__init__() method will set as queryset only Subject objects where user_id is None.

Difficulty uploading a file to a FileField, form isn't valid

Halo, i'm trying to upload a file using filefield. But i always failed. when statement form.errors.as_data() executed, the browser return 'tempfile'. I already trying to find solution from django documentation and some django references. But, still can't fix it. ;(
Here's my view.py
def dataprocessing(request):
if request.method == 'POST':
form = DocumentForm(request.POST, request.FILES)
if form.is_valid():
import pdb; pdb.set_trace()
newdoc = Document(docfile=request.FILES['myfile'])
newdoc.save()
#Redirect to the dataprocessing after POST
#return render(request, 'dataprocessing.html')
return HttpResponse("success")
else:
return HttpResponse(form.errors.as_data())
else:
import pdb; pdb.set_trace()
form = DocumentForm() #A empty, unbound form
return render(request, 'dataprocessing.html', {'form': form})
models.py
class Document(models.Model):
docfile = models.FileField(upload_to='documents/%Y/%m/%d')
forms.py
class DocumentForm(forms.Form):
tempfile = forms.FileField()
And dataprocessing.html
<form method="post" enctype="multipart/form-data" action="{% url "dataprocessing" %}">
<div class="form-group">
<label for="up">Input Data</label> {% csrf_token %}
<input type="file" name=myfile class="filestyle" data-buttonName="btn-primary" data-buttonBefore="true" data-size="sm" accept="application/vnd.ms-excel, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
id="up">
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary btn-block">Upload Data</button>
<button type="button" class="btn btn-primary btn-block">Download Template</button>
</div>
</form>
How about using forms.ModelForm instaed forms.Form like this?
# forms.py
class DocumentForm(forms.Model):
class Meta:
model = Document
fields = ['tempfile']
and make your views.py like this:
# views.py
def dataprocessing(request):
if request.method == 'POST':
form = DocumentForm(request.POST, request.FILES)
if form.is_valid():
form.save()
return HttpResponse("success")
else:
return HttpResponse(form.errors.as_data())
else:
form = DocumentForm() #A empty, unbound form
return render(request, 'dataprocessing.html', {'form': form})
This makes form object can be saved directly to your model.

Django Template Form Render

My problem is not to show django form fields on template.It's silly but I just haven't found any solution.
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = ['name', 'email', 'text']
def __init__(self, content_type, id, *args, **kwargs):
super(CommentForm, self).__init__(*args, **kwargs)
self.content_type = content_type
self.id = id
def save(self, commit=True):
post_type = ContentType.objects.get_for_model(Post)
comment_type = ContentType.objects.get_for_model(Comment)
comment = super(CommentForm, self).save(commit=False)
if self.content_type == 'post':
comment.content_type = post_type
comment.post = self.id
else:
parent = Comment.objects.get(id=self.id)
comment.content_type = comment_type
comment.post = parent.post
comment.object_id = self.id
if commit:
comment.save()
return comment
my view:
def add_comment(request, content_type, id):
if request.method == 'POST':
data = request.POST.copy()
form = CommentForm(content_type, id, data)
if form.is_valid():
form.save()
return redirect(reverse('index'))
my add_comment template:
<form method="post" action="{% url 'add_comment' 'post' post.id %}">
{% csrf_token %}
{% if not user.is_authenticated %}
{{ form.name.label_tag }}
{{ form.name }}
{{ form.email.label_tag }}
{{ form.email }}
{% endif %}
{{ form.text.label_tag }}
{{ form.text }}<br>
<input type="submit" value="Comment" />
</form>
and I included like:
<button id="button" type="button">Add Comment</button>
<div id="post_comment_form">{% include 'articles/add_comment.html' %}</div>
</article> <!-- .post.hentry -->
why not django rendered form fields,despite of showing buttons?
EDIT:
I'm rendering form in post view.
def post(request, slug):
post = get_object_or_404(Post, slug=slug)
comments = Comment.objects.filter(post=post.id)
return render(request,
'articles/post.html',
{'post': post,
'form': CommentForm,
'comments': comments,
# 'child_comments': child_comments
}
)
You forgot to instantiate the form, change this line:
'form': CommentForm,
to this
'form': CommentForm(),
In your view, you're not sending any context variables to the template, so your 'form' object isn't available for your template to process.
For example, the following return statement will render your .html and pass along all local variables, this isn't necessarily the best option (how much do you want your template to have access to), but is simple:
from django.shortcuts import render
...
return render(request, "template.html", locals())
you can also pass a dictionary instead of all local variables. Here's the documentation for render