Django UpdateView forms - django

I have a form class that looks like..
#forms.py
class ExampleForm(forms.Form):
color = forms.CharField(max_length=25)
description = forms.CharField(widget=forms.Textarea, max_lenght=2500)
and my view looks like this..
#views.py
class EditExample(UpdateView):
model = Example
fields = ['color', 'description']
template_name = 'example.html'
def get_success_url(self):
pass
Template:
#example.html
{% for field in form %}
{% if field.errors %}
<div class="control-group error">
<label class="control-label">{{ field.label }}</label>
<div class="controls">{{ field }}
<span class="help-inline">
{% for error in field.errors %}{{ error }}{% endfor %}
</span>
</div>
</div>
{% else %}
<div class="control-group">
<label class="control-label">{{ field.label }}</label>
<div class="controls">{{ field }}
{% if field.help_text %}
<p class="help-inline"><small>{{ field.help_text }}</small></p>
{% endif %}
</div>
{% endif %}
{% endfor %}
When the template is rendered, all the fields show up and populate correctly but the 'description' doesn't show up in a Textarea but rather in a normal field. Im assuming this is because UpdateView works off of 'model = something' rather than 'form = something'.
I have tried..
#views.py
class EditExample(UpdateView):
model = Example
form_class = Exampleform
template_name = 'example.html'
def get_success_url(self):
pass
but I get a Django error saying "init() got an unexpected keyword argument 'instance'.
Is there any way to successfully get the Description to render in a Textarea using Updateview? If not, how would I accomplish this?
Thanks!

Your form needs to inherit from forms.ModelForm, not the base Form class.

Related

How to use model form instances of a formset in Django template

I'm trying to access the instance of the forms in a formset, but it is not working. I CAN access them using the variable notation, as in {{ form }}, but not in code, as in {% url 'section' form.instance.pk %}. I need to iterate through the forms in the formset along with the corresponding model instance.
My view:
# views.py
def sec(request, companyurl):
company = get_if_exists(Company, author=request.user)
SectionFormSet = modelformset_factory(Section, form=SectionForm, can_delete=True)
sections = Section.objects.filter(company=company).order_by('order')
formset = SectionFormSet(request.POST or None,
initial=[{'company': company}],
queryset=sections
context = {
'sections': sections,
'formset': formset,
}
return render(request, 'questions/sections.html', context)
My model:
# models.py
class Section(models.Model):
section = models.CharField(max_length=100)
company = models.ForeignKey(Company, on_delete=models.CASCADE)
order = models.PositiveIntegerField(default=1000000)
show = models.BooleanField(default=True)
def __str__(self):
return self.section
My Form (I'm using django-crispy forms):
# forms.py
class SectionForm(forms.ModelForm):
class Meta:
model = Section
fields = ['company', 'section', 'show', 'order']
labels = {
'section': '',
'show': 'Show'
}
def __init__(self, *args, **kwargs):
super(SectionForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_tag = False
self.helper.layout = Layout(
Div(
Div(HTML("##"), css_class = 'my-handle col-auto'),
Div('section', css_class='col-3'),
Div('show', css_class = 'col-auto'),
Div('DELETE', css_class = 'col-auto'),
Field('company', type='hidden'),
Field('order', type='hidden'),
css_class='row',
),
)
My template (this is where the problem is seen):
<form action="#" method="post">
{% csrf_token %}
{{ formset.management_form }}
<div id="simpleList" class="list-group">
{% for fo in formset %}
<div class="list-group-item hold">
{% crispy fo %}
<!-- TESTING TO SEE IF THIS WORKS, AND IT DOES! -->
{{ fo.instance }} + {{ fo.instance.pk }} + {{ fo.instance.section }}
<!-- THE PROBLEM OCCURS WHEN THIS IS ADDED -->
<a href="{% url 'section' fo.instance.pk fo.instance.section %}">
{{ fo.instance }}
</a>
<!-------------------------------------------->
<input type="hidden" name="order" value="{{ section.pk }}">
{% for hid in fo.hidden_fields %}
{{ hid }}
{% endfor %}
</div>
{% endfor %}
<button type="submit" class="btn btn-outline-primary">Save changes</button>
</form>
When I add the <a href="{% url 'section' fo.instance.pk fo.instance.section %}>link</a> line I get
Reverse for 'section' with arguments '(None, '')' not found. 1 pattern(s) tried: ['section/(?P<pk>[0-9]+)/(?P<section>[^/]+)\\Z']
The error is clear. fo.instance.pk is None and fo.instance.section is an empty string. Yet when I remove the anchor tag, the line above appears and shows the correct values for both of these. I think I know the difference in how the {{ }} and the {% %}, and I thought I knew how model form instances were tied to the model, but I am missing something.
Thanks for any help.
Formsets create blank forms
The answer was staring me in the face, when I printed the results. The last form, a blank, of course was giving me None and an empty string, since it had no data to fill it with. Thus the simple solution is to check for this before trying to form the url with the information. Therefore, this has nothing to do with the differences between {{ }} and {% %} nor form instances.
{% for fo in formset %}
<div class="list-group-item hold">
{% crispy fo %}
<!-- TESTING TO SEE IF THIS WORKS, AND IT DOES! -->
{{ fo.instance }} + {{ fo.instance.pk }} + {{ fo.instance.section }}
<!-- THE PROBLEM OCCURED WHEN THIS WAS ADDED -->
<!-- THE SIMPLE SOLUTION: --------------------->
{% if fo.instance.pk %}
<a href="{% url 'section' fo.instance.pk fo.instance.section %}">
{{ fo.instance }}
</a>
{% endif %}
<!-------------------------------------------->
<input type="hidden" name="order" value="{{ section.pk }}">
{% for hid in fo.hidden_fields %}
{{ hid }}
{% endfor %}
</div>
{% endfor %}
<button type="submit" class="btn btn-outline-primary">Save changes</button>
</form>

django-autocomplete-light template not rendering autocomplete widget

I am trying to make a search field on my homepage where you search entries by tag, and within that search field as you type in letters it should suggest you tags that contain what you have typed so far. I am using django-taggit for tags.
I have followed this tutorial :
https://django-autocomplete-light.readthedocs.io/en/master/taggit.html
It has support for django-taggit.
template
<div class="search-container">
<form method="post">
{% csrf_token %}
{% for field in form %}
{{ field.label_tag }}
{{ field }}
{% endfor %}
<button type="submit">Search</button>
</form>
</div>
urls.py
# AUTOCOMPLETE URL
url(r'^tag-autocomplete/$', views.TagAutocomplete.as_view(), name='tag-autocomplete'),
forms.py
class SearchForm(autocomplete.FutureModelForm):
class Meta:
model = Intrare
fields = ('tags',)
widgets = {
'tags': autocomplete.TaggitSelect2('intrari:tag-autocomplete')
}
models.py
class Intrare(models.Model):
tags = TaggableManager()
def __str__(self):
return self.titlu
views.py
class TagAutocomplete(autocomplete.Select2QuerySetView):
def get_queryset(self):
intrari = [intrare.tags for intrare in Intrare.objects.filter(public=True)]
tags = reduce(lambda x, y: x | y, [tags.get_queryset() for tags in intrari])
tags = [tag.name for tag in tags]
qs = Tag.objects.filter(name__in=tags)
if self.q:
qs = qs.filter(name__contains=self.q)
return qs
Here is the result. The widget does not show properly
I have found the mistake, I forgot to add {{ form.media }} in template.
<div class="search-container">
{{ form.media }}
<form method="post">
{% csrf_token %}
{% for field in form %}
{{ field.label_tag }}
{{ field }}
{% endfor %}
<button type="submit">Search</button>
</form>
</div>

How to show django form in django template?

I am trying to create a form using django and css.
views.py
from django.shortcuts import render
from .forms import ContactForm
def home(request):
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
pass
else:
form = ContactForm()
return render(request, 'home.html', {'form':form})
forms.py
from django import forms
class ContactForm(forms.Form):
name = forms.CharField(max_length = 30)
email = forms.EmailField(max_length = 254)
message = forms.CharField(max_length = 2000, widget = forms.Textarea(),help_text = "Write Your Message here")
def clean(self):
cleaned_data = super(ContactForm, self).clean()
name = cleaned_data.get('name')
email = cleaned_data.get('email')
message = cleaned_data.get('message')
if not name and not email and not message:
raise forms.ValidationError('You have to write something!')
When I try to add the form to my html page like the following it doesn't show up. Just the button shows up, no form fields -
{% extends 'store/main.html' %}
{% load static %}
{% block content %}
<h3>Store</h3>
<form method = "post" novalidate>
{% csrf_token %}
{{ form }}
<button type='submit'>Submit</button>
</form>
{% endblock content %}
If I do css form instead it obviously show up the way it should.
{% extends 'store/main.html' %}
{% load static %}
{% block content %}
<h3>Store</h3>
<form>
<label for="fname">First Name</label>
<input type="text" id="fname" name="fname">
<button type='submit'>Submit</button>
</form>
{% endblock content %}
So I decided to add the form fields individually to the css form. Where does the {{form.name}} or {{form.email}} tag go?
EDIT:
Hey Vivek, the contact form code is this -
class ContactForm(forms.Form):
name = forms.CharField(max_length = 30)
email = forms.EmailField(max_length = 254)
message = forms.CharField(max_length = 2000, widget = forms.Textarea(),help_text = "Write Your Message here")
The html template looks like this-
{% extends 'store/main.html' %}
{% load static %}
{% block content %}
<h3>Store</h3>
<form method = "post" novalidate>
{% csrf_token %}
<label class="float-left" for="name">Name</label>
{{ form.name }}
<button type='submit'>Submit</button>
</form>
{% endblock content %}
Thanks for any input.
Accessing form fields individually will make you to render the form errors individually as well. {{form}} encapsulates everything:- Form fields , errors, non_field_errors..So if you have to access the fields individually do not forget to add the form errors.
I have written a sample code which will server the purpose.
{% csrf_token %}
{% if form.errors %}
<div class="alert alert-danger" style="text-align:left">
<ul>
{% for field in form %}
{% for error in field.errors %}
<li><strong>{{ error|escape }}</strong></li>
{% endfor %}
{% endfor %}
{% for error in form.non_field_errors %}
<li><strong>{{ error|escape }}</strong></li>
{% endfor %}
</ul>
</div>
{% endif %}
<div class="form-row">
<div class="col-md-4 mb-3">
<label class="float-left" for="id_name">Name</label>
{{ form.name }}
</div>
<div class="col-md-8 mb-3">
<label class="float-left" for="id_email">Email ID</label>
{{ form.email }}
</div>
</div>
<br>
<input type="submit" class="btn btn-primary" value="Pay" id="submit">
</form>

django rest framework: how to add custom css class to the ModelSerializer

I'm using django rest framework and I want to add extra css class names to the PostSerializer's fields. This is my code:
models.py
class Post(models.Model):
title = models.CharField(default="New Post", max_length=50)
text = models.TextField(blank=True, null=True)
serializers.py
class PostSerializer(serializers.ModelSerializer):
class Meta:
model = Post
fields = ('id', 'title', 'text')
A field like title will be rendered as:
<div class="form-group ">
<label >Title</label>
<input name="title" class="form-control" type="text" value="" >
</div>
There is already a class form-control exist, I want to add another one, how could I achieve it?
To set custom class for serializer field in your API you should define custom template for the field type and than define serializer field with this custom template.
First create custom template for example for the input field, which is a copy of rest framework's built-in input.html with added {{ style.class }} next to form-control. Place this inside your templates folder, either inside your app's templates folder or project's templates folder.
custom_input.html
<div class="form-group {% if field.errors %}has-error{% endif %}">
{% if field.label %}
<label class="col-sm-2 control-label {% if style.hide_label %}sr-only{% endif %}">
{{ field.label }}
</label>
{% endif %}
<div class="col-sm-10">
<input name="{{ field.name }}" {% if style.input_type != "file" %}class="form-control {{ style.class }}"{% endif %} type="{{ style.input_type }}" {% if style.placeholder %}placeholder="{{ style.placeholder }}"{% endif %} {% if field.value is not None %}value="{{ field.value }}"{% endif %} {% if style.autofocus and style.input_type != "hidden" %}autofocus{% endif %}>
{% if field.errors %}
{% for error in field.errors %}
<span class="help-block">{{ error }}</span>
{% endfor %}
{% endif %}
{% if field.help_text %}
<span class="help-block">{{ field.help_text|safe }}</span>
{% endif %}
</div>
</div>
And than declare your serializer with custom_input.html and class attribute set to desired classes. In this example test1 and test2 classes will be added next to form-control class.
serializers.py
class PostSerializer(serializers.ModelSerializer):
title = serializers.CharField(style={'template': 'your_template_folder/custom_input.html', 'class': 'test1 test2'})
class Meta:
model = Post
fields = ('id', 'title', 'text')

Django returning bad help text in my signup page

As you can see the help text is not being rendered as UL instead its just plain text
Here is my code
Forms.py:
class CustomUserCreationForm(UserCreationForm):
class Meta(UserCreationForm.Meta):
model = CustomUser
now = datetime.datetime.now()
fields = ('username', 'email', 'gender', 'security_question', 'answer', 'birth_date', 'resume')
widgets={
'birth_date' :DatePickerInput(
options={
'maxDate':str(datetime.datetime.now()),
}
)
}
Views.py:
class SignUp(generic.CreateView):
form_class = CustomUserCreationForm
success_url = reverse_lazy('login')
template_name = 'users/signup.html'
signup.html:
{% extends 'base.html' %}
{% block title %}Sign Up{% endblock %}
{% block content %}
<div class="login-page">
<h1>Sign up</h1>
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
<!--
{{ form.as_p }}
-->
<div class="form">
{% for field in form %}
<p>
{{ field.label_tag }}<br>
{{ field }}
{% if field.help_text %}
<small style="color: grey">{{ field.help_text }}</small>
{% endif %}
{% for error in field.errors %}
<p style="color: red">{{ error }}</p>
{% endfor %}
</p>
{% endfor %}
<button type="submit">Sign up</button>
</div>
</form>
</div>
{% endblock %}
Can someone help me figure out how do i Fix the issue ? i am using Django2.0.6
help_text is allowed to contain HTML - but you are rendering it as a safe string - you need to use the safe template filter to allow the HTML to be rendered.
You are also rendering it inside a <small> tag which will result in invalid HTML if the help text contains a list, as it does in this case.
I'd suggest you consider refactoring your template do handle this - e.g.:
{% if field.help_text %}
<div style="color: grey">{{ field.help_text|safe }}</div>
{% endif %}
You might also want to consider using styled classes instead of inline styling for these elements.
If you don't want HTML to appear in the help_text then you will need to modify the help_text of the field in question.