How to properly overwrite clean() method - python

I'm trying the Tango With Django Tutorial and the overwrite in the clean() method isn't working to add 'http://' in my urls. What is wrong in this code?
forms.py
class PageForm(forms.ModelForm):
...
def clean(self):
cleaned_data = self.cleaned_data
url = cleaned_data.get('url')
if url and not url.startswith('http://'):
url += 'http://'
cleaned_data['url'] = url
return cleaned_data
views.py
def add_page(request, category_name_slug):
try:
cat = Category.objects.get(slug=category_name_slug)
except Category.DoesNotExist:
cat = None
if request.method == 'POST':
form = PageForm(request.POST)
if form.is_valid():
if cat:
page = form.save(commit=False)
page.category = cat
page.views = 0
page.save()
return category(request, category_name_slug)
else:
print(form.errors)
else:
form = PageForm()
context_dict = {'category': cat, 'form': form}
return render(request, 'rango/add_page.html', context_dict)
add_page.html
{% extends "base.html" %}
{% block title %}Add Page{% endblock title %}
{% block content %}
<h1>Add a Page</h1>
<form id='page_form' method='post' action="">
{% csrf_token %}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{% for field in form.visible_fields %}
{{ field.errors }}
{{ field.help_text }}
{{ field }}
{% endfor %}
<input type="submit" name="submit" Value="Create Page" />
</form>
{% endblock content %}
The admin is working properly, but the html itself isn't accepting this writing.

Usually, since you are cleaning only one field, you should do this in a field-specific method clean_url.
def clean_url(self):
url = self.cleaned_data['url']
# your cleaning here
return url

you need this:
def clean(self):
cleaned_data = super(PageForm, self).clean() # <-----------
url = cleaned_data.get('url')
if url and not url.startswith('http://'):
url += 'http://'
cleaned_data['url'] = url
return cleaned_data

Related

How to direct a page from a form Django

I am working on a dictionary app, i am allowing a user to enter a word through a form. When the word is entered in the form and a submit button is pressed i want the form to be maintained on the same page however when the user enter the word and presses submit the form disappears leaving only the submit button and the search results
Here is the dictionary/form code
class NameForm(forms.Form):
your_name = forms.CharField(max_length=100, label=False)
the dictionary/view code
def index(request):
if request.method == 'POST':
form = NameForm(request.POST)
if form.is_valid():
word = form.cleaned_data['your_name']
print(word)
if Dictionary.get_verb(word):
verb = Dictionary.get_verb(word)
else:
verb = False
print(verb)
if Dictionary.get_noun(word):
noun = Dictionary.get_noun(word)
else:
noun = False
print(noun)
synonyms = Dictionary.get_synonyms(word)
print(synonyms)
form = NameForm()
context = {
'verb':verb,
'noun':noun,
'synonyms':synonyms,
}
return render(request,'index.html' ,context)
else:
form = NameForm()
context = {
'form': form,
}
return render(request, 'index.html', context)
and the index.html
form action="" method="post">
{% csrf_token %}
{{form}}
<br>
<input type="submit" value="Submit">
</form>
<hr>
{% if noun %}
<h2>Noun</h2>
{% for noun_word in noun %}
<p>{{noun_word}}</p>
{% endfor %}
{% else %}
<!-- print nothing-->
{% endif %}
<br>
<hr>
{% if verb %}
<h2>Verb</h2>
{% for verb_info in verb %}
<p>{{verb_info}}</p>
{% endfor %}
{% else %}
<!-- print nothing-->
{% endif %}
<h2>Synonyms</h2>
{% if synonyms %}
{% for synonym_info in synonyms %}
<p>{{synonym_info}}</p>
{% endfor %}
{% else %}
<!-- print nothing-->
{% endif %}
I have created a dictionary class to interact with the Dictionary API. But my challenge is how do i go about it so that when the form is submitted it will return the form and the button together with the results below. Thank you!!
you are missing the form in context when the form is valid, that's why it is disappearing.
form = NameForm()
context = {
'verb': verb,
'noun': noun,
'synonyms': synonyms,
'form': form ## missing this (add)
}
return render(request,'index.html' ,context)
You can add render in forms.py or you can set the action in your template
<form class="postForm" action="{% url 'name of your url' %}" method="POST">

Editing view for combined form and inline_formset

I have been trying to create an editing view that allows me manage both parent and child models using an inline formset based in the documentation here
From what I can appreciate the formset doesn't validate. I did try and change it so that instead of validating the entire formset it iterated through each individual form in the formset and validated them individually. This did allow me to add items to the formset but not delete them.
At the moment the code results in "didn't return an HttpResponse object. It returned None instead" value error as the redirect is in the If valid statement and so if that does not result in true there is no other redirect to fall back on.
Models
class Shoppinglist(models.Model):
name = models.CharField(max_length=50)
description = models.TextField(max_length=2000)
created = models.DateField(auto_now_add=True)
created_by = models.ForeignKey(User, related_name='lists', on_delete=models.CASCADE)
last_updated = models.DateTimeField(auto_now=True)
def __str__(self):
return self.name
class Item(models.Model):
name = models.CharField(max_length=80, unique=True)
amount = models.IntegerField(default=1)
shoppinglist = models.ForeignKey(Shoppinglist, on_delete=models.CASCADE)
def __str__(self):
return self.name
URL
urlpatterns = [
url(r'^shoppinglists/(?P<pk>\d+)/edit/$', views.shoppinglist_edit, name='shoppinglist_edit'),
]
View
def shoppinglist_edit(request, pk):
try:
shoppinglist = Shoppinglist.objects.get(pk=pk)
except ShoppingList.DoesNotExist:
raise Http404
ItemInlineFormset = inlineformset_factory(Shoppinglist, Item, extra=1, fields=('name', 'amount'))
if request.method == "POST":
form = ShoppinglistForm(request.POST, instance=shoppinglist)
formset = ItemInlineFormset(request.POST, instance=shoppinglist)
if formset.is_valid() and form.is_valid():
form.save()
formset.save()
return redirect('packlist_list', pk=pk)
else:
form = ShoppinglistForm(instance=shoppinglist)
formset = ItemInlineFormset(instance=shoppinglist)
context = {
'shoppinglist' : shoppinglist,
'listform': form,
'formset': formset,
}
return render(request, 'edit_list_with_items.html', context)
Template
{% block content %}
<form method="post">
{% csrf_token %}
<label>List Name</label>
{{ listform.name }}
{% if listform.first_name.errors %}
{% for error in listform.first_name.errors %}
{{ error|escape }}
{% endfor %}
{% endif %}
<label>Description</label>
{{ listform.description }}
{% if listform.description.errors %}
{% for error in listform.description.errors %}
{{ error|escape }}
{% endfor %}
{% endif %}
{{ formset.management_form }}
{% for form in formset %}
<div class="item-formset">
{{ form.amount }}
{% if form.amount.errors %}
{% for error in form.amount.errors %}
{{ error|escape }}
{% endfor %}
{% endif %}
{{ form.name }}
{% if form.name.errors %}
{% for error in form.name.errors %}
{{ error|escape }}
{% endfor %}
{% endif %}
</div>
{% endfor %}
{% if formset.non_form_errors %}
{% for error in formset.non_form_errors %}
{{ error|escape }}
{% endfor %}
{% endif %}
<div class="row spacer">
<button type="submit" class="btn btn-block btn-primary">Create</button>
</div>
</form>
{% endblock %}
{% block extra_js %}
<script>
$('.item-formset').formset({
addText: 'add item',
deleteText: 'remove'
});
</script>
{% endblock %}
Please note I am using this jquery plugin in the template.
https://github.com/elo80ka/django-dynamic-formset
it is probably either your form or formset is invalid, and you dont use else statement to handle that.
so in your views.py:
if request.method == "POST":
form = ShoppinglistForm(request.POST, instance=shoppinglist)
formset = ItemInlineFormset(request.POST, instance=shoppinglist)
if formset.is_valid() and form.is_valid():
form.save()
formset.save()
return redirect('packlist_list', pk=pk)
else:
# either your form or formset is invalid, so this code will render it again.
context = {
'shoppinglist' : shoppinglist,
'listform': form,
'formset': formset,
}
return render(request, 'edit_list_with_items.html', context)
else:
form = ShoppinglistForm(instance=shoppinglist)
formset = ItemInlineFormset(instance=shoppinglist)
context = {
'shoppinglist' : shoppinglist,
'listform': form,
'formset': formset,
}
return render(request, 'edit_list_with_items.html', context)
or you can simplify it with this:
if request.method == "POST":
form = ShoppinglistForm(request.POST, instance=shoppinglist)
formset = ItemInlineFormset(request.POST, instance=shoppinglist)
if formset.is_valid() and form.is_valid():
form.save()
formset.save()
return redirect('packlist_list', pk=pk)
else:
form = ShoppinglistForm(instance=shoppinglist)
formset = ItemInlineFormset(instance=shoppinglist)
# notice the indentation
context = {
'shoppinglist' : shoppinglist,
'listform': form,
'formset': formset,
}
return render(request, 'edit_list_with_items.html', context)
Mentioned error coming because you write this return render(request, 'edit_list_with_items.html', context) inside else block.
instead of this:
else:
form = ShoppinglistForm(instance=shoppinglist)
formset = ItemInlineFormset(instance=shoppinglist)
context = {
'
}
return render(request, 'edit_list_with_items.html', context)
Do this:
else:
form = ShoppinglistForm(instance=shoppinglist)
formset = ItemInlineFormset(instance=shoppinglist)
context = {
}
return render(request, 'edit_list_with_items.html', context)

'ErrorDict' object has no attribute 'status_code' while validating form

I have models.py and forms.py, views.py and as bellow . I want only alpha numeric inputs . after submitting the form, i am getting the error :'ErrorDict' object has no attribute 'status_code'
Kindly suggest .
from django.core.validators import RegexValidator
alphanumeric = RegexValidator(r'^[0-9a-zA-Z]*$', 'Only alphanumeric characters are allowed.')
class News_Post(models.Model):
Country=models.CharField(max_length=20, validators=[alphanumeric])
State=models.CharField(max_length=20, validators=[alphanumeric])
District=models.CharField(max_length=20, validators=[alphanumeric])
Area=models.CharField(max_length=20, validators=[alphanumeric])
Photo_link=models.CharField(max_length=50,blank=True)
News_Title=models.CharField(max_length=200, validators=[alphanumeric])
News=models.TextField(validators=[alphanumeric])
created_date=models.DateTimeField(auto_now_add=True,)
author = models.CharField(max_length=20)
def __str__(self):
return self.News_Title
forms.py:
from django import forms
from django.forms import ModelForm
class NewsForm(forms.ModelForm):
Country=forms.CharField(max_length=20, required=False, help_text='Optional.')
State=forms.CharField(max_length=20, required=False, help_text='Optional.')
District=forms.CharField(max_length=20, required=False, help_text='Optional.')
Area=forms.CharField(max_length=20, required=False, help_text='Optional.')
Photo_link=forms.CharField(max_length=50, required=False, help_text='Optional.')
News_Title=forms.CharField(max_length=200, required=True, help_text='Required')
News=forms.CharField(widget=forms.Textarea)
class Meta:
model = News_Post
fields = ('Country','State','District','Area','Photo_link','News_Title', 'News', )
exclude = ["author"]
Views.py:
.
def new_submit(request):
if request.method == 'POST':
form = NewsForm(request.POST)
if form.is_valid():
c=form.save(commit=False)
c.author = request.user
c.save()
return redirect(my_submitted_news )
else:
return form.errors
else:
form = NewsForm()
return render(request,'new_submit.html', {'form': form})
new_submit.html:
{% block content %}
{% if form.errors %}
<p style="color: red"> Please try again.</p>
{% endif %}
<form method="post">
{% csrf_token %}
<input type="hidden" name="next" value="{{ next }}" />
{% 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">Submit News</button>
{% endblock %}
Edit your view,
def new_submit(request):
if request.method == 'POST':
form = NewsForm(request.POST)
if form.is_valid():
c=form.save(commit=False)
c.author = request.user
c.save()
return redirect('your_url_name' )
else:
return render(request, 'template_name', dict(form, form))
else:
form = NewsForm()
return render(request,'new_submit.html', {'form': form})
When the form is not valid, your else statement returns form.errors directly. That is not a valid thing to return from a view; views always need to return an HTTP response.
You should remove that first else statement, and let execution fall through to the final line so that your template is rendered with the invalid form. You should also modify the template so that it actually outputs the contents of form.errors.

How to use multiple forms with a Form Wizard form in the same template (Django)

I'm using multiple forms in the same template and they all work until I add my Form Wizard, when it becomes that either the FormWizard - form works or the rest of the forms works but not both simultaniousely.
When I have the URL's with postid (?P\d+) -url placed prior to the ContactWizard.as_view -urls the forms in the view - function one_labeling are displayed but not the Form Wizard/ContactWizard.as_view in views.py class ContactWizard(SessionWizardView)
url(r'^label$', LabelingIndex),
url(r'^label(?P<postID>\d+)$',one_labeling),# <----- here
url(r'^label',ContactWizard.as_view([Form1, Form2, Form3])),
url(r'^label(?P<one_labeling>\d+)/$', 'formwizard.views.one_labeling'),
and vice versa, when the URL's for the Form Wizard is placed before the postID - url for the forms in the view function one_labeling then the FormWizard is displayed (and works) but the other forms aren't displayed/evoked.
url(r'^label$', LabelingIndex),
url(r'^label',ContactWizard.as_view([Form1,Form2, Form3])),
url(r'^label(?P<one_labeling>\d+)/$', 'formwizard.views.one_labeling'),
url(r'^label(?P<postID>\d+)$',one_labeling), #<----- here
I'm not sure on how to prefix the Wizard Form so that I could use it as {{ form9.as_p }} like with {{ form3.as_p }} instead of {{ form1 }}{{ wizard.management_form }} or {{ form }} in the done.html below, so that it would work simultaniousely with the other forms in template one_labeling_index.html.
in template done.html
{% extends 'base_one_labeling.html' %}
{% block content %}
{% for form in form_data %}
{{ form }}
{% endfor %}
{% endblock %}
in views.py
class ContactWizard(SessionWizardView):
template_name = "one_labeling_index.html"
def done(self, form_list, **kwargs):
form_data = process_form_data(form_list)
return render_to_response("done.html",{"form_data":form_data})
def process_form_data(form_list):
form_data = [form.cleaned_data for form in form_list]
logr.debug(form_data[0]['subject'])
logr.debug(form_data[1]['sender'])
logr.debug(form_data[2]['message'])
send_mail(form_data[0]['subject'],form_data[1]['sender'],
form_data[2]['message'], 'xxxx#gmail.com',
fail_silently=False)
return form_data
in views.py,LabelingIndex,function evoking template labeling_index.html
def LabelingIndex(request):
#labelings, objects in class Labeling() in models.py
labelings = Labeling.objects.all()
c ={"labelings":labelings}
c.update(csrf(request))
return render(request,"labeling_index.html", c)
in views.py,one_labeling, views function one_labeling
def one_labeling(request,postID):
#one_labeling, object in class Labeling
one_labeling= Labeling.objects.get(id=postID)
template = one_labeling_index.html
if request.method == "POST":
# forms used in one_labeling_index.html
form = SentenceForm(request.POST, prefix="sentence")
form2 = OpenFileForm(request.POST, prefix="file")
form3 = LabelingForm(request.POST,prefix="form3")
form9 =LabelingForm2(request.POST,prefix="labeling")
if form.is_valid() and 'button1' in request.POST:
# do ....
if form3.is_valid() and 'button2' in request.POST:
post_one_labeling(request.POST, one_labeling)
else:
form = SentenceForm()
form2 = OpenFileForm()
form3 = LabelingForm()
form9 = LabelingRRGForm2()
c = {"one_labeling":one_labeling,"form3":form3,"form":form,"form9":form9...... }
c.update(csrf(request))
return render(request,template,c,context_instance=RequestContext(request))
in template Labeling_index.html
{% for one_labeling in labelings %}
# Link to new id (postid) - page; template one_labeling.html
&nbsp Subject: <a href="/label{{ one_labeling.id }}">{{ one_labeling.title }}<a/><br/>
{% endfor %}
in template one_labeling_index.html
# extending base_one_labeling.html
{% extends "base_one_labeling.html" %}
{% block content %}
# form3
<form3 action="" method="post" enctype="multipart/form-data">{% csrf_token %}
{{ form3.as_p }}
</form3>
# Form Wizard
<p>Label {{ wizard.steps.step1 }} out of {{ wizard.steps.count }} ({{ wizard.steps.step1 }}/{{ wizard.steps.count }})</p>
{% for field in form %}
{{field.error}}
{% endfor %}
<form action="" method="post" enctype="multipart/form-data">{% csrf_token %}
<table>
{{ wizard.management_form }}
{% if wizard.form.forms %}
{{ wizard.form.management_form }}
{% for form1 in wizard.form.forms %}
{{ form1 }}
{% endfor %}
{% else %}
{{ wizard.form }}
{% endif %}
</table>
{% if wizard.steps.prev %}
{% endif %}
<html>
<body>
The line
url(r'^label',ContactWizard.as_view([Form1, Form2, Form3])),
matches any url beginning by "label", so any of your other url you put after are never matched.
Also, except the trailing "/", the lines:
url(r'^label(?P<one_labeling>\d+)/$', 'formwizard.views.one_labeling'),
url(r'^label(?P<postID>\d+)$',one_labeling), #<----- here
match the same thing.
So you have to order carefully your urls, and distinguish them somehow to avoid any ambiguity.

Django - Form is not saving the modifications

I'm creating a page where my users can edit their articles but there is one problem, my form is not saving the modifications when I submit my form. Let's have a look:
views.py
def edit(request, id=None, template_name='article_edit.html'):
if id:
article = get_object_or_404(Article, id=id)
if article.user != request.user:
return HttpResponseForbidden()
else:
article = Article(user=request.user)
if request.POST:
form = ArticleForm(request.POST, instance=article)
if form.is_valid():
save_it = form.save()
save_it.save()
form.save_m2m()
return HttpResponseRedirect("/")
else:
form = ArticleForm(instance=article)
context = {'form': form}
populateContext(request, context)
return render(request, template_name, context)
line 3 to 8 : Is to check if it's your own articles there is no problem with that.
line 10 to 18 : There is a problem between these lines, my form is not saving when I submit my form
forms.py (ModelForm)
class ArticleForm(forms.ModelForm):
class Meta:
model = Article
exclude = ['date', 'rating', 'user']
form = ArticleForm()
(Line 4 : I'm excluding the date, the ratings and the username when saved so that the user can not change these informations.)
I don't have any problem in my template.html and the urls.py don't bother with that I checked over 10 times :)
Any help would be great, I'm blocked on this problem since over 1 month...
******* EDIT *******
Models.py
class Article(models.Model):
user = models.ForeignKey(User)
titre = models.CharField(max_length=100, unique=True)
summary = RichTextField(null=True, max_length=140)
contenu = RichTextField(null=True)
date = models.DateTimeField(auto_now_add=True, auto_now=False, verbose_name="Date de parution")
image = models.ImageField(upload_to='article', default='article/amazarashi.jpeg')
rating = RatingField(can_change_vote=True)
tags = TaggableManager(through=TaggedItem, blank=True)
def __str__(self):
return self.titre
Template.html
{% block body %}
{% if user.is_authenticated %}
<p>Authentificated as <strong>{{ user.username }}</strong></p>
{% else %}
<p>NOT Authentificated</p>
{% endif %}
<h1>Edit this {{ article.titre }}</h1>
<br>
<div class="col-xs-12 col-sm-8 col-md-8 col-lg-8">
<form enctype='multipart/form-data' action="{% url "article.views.index" %}" method="post" class="form" autocomplete="off" autocorrect="off">
{% csrf_token %}
<div class="form-group">TITRE
{{ form.titre.errors }}
{{ form.titre }}
</div>
<div class="form-group">SUMMARY
{{ form.media }}
{{ form.summary.errors }}
{{ form.summary }}
</div>
<div class="form-group">CONTENU
{{ form.media }}
{{ form.contenu.errors }}
{{ form.contenu }}
</div>
<div class="form-group">
{{ form.image.errors }}
{{ form.image }}
</div>
<div class="form-group">TAGS
{{ form.tags.errors }}
{{ form.tags }}
</div>
<input type="submit" class="btn btn-default" value="Submit"/>
</div>
</form>
{% endblock %}
According to your error message.. Modify your form in templates:
<form enctype='multipart/form-data' ...>
Add request.FILES to your Form creation:
if request.POST:
form = ArticleForm(request.POST, request.FILES, instance=article)
UPDATE:
You have strange url tag parameter. Are you sure you have defined your url like: ('...', your_view, name='article.views.index')? I am in doubt cause url tag takes url name as parameter but not view path and nobody usually uses url names like this.

Categories

Resources