How can I raise Validation Error for a FileField - django

I have a form field like this
class FeedForm(ModelForm):
files=form.FileField(validators=[validate_file_extension])
class Meta:
model=Feed
fields=('text','auth','files',)
with the validator used to allow specific file types:
validator.py
def validate_file_extension(value):
ext = os.path.splitext(value.name)[1] # [0] returns path+filename
valid_extensions = ['.pdf', '.doc', '.docx', '.jpg', '.png', '.xlsx', '.xls']
if not ext.lower() in valid_extensions:
raise ValidationError(u'Unsupported file extension.')
I want to raise the above Validation Error in my template,how can I go about it?
views.py that generate form:
def post_feed(request):
form_class = FeedForm
if request.method == 'POST':
form = form_class(request.POST,request.FILES)
if form.is_valid():
feed = form.save(commit=False)
feed.user = User.objects.get(pk=7)
feed.pub_date=timezone.now()
#instance = Feed(files=request.FILES['files'])
# feed.files=request.FILES['files']
feed.save()
return redirect('home')
else:
form = form_class()
concern='Concern'
feeds=Feed.objects.filter(pub_date__lte=timezone.now()).order_by('-pub_date')
paginator = Paginator(feeds,5) # Show 25 contacts per page
page = request.GET.get('page')
try:
feedz = paginator.page(page)
except PageNotAnInteger:
feedz = paginator.page(1)
except EmptyPage:
feedz = paginator.page(paginator.num_pages)
#return redirect('home')
return render_to_response('index.html', {"feeds":feeds,"feedz": feedz,'form':FeedForm(),'feed_detail':feed_detail,})
views that the form is on using an include tag:
def home(request):
concern='Concern'
feeds=Feed.objects.filter(pub_date__lte=timezone.now()).order_by('-pub_date')
paginator = Paginator(feeds,5) # Show 25 contacts per page
page = request.GET.get('page')
try:
feedz = paginator.page(page)
except PageNotAnInteger:
# If page is not an integer, deliver first page.
feedz = paginator.page(1)
except EmptyPage:
# If page is out of range (e.g. 9999), deliver last page of results.
feedz = paginator.page(paginator.num_pages)
return render_to_response('index.html', {"feeds":feeds,"feedz": feedz,'form':FeedForm(),'feed_detail':feed_detail,},context_instance=RequestContext(request))
html that generates the form:post_feed.html
<form role="form" action="{% url 'post_feed' %}" enctype="multipart/form-data" method="post">
{% csrf_token %}
<div class="mdl-textfield mdl-js-textfield ">
{{form.text}}
<label class="mdl-textfield__label" for="{{form.text.id_for_label}}">Cheated on?Blow the whistle here</label>
</div>
<div class="mdl-select mdl-js-select mdl-select--floating-label">
<label class="mdl-select__label" for="{{form.auth.id_for_label}}">Authority addressed to:<br/></label>
{{form.auth}}
</div><br/>
{{form.files}}
<br/> {{form.files2}}
<br/> {{form.files3}}
<br/><br/> <button class="mdl-button mdl-js-button mdl-js-ripple-effect mdl-button--raised mdl-button--colored">Post</button>
{% if form.errors %}
{% for field in form %}
{% for error in field.errors %}
<div class="alert alert-error">
<strong>{{error|escape}}</strong>
</div>
{% endfor %}
{% endfor %}
{% endif %}
</form>
The html that has the above form on using an include tag
{% include "post_feed.html" %}
<h2>Feed Stream</h2>
{% for feed in feedz %}
<strong> {{feed.full_name_of_poster|title}} </strong> |
{% if feed.resolved == True %}
RESOLVED
{% else %}
UNRESOLVED
{% endif %}
<p> To:{{feed.auth}} </p>
<p>{{feed.text}} </p>
Full details
<p id='count'> {{feed.total_concerns}} concern{{feed.total_concerns|pluralize:'s'}} &nbsp {{feed.no_of_comments}} comment{{feed.no_of_comments|pluralize:'s'}} </p>
<p> {{feed.pub_date|naturaltime|capfirst}} </p>
<hr/>
{% endfor %}
<div class="pagination">
<span class="step-links">
{% if feedz.has_previous %}
previous
{% endif %}
<span class="current">
Page {{ feedz.number }} of {{ feedz.paginator.num_pages }}.
</span>
{% if feedz.has_next %}
next
{% endif %}
</span>
</div>
{% endblock %}
I have gone through the docs but no breakthrough,Kindly help me out.Thanks in advance

The usual format for a function based view that handles a form is:
def post_feed(request):
form_class = FeedForm
if request.method == 'POST':
form = form_class(request.POST,request.FILES)
if form.is_valid():
# process the form then redirect
...
return redirect('home')
else:
# You don't actually need this else statement here
print form.errors
else:
# create blank form for GET requests
form = form_class()
# Now return a response for GET requests and invalid POST requests
concern='Concern'
feeds=Feed.objects.filter(pub_date__lte=timezone.now()).order_by('-pub_date')
return render(request , 'index.html' ,{'feeds':feeds,'form':FeedForm(),'feed_detail':feed_detail,})
So you just need to change the indentation at the end of the view, so that you return a response for invalid POST requests as well.
Django will automatically display any validation errors if you use {{ form }} in your template. If you render the fields individually, then see the docs for rendering fields manually for how to include errors manually.

Related

Django crispy forms - bootstrap4 table_inline_formset template rendering extra row on top

I am using the bootstrap4/table_inline_formset.html template in a FormHelper from django-crispy-forms. The table is rendered correctly in the template, but an extra form always appears at the beginning of the table, which is not visible when submitting the form.
forms.py:
class MetricForm(forms.ModelForm):
class Meta:
model = Metric
exclude = ['auto_value','occurrence']
class MetricFormSetHelper(FormHelper):
def __init__(self, *args, **kwargs):
super(MetricFormSetHelper, self).__init__(*args, **kwargs)
self.add_input(Submit('submit', 'Submit', css_class="btn btn-success"))
self.template = 'bootstrap4/table_inline_formset.html'
views.py:
#login_required
def create_occurrence(request, pk):
try:
site = Site.objects.get(id=pk)
except Site.DoesNotExist:
raise Http404("Site does not exist")
form = OccurrenceForm(request.POST or None, initial={'site':site})
MetricFormset = modelformset_factory(Metric, form=MetricForm, extra=3)
formset = MetricFormset(queryset=Metric.objects.none())
helper = MetricFormSetHelper()
if form.is_valid():
occurrence = form.save(commit=False)
occurrence.added_by = request.user
occurrence.site = site
occurrence.save()
form.save_m2m()
metric_formset = MetricFormset(request.POST)
if metric_formset.is_valid():
for metric_form in metric_formset.forms:
if all([metric_form.is_valid(), metric_form.cleaned_data != {}]):
metric = metric_form.save(commit=False)
metric.occurrence = occurrence
metric.save()
messages.success(request, "Occurrence created successfully.")
execute_from_command_line(["../manage_dev.sh", "updatelayers", "-s", "archaeology"])
return redirect(occurrence.get_absolute_url())
context = {
'form': form,
'site':site,
'formset':formset,
'helper': helper,
}
return render(request, "archaeology/occurrence_form.html", context=context)
template:
...
<form action="" method="post">
{% csrf_token %}
{{ form|crispy }}
<h4>Metrics</h4>
{{ formset.management_form }}
{% crispy formset helper %}
{% if form.instance.pk != None %}
<a class="btn btn-danger" href="{% url 'delete_occurrence' occurrence.id %}">{% trans "Delete" %}</a>
{% endif %}
</form>
...
Any idea how to remove the extra row?
I had to change the template and remove the lines that printed an empty form at the beginning.
table_inline_formset.html:
<tr class="d-none empty-form">
{% for field in formset.empty_form %}
{% include 'bootstrap4/field.html' with tag="td" form_show_labels=False %}
{% endfor %}
</tr>

django - choices from __init__ are not loading in the form

I am using __init__ to build my form choices from parameters passed from the view. It looks like my choices are built correctly when I do print(choices), but the form is not loading any choices. There isn't even a widget for it showing. I do not get any errors. I've used similar code in other views which worked, which is one reason why this one is really confusing me.
I did see that print("ok") never gets printed to the shell, while print("else") does get printed
view
def newobjtoassess(request, assess_pk):
user = request.user
assessment = Assessment.objects.get(pk=assess_pk)
course_pk = assessment.course.pk
context['assessment'] = assessment
form = ObjToAssessmentForm(user=user, course_pk=course_pk)
if request.method == 'POST':
print("ok")
form = ObjToAssessmentForm(request.POST, user=user, course_pk=course_pk)
if form.is_valid():
f = form.cleaned_data
objective = f.get('objective')
assessment.objectives.add(objective)
assessment.save()
return HttpResponseRedirect(reverse('gradebook:assessupdate', args=[assess_pk]))
else:
context['form'] = form
return render(request, "gradebook/newobjtoassess.html", context)
else:
print("else")
form = ObjToAssessmentForm(user=user, course_pk=course_pk)
return render(request, "gradebook/newobjtoassess.html", context)
form
class ObjToAssessmentForm(forms.Form):
objective = forms.ChoiceField(label='Learning Objective', choices=[])
def __init__(self, *args, **kwargs):
user = kwargs.pop('user')
my_course = kwargs.pop('course_pk')
super(ObjToAssessmentForm, self).__init__(*args, **kwargs)
choices=[(o.id, str(o)) for o in Objective.objects.filter(user=user, course=my_course)]
print(choices)
self.fields['objective'] = forms.ChoiceField(choices=choices)
template
{% extends 'base-g.html' %} {% load static %} {% block content %}
{% load crispy_forms_tags %}
<div class="container">
<div class="row">
<div class="col">
<p>Course: {{ assessment.course }}</p>
</div>
</div>
<div class="row">
<div class="col">
<p>{{ assessment.assessment_name }}</p>
</div>
</div>
<div class="row">
<div class="col">
<form method="post">{% csrf_token %}
{{ form|crispy }}
<input type = "submit" value="Update">
</form>
</div>
</div>
</div>
{% endblock content %}
I got mixed up with the indentation on the else. As well, I needed to pass the form to the template in the else.
# the last (2nd of the two) else in the view above
else:
form = ObjToAssessmentForm(user=user, course_pk=course_pk)
context['form'] = form
return render(request, "gradebook/newobjtoassess.html", context)
The view can be cleaned up a bit, but this solves the problem.

Python Django - Pass initial value into bound form

I'm new to Python Django and I'm trying to set up a bound form with three fields where one field (which will be read only) takes an initial value and displays it on the form; the other two fields will be populated by the user when they completes the form. But when I try to submit the form, the form.is_valid returns false, and I'm not sure what I did wrong. Can anyone please help?
Thanks
Here's the code:
views.py
class AddKeyAccompView(TemplateView):
template_name = 'AddKeyAccomp.html'
def get(self, request, Program):
username = request.user.username
form = AddKeyAccompForm(request, Program=Program)
return render(request, self.template_name, {'form': form
,'title':'Add New Key Accomplishment'
,'User': username
})
def post(self, request, Program):
username = request.user.username
form = AddKeyAccompForm(request.POST, Program=Program)
if form.is_valid():
Name = form.cleaned_data['Name']
Description = form.cleaned_data['Description']
form.save()
form = AddKeyAccompForm(request, Program=Program)
return HttpResponseRedirect(reverse('ModInit', args=[Program]))
else:
return HttpResponse('invalid form')
args = {'form': form
,'title':'Add New Key Accomplishment'
,'User': username
,'Name': Name
,'Desc': Description
,'Program': Program
}
return render(request, self.template_name, args)
forms.py
class AddKeyAccompForm(forms.ModelForm):
def __init__(self, request, *args, **kwargs):
self.program = kwargs.pop('Program')
super(AddKeyAccompForm, self).__init__(*args, **kwargs)
self.fields['Program'].initial = self.program
class Meta:
model = Key_Accomplishments
fields = ('Name', 'Description', 'Program',)
widgets = {
'Name': forms.TextInput(attrs={'required':True, 'class':'form-control'})
,'Description': forms.Textarea(attrs={'required': True, 'class':'form-control'})
,'Program': forms.TextInput(attrs={'readonly':'readonly', 'class':'form-control'})
}
html file
{% extends 'base.html' %}
<!DOCTYPE html>
<html>
<head>
{% block head %}
<title>New Key Accomplishment</title>
{% endblock %}
</head>
<body>
{% block body %}
<div class="container">
<ol class="breadcrumb my-4">
<li class="breadcrumb-item active">
<center>{{ title }}</center>
</li>
</ol>
</div>
<br>
<div class="offset-3 col-md-6">
<form method="post">
{% csrf_token %}
<div class="form-group" style="padding-left:10%;">
{% for field in form %}
<label>{{ field.label_tag }}</label>
{{ field }}
<br>
{% endfor %}
</div>
<div class="btn" style="padding-left: 10%;">
<button type="submit">Submit</button>
</div>
</form>
</div>
{% endblock %}
</body>
</html>

Django file now showing in the template

My file is being uploaded in the correct path but I have an issues with it:
Whenever I refresh my HTML page the file gets uploaded again and again. How do I solve this? Also
Please help me with the code or suggest me.
Thanks in advance:)
My views.py
def about_experiment(request, ex_link_name):
researcher = None
study = None
posts = None
exp = get_object_or_404(Experiment,link_name = ex_link_name)
high_scores = ScoreItem.objects.filter(experiment=exp,active=True)
context = {
'request': request,
'exp':exp,
'high_scores': high_scores,
'awards':AwardItem.objects.filter(experiment=exp,visible=True),
}
if exp.about_file:
context['about_file'] = settings.EXPERIMENT_DIRS+exp.about_file.get_include_path()
return render(request, 'about_experiment.html', context)
if request.method == 'POST':
form = AboutHelp(request.POST, request.FILES)
posts = Help.objects.filter().order_by('-date')[0]
documents = Help.objects.all()
if form.is_valid():
obj = form.save(commit = False)
obj.save()
researcher = form.cleaned_data['researcher']
study = form.cleaned_data['study']
document = form.cleaned_data['document']
else:
form = AboutHelp()
posts = Help.objects.filter().order_by('-date')[0]
documents = Help.objects.all()
return render(request, 'about_experiment.html', {'posts': posts})
return render(request, 'about_experiment.html', {'posts': posts})
Source page
<form action="{% url 'lazer.views.about_experiment' exp.link_name %}" method="POST" name="form" enctype="multipart/form-data">
{% csrf_token %}
<label>Researcher Name(s):
<input type="text" name="researcher"><br>
<lable>Study Summary
<textarea rows="10" cols="50" placeholder="Start typing..." maxlength="500" class="form-control" name="study"></textarea>
<br>
<label>Upload your IRB approval letter:
<input type ="file" id="irb-file" class="file_input" name="document"></label>
<br>
<input type = "submit" value="Submit" class="btn btn-primary" />
</form>
destination page
<div class="tab-pane" id="irb">
<h4> List of file(s) uploaded:</h4>
<!--File upload-->
{% if documents %}
<ul>
{% for file in documents %}
<li> {{ file.document.name }} </li>
{% endfor %}
</ul>
{% else %}
<p>No such documents available.</p>
{% endif %}
<!--File upload ends-->
</div>
{% if high_scores %}
{% for hs in high_scores %}
<div class="tab-pane" id="{{ hs.link_name }}">
{% high_score request exp.link_name hs.link_name %}
</div>
{% endfor %}
{% endif %}
As #almost a beginner pointed out, you should be redirecting to some other view, if your form is submitted successfully. If not, (in your case), when the page reloads, the code for POST request is executed again. ie, your form is submitted again. I could suggest some changes in your view,
def about_experiment(request, ex_link_name):
exp = get_object_or_404(Experiment,link_name = ex_link_name)
high_scores = ScoreItem.objects.filter(experiment=exp,active=True)
context = {
'request': request,
'exp':exp,
'high_scores': high_scores,
'awards':AwardItem.objects.filter(experiment=exp,visible=True),
'posts':Help.objects.filter().order_by('-date')[0],
'documents':Help.objects.all()
}
if exp.about_file:
context['about_file'] = settings.EXPERIMENT_DIRS+exp.about_file.get_include_path()
if request.method == 'POST':
form = AboutHelp(request.POST, request.FILES)
if form.is_valid():
obj = form.save(commit = False)
obj.save()
return redirect(reverse('lazer.views.about_experiment', kwargs={ 'ex_link_name':obj.link_name }))
else:
form = AboutHelp()
return render(request, 'about_experiment.html', context)
Here, I merely assumed your obj has a field link_name. You may need to change that according to your models.

Django Paginator Error

I'm been trying to implement django paginator into my whiteboard app so I can split the pictures into different pages.
The problem occurs when I attempt to move across different pages.I limited each page to 1 objects and uploaded few pictures to test if the pagination works between pages but when I try to move across different pages using the pagination method, it doesn't respond.
http://img854.imageshack.us/img854/3303/94627386.jpg
I'm been researching and testing for solutions to this problems through the django pagination docs and I think problem lay at the pagination module method at my template.
My views.py
def Boat(request ,animal_id):
if not request.user.is_authenticated():
return HttpResponseRedirect(reverse('world:LoginRequest'))
picture = Picture.objects.filter(board=animal_id)
paginator = Paginator(picture,1)
page = request.GET.get('page')
try:
picture = paginator.page(page)
except PageNotAnInteger:
picture = paginator.page(1)
picture = paginator.page(paginator.num_pages)
return render(request,'boat.html',{'picture':picture })
My boat.html
{% if picture.object_list %}
<ul>
{% for pet in picture.object_list %}
{% if pet.image %}
<br>
<img src= "{{ pet.image.url }}" </a>
<br>
</a>
</li>
{% endif %}
<br>
View Comment Like<br/>
{% for c in picture %}
{% ifequal c.picture.id pet.id %}
<br>{{ c.body }}</li>
<br>{{ c.created}}</li>
<br>{{ c.user}}</li>
{% endifequal %}
% endfor %}
{% endfor %}
</ul>
{% endif %}
Add Pictures to your board<br/>
{% if number %}
{{number}}
{% endif %}
Return back to Profile<br/>
<br><br><br><br><br>
<div class="pagination">
<span class="step-links">
{% if picture.has_previous %}
previous
{% endif %}
<span class="current">
Page {{ picture.number }} of {{ picture.paginator.num_pages }}.
</span>
{% if picture.has_next %}
next
{% endif %}
</span>
</div>
Parts of my module
class Picture(models.Model):
user = models.ForeignKey(User)
board = models.ForeignKey(Board,blank=False,null=False,related_name='board')
image = models.FileField(upload_to="images/",blank=True)
description = models.TextField()
is_primary = models.BooleanField(default=False)
def __unicode__(self):
return self.description
def Boat(request ,animal_id):
if not request.user.is_authenticated():
return HttpResponseRedirect(reverse('world:LoginRequest'))
picture = Picture.objects.filter(board=animal_id)
paginator = Paginator(picture,1)
try:
page = int(request.GET.get('page', '1'))
except ValueError:
page = 1
try:
picture = paginator.page(page)
except (EmptyPage, InvalidPage):
picture = paginator.page(paginator.num_pages)
picture = paginator.page(paginator.num_pages)
return render(request,'boat.html',{'picture':picture })
#this is view
#this is views files
#login_required(login_url='/login')
# class Base_page_list2(ListView):
def Base_page_list(request,*args, **kwargs):
# tiket = Tiket.objects.all()
# lastest_tiket =Tiket.objects.order_by('-id').all()[:8]
tiket_list = Tiket.objects.all()
paginator = Paginator(tiket_list,2)
page = request.GET.get('page')
page_obj = paginator.get_page(page)
context ={
'tiket':None,
'page_obj':page_obj,
}
context['tiket']=['page_obj']
if request.user.is_superuser:
context['tiket']= Tiket.objects.all()
elif not request.user.is_hrm:
raise Http404('شما نمی توانید به این صحفه دسترسی داشته باشید')
elif request.user.is_mis :
context['tiket']= Tiket.objects.filter(status_tag='s')
elif request.user.is_mali:
context['tiket']=Tiket.objects.filter(status_tag='m')
elif request.user.is_mosh:
context['tiket']=Tiket.objects.filter(status_tag='c')
elif request.user.is_modir:
context['tiket']=Tiket.objects.filter(status_tag='b')
elif request.user.is_kz:
context['tiket']=Tiket.objects.filter(status_tag='k')
elif request.user.is_pa:
context['tiket']=Tiket.objects.filter(status_tag='p')
else:
context['page_obj']['tiket']=Tiket.objects.filter(author=request.user)
return render(request,'hrm_account/base.html',context)
`enter code here`error
File "/home/ali/Desktop/testsharen2/sharen/sharen_hrm/views.py", line 128, in Base_page_list
context['page_obj']['tiket']=Tiket.objects.filter(author=request.user)
TypeError: 'Page' object does not support item assignment