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.
Related
I've created a django subscription form. I want to show a 'Thank You' message below the form after submitting but if I submit the form, email field is still showing the value. I've tried HttpResponseRedirect('/') but doing so doesn't show 'Thank You' message.
#Views.py
global categories
categories = ['Development','Technology','Science','Lifestyle','Other']
class IndexView(TemplateView):
model = Post
template_name = 'blog/index.html'
def post(self,request,*args,**kwargs):
context = self.get_context_data()
if request.method == 'POST':
form = SubscriberForm(request.POST)
if context["form"].is_valid():
context["email"] = request.POST.get('email')
form.save()
form = SubscriberForm()
return render(request, 'blog/index.html', context=context)
else:
form = SubscriberForm()
def get_context_data(self, **kwargs):
# Call the base implementation first to get a context
context = super(IndexView,self).get_context_data(**kwargs)
# Add in a QuerySet of all the books
context['post_list'] = Post.objects.all()
context["categories"] = categories
form = SubscriberForm(self.request.POST or None) # instance= None
context["form"] = form
return context
#sidebar.html
<div class="subscribe">
<form class="" action="" method="post">
{% csrf_token %}
{{ form.as_p }}
<button id="subscribe-button" type="submit" name="button"><i class="fa fa-paper-plane" aria-hidden="true"></i></button>
</form>
{% if email %}
<h6>Thank you for Subscribing!</h6>
{% endif %}
<!-- <i class="fa fa-paper-plane" aria-hidden="true"></i> -->
</div>
#models.py
class Subscribe(models.Model):
email = models.EmailField()
subscribed_on = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ('-subscribed_on',)
def __str__(self):
return 'Subscribed by {} on {}'.format(self.email, self.subscribed_on)
#forms.py
class Subscribe(models.Model):
email = models.EmailField()
subscribed_on = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ('-subscribed_on',)
def __str__(self):
return 'Subscribed by {} on {}'.format(self.email, self.subscribed_on)
Instead of rendering the template you can redirect() after saving the form.
And to render the success message you can use the django messaging framework.
def post(self,request,*args,**kwargs):
context = self.get_context_data()
if request.method == 'POST':
form = SubscriberForm(request.POST)
if context["form"].is_valid():
context["email"] = request.POST.get('email')
form.save()
messages.success(request, 'Thank you for subscribing')
return redirect('/')
else:
form = SubscriberForm()
return render(request, 'blog/index.html', context=context)
Now in the template you can render the messages like this.
<div class="subscribe">
<form class="" action="" method="post">
{% csrf_token %}
{{ form.as_p }}
<button id="subscribe-button" type="submit" name="button"><i class="fa fa-paper-plane" aria-hidden="true"></i></button>
</form>
{% if messages %}
<ul class="messages">
{% for message in messages %}
<li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
<!-- <i class="fa fa-paper-plane" aria-hidden="true"></i> -->
</div>
Can you help me out with this. I hava a model form and I need to raise an error after validate two datetime objects in the clean method of the model form. This is what I have.
Forms
class HorariosDisponibles(forms.ModelForm):
tutor = forms.ModelChoiceField(queryset=Tutor.objects.all(),widget=forms.Select(attrs= {'class': 'input is-small is-rounded ' }),label='TUTOR',)
dia_hor_inicio =forms.DateTimeField(widget=forms.DateTimeInput(attrs= {'class': 'input is-small is-rounded ',}),label='Horario de Inicio', initial=datetime.date.today )
dia_hor_fin= forms.DateTimeField(widget=forms.DateTimeInput(attrs= {'class': 'input is-small is-rounded ' }),label='Horario de FinalizaciĆ³n', initial=datetime.date.today)
class Meta:
model = horarios_disp
fields = '__all__'
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields["dia_hor_inicio"].widget = DateTimeInput()
self.fields["dia_hor_inicio"].input_formats = ["%Y-%m-%dT%H:%M", "%Y-%m-%d %H:%M"]
self.fields["dia_hor_fin"].widget = DateTimeInput()
self.fields["dia_hor_fin"].input_formats = ["%Y-%m-%dT%H:%M", "%Y-%m-%d %H:%M"]
def clean(self):
cleaned_data = super(HorariosDisponibles, self).clean()
tutor = cleaned_data.get("tutor")
dia_hor_inicio = cleaned_data.get("dia_hor_inicio")
dia_hor_fin = cleaned_data.get("dia_hor_fin")
if dia_hor_inicio and dia_hor_fin:
if dia_hor_inicio.day != dia_hor_fin.day :
msg = 'Las fechas no pueden ser distintas'
self.add_error("dia_hor_inicio", msg)
raise forms.ValidationError("Las fechas no pueden ser distintas")
#NEITHER OF THIS APPROACHES WORKED
return cleaned_data
VIEWS
#login_required
def horario_tutor(request):
context = {
}
if request.method == 'POST':
print(request.POST)
form = HorariosDisponibles(request.POST)
if form.is_valid():
tutor = form.cleaned_data['tutor']
print("adentro")
dia_hor_inicio = form.cleaned_data['dia_hor_inicio']
dia_hor_fin = form.cleaned_data['dia_hor_fin']
tutor_horario = horarios_disp(
tutor=tutor, dia_hor_inicio=dia_hor_inicio, dia_hor_fin=dia_hor_fin)
tutor_horario.save()
context = {
'form': form
}
return redirect("home")
return render(request,"horarios_disponibles.html", context)
else:
form = HorariosDisponibles()
context['form'] = form
return render(request, "horarios_disponibles.html", context)
TEMPLATES
{% extends 'base.html' %}
{% block body %}
<section class="section">
<div class="columns is-vcentered">
<div class="column is-centered is-4 is-offset-2">
<form method="post">
{% csrf_token %}
{% for field in form %}
<div class="field">
{% for error in field.errors %}
<p class="help is-danger">{{ error }}</p>
{% endfor %}
<label for="{{field.id_for_label}}" class="label">{{ field.label }}</label>
{{ field }}
{% for non_field_error in form.non_field_errors %}
<p class="help is-danger">{{ non_field_error }}</p>
{% endfor %}
{% if field.help_text %}
<p class="help is-danger">{{ field.help_text|safe }}</p>
{% endif %}
</div>
{% endfor %}
<p class="control">
<button class="button is-link" type="submit">
Enviar
</button>
</p>
</form>
</section>
It validates if I put two different dates in the form, but it doesn't enter to is_valid() (because ther form is not valid). Render just the button of the template.
Try this:
if form.is_valid():
tutor = form.cleaned_data['tutor']
dia_hor_inicio = form.cleaned_data['dia_hor_inicio']
dia_hor_fin = form.cleaned_data['dia_hor_fin']
tutor_horario = horarios_disp(
tutor=tutor, dia_hor_inicio=dia_hor_inicio, dia_hor_fin=dia_hor_fin
)
tutor_horario.save()
context = {'form': form}
return redirect("home")
else:
context = {'error': 'whatever error you want to show here'}
return render(request, "horarios_disponibles.html", context)
# and probably some extra handling at the end in case there are errors
As a matter of fact, you won't need to declare the context = {} at the beginning of your code before if request.method == 'POST' because you're going to declare one on in the if-else statement anyways.
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)
I've tried looking around for solutions on how to check if a form's name is already existing in the database. I used this link to figure out how, and it is indeed not allowing duplicate names to be entered. But where I expected one, I did not get an error message. I'm not sure what I'm doing wrong here, so if anyone can tell me what I should do, that would be really useful!
addgame.html:
<form method="POST" class="post-form" enctype="multipart/form-data">
{% csrf_token %}
{% if form.non_field_errors %}
{% for error in form.non_field_errors %}
{{ error }}
{% endfor %}
{% endif %}
<div class="form-group">
{{ form.name.label_tag }}
{% render_field form.name class="form-control" %}
<br>
{{ form.genre.label_tag }}
{% render_field form.genre class="form-control" %}
<br>
{{ form.image.label_tag }}
{{ form.image }}
</div>
<hr>
<button type="submit" class="save btn btn-primary">Save</button>
</form>
views.py:
def addgame(request):
if request.method == "POST":
form = InfoForm(request.POST, request.FILES)
if form.is_valid():
infolist = form.save(commit=False)
infolist.created_date = timezone.now()
infolist.save()
return redirect('index')
else:
form = InfoForm()
return render(request, 'ranking/addgame.html', {'form': form})
forms.py:
class InfoForm(forms.ModelForm):
class Meta:
model = GameInfo
fields = ('name', 'image', 'genre')
def clean_name(self):
name = self.cleaned_data['name']
try:
match = GameInfo.objects.get(name=name)
except GameInfo.DoesNotExist:
return name
raise forms.ValidationError('This game has already been added to the list.')
not sure if needed, so I'll post models.py as well:
class GameInfo(models.Model):
GAME_CHOICE = [
("BMU", "Beat 'em up"),
("FT", "Fighting"),
("PF", "Platform"),
("FPS", "Shooter"),
("SV", "Survival"),
("ST", "Stealth"),
("AA", "Action Adventure"),
("EX", "Exploring"),
("SH", "Survival horror"),
("IF", "Interactive fiction"),
("IM", "Interactive movie"),
("VN", "Visual novel"),
("ARP", "Action role-playing"),
("JRP", "Japanese role-playing"),
("TRP", "Tactical role-playing"),
("CAM", "Construction and management"),
("LS", "Life simulation"),
("SP", "Sports"),
("VH", "Vehicle"),
("MOBA", "Multiplayer online battle arena"),
("RTS", "Real-time strategy"),
("RTT", "Real-time tactics"),
("TBS", "Turn-based strategy"),
("TBT", "Turn-based tactics"),
("MMORPG", "MMORPG"),
("MMOFPS", "MMO-FPS"),
("MMOR", "MMO Racing"),
("CG", "Cardgame"),
("PAC", "Point and Click"),
("MG", "Music Game"),
("VR", "Virtual Reality"),
("RC", "Racing"),
]
name = models.CharField(max_length=100)
created_date = models.DateTimeField(default=timezone.now)
image = models.ImageField(upload_to='./media/images/')
genre = models.CharField(
max_length=6,
choices=GAME_CHOICE,
default="BMU",
)
def __str__(self):
return self.name
class Meta:
ordering = ('name',)
If you are rendering the form fields manually, then it's up to you to include the errors, for example:
{{ form.name.errors }}
{{ form.name.label_tag }}
{% render_field form.name class="form-control" %}
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.