Django: FILES Form Not Validating - python

I have a basic Form that accepts a file / image from a template. For some reason it won't validate and I can't see the error.
views.py
# Flag a Job as complete
#login_required()
#user_passes_test(lambda u: u.groups.filter(name='Developer').exists(), login_url='/login/', redirect_field_name='not allowed')
#require_http_methods(['POST'])
def job_complete(request, jobid, userid):
# Get the Job
job = Jobs.objects.get(id=jobid)
jobsubmit = JobSubmitForm(request.FILES)
if jobsubmit.is_valid():
js = jobsubmit.save(commit=False)
js.user_id = userid
js.job_id = jobid
js.save()
job.status = 'IR'
job.save()
return redirect('view_job', jobid=jobid, slug=job.slug)
else:
messages.error(request, "There are form errors!")
return redirect('view_job', jobid=jobid, slug=job.slug)
forms.py
class JobSubmitForm(forms.ModelForm):
class Meta:
model = JobSubmit
fields = ('file', 'image', 'comment', 'gitHubLink')
def save(self, commit=True):
jobsubmit = super(JobSubmitForm, self).save(commit=False)
jobsubmit.user_id = self.cleaned_data['user_id']
jobsubmit.job_id = self.cleaned_data['job_id']
if commit:
jobsubmit.save()
return jobsubmit
view.html
<form method="post" action="/job/job_complete/j{{ job.id }}/u{{ request.user.id }}/" class="form-inline btn-group" enctype="multipart/form-data">
{% csrf_token %}
<div class="span6 inline">
<label class="control-label">Attach Files: </label>{{ job_submit.file }}
<p class="help-block">Attach files that go with this Job.</p>
</div>
<div class="span6 inline">
<label class="control-label">Attach Images: </label>{{ job_submit.image }}
<p class="help-block">Attach images that go with this Job.</p>
</div>
<div class="span6 inline">
<label class="control-label">GitHub URL: </label>{{ job_submit.gitHubLink|add_class:"form-control"|attr:"placeholder:Example: https://www.github.com/path/to/code/repo/or/commit" }}
<p class="help-block">If hosting work on GitHub.</p>
</div>
<div class="span6 inline"><label class="control-label">Job Comments(Required): </label>{{ job_submit.comment|add_class:"form-control"|attr:"placeholder:Example: Fun Job! Please keep me in mind for future work!" }} </div>
<div class="modal-footer">
<button type="submit" class="btn btn-success btn-med pull-left"><i class="fa fa-check-circle"></i> Job Complete</button>
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</form>
models.py
# Store data related to a Job (files, comments, etc.)
class JobSubmit(models.Model):
job = models.ForeignKey(Jobs)
user = models.ForeignKey(User)
file = models.FileField(upload_to="uploads/jobs/files", blank=True, null=True)
image = models.ImageField(upload_to="uploads/jobs/images", blank=True, null=True)
comment = models.TextField()
gitHubLink = models.URLField(blank=True)
Hopefully it's not something silly... it's been a long day and sleepy programming isn't the best idea. :/
Appreciate the help if anyone sees what's wrong. Pointers welcomed, as well. Cheers,

This line:
jobsubmit = JobSubmitForm(request.FILES)
should be as:
jobsubmit = JobSubmitForm(request.POST, request.FILES)
try it?

Related

Changed the model to UNIQUE and form broke

I had a working form and page with following code:
model.py
class TrafficSources(models.Model):
name = models.CharField('name', max_length=250)
token = models.CharField('token', max_length=250)
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('ts_detail', kwargs={'slug': self.name.lower()})
Views.py
#login_required(login_url='/')
def settings(request):
error = ''
if request.method == 'POST':
pk = request.POST.get('id')
new_form = TrafficSourcesForm(request.POST)
print('new_form here:/n', new_form)
if new_form.is_valid():
if pk:
TrafficSources.objects.filter(id=pk).update(**new_form.cleaned_data)
error = f'{error} Saved.'
else:
new_form.save()
error = '1 new object added.'
return redirect(request.path, {'error': error})
else:
error = 'Something went wrong!'
new_form = TrafficSourcesForm()
forms = [TrafficSourcesForm(instance=x) for x in TrafficSources.objects.all()]
return render(request, 'mainpage/dashboard.html', {'new_form': new_form, 'forms': forms, 'error': error})
HTML.html
{% for form in forms %}
<form method="POST" class="table-row">
{% csrf_token %}
<input type="hidden" name="id" value="{{ form.instance.pk }}">
<div class="table-cell">{{ form.name }}</div>
<div class="table-cell">{{ form.token }}</div>
<div class="table-cell"><button class="btn-success w-100 form-control">Save</button></div>
</form>
{{ form.non_field_errors }}
{% endfor %}
<div class="table-row">
<span colspan="3">Add new traffic source:</span>
</div>
<form method="POST" class="table-row">
{% csrf_token %}
<span class="table-cell">{{ new_form.name }}</span>
<span class="table-cell">{{ new_form.token }}</span>
<span class="table-cell"><button class="btn btn-lg btn-success w-100">Add</button></span>
</form>
As I need the 'name' column in my table to create URL for django I made this change in my model class:
class TrafficSources(models.Model):
name = models.CharField('name', max_length=250, unique=True)
token = models.CharField('token', max_length=250)
I've med the migrations and my form stopped working. It shows me no errors (maybe the error code is not working). And it cannot pass the form validation if I change the 'token' column. If I change the 'name' column - all works fine. Any advice?
UPDATE: I found an error. It says: Traffic sources with this Name already exists. But why the new_form.is_valid() says that? Of course it exists, I want to update the token field...

Update and create existing data in Django

I need to update and, if needed, create elements in a Django update view. Basically, I have a form where I am giving the user the chance of updating a row or inserting one or more new rows.
The problem is that I am having issues in updating the "old" rows. If I update an existing row, it creates a new one.
Here I post some code:
views.py
def edit_flight_mission(request, pk):
mission = Mission.objects.get(id=pk)
form = EditMissionForm(request.POST or None, instance=mission)
learning_objectives = LearningObjective.objects.filter(mission_id=mission)
context = {
'mission': mission,
'form': form,
'learning_objectives': learning_objectives,
}
if request.method == 'POST':
learning_obj = request.POST.getlist('learning_obj')
solo_flight = request.POST.get('solo_flight')
if form.is_valid():
mission_obj = form.save()
if solo_flight == 'solo_flight':
mission_obj.solo_flight = True
mission_obj.save()
for lo in learning_obj:
learning_objective, created = LearningObjective.objects.get_or_create(name=lo, mission_id=mission.id)
if not created:
learning_objective.name = lo
learning_objective.save()
return render(request, 'user/edit_flight_mission.html', context)
models.py
class Mission(models.Model):
name = models.CharField(max_length=200)
duration_dual = models.DurationField(blank=True, null=True)
duration_solo = models.DurationField(blank=True, null=True)
training_course = models.ForeignKey(
TrainingCourse, on_delete=models.CASCADE)
note = models.TextField(null=True, blank=True)
solo_flight = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class LearningObjective(models.Model):
name = models.CharField(max_length=300)
mission = models.ForeignKey(Mission, on_delete=models.CASCADE, blank=True, null=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
forms.py
class EditMissionForm(forms.ModelForm):
class Meta:
model = Mission
fields = ('name', 'duration_dual', 'duration_solo', 'training_course')
widgets = {
'name': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Enter Mission Name'}),
'duration_dual': forms.TextInput(attrs={'class':'form-control', 'placeholder': 'Duration as HH:MM:SS'}),
'duration_solo': forms.TextInput(attrs={'class':'form-control', 'placeholder': 'Duration as HH:MM:SS'}),
'training_course': forms.Select(attrs={'class': 'form-control'}),
}
template
{% extends "base.html" %}
{% block head_title %}
Edit Flight Mission {{mission.id}}
{% endblock head_title %}
{% block title %}
Edit Flight Mission {{mission.id}}
{% endblock title%}
{% block content %}
<form action="" method="post">
{% csrf_token %}
<div class="card-body">
<div class="form-group">
{{form.as_p}}
</div>
<div class="form-group">
<div id="inputFormRow">
<label>Learning Objective</label>
{% for lo in learning_objectives %}
<div class="input-group mb-3">
<input type="text" value="{{lo.name}}" class="form-control" name="learning_obj" placeholder="Learning Objective">
<div class="input-group-append">
</div>
</div>
{% endfor %}
<div id="newRow"></div>
<div class="form group">
<div class="form-check">
<input class="form-check-input" type="checkbox" name="solo_flight" value="solo_flight" id="flexCheckDefault">
<label class="form-check-label" for="flexCheckDefault">
Solo Flight
</label>
</div>
</div>
<button id="addRow" type="button" class="btn btn-primary mb-3">Add Learning Objective</button>
</div>
</div>
<div class="card-footer">
<button type="submit" class="btn btn-primary btn-block">
Add New Mission
</button>
</div>
</form>
{% endblock content %}
{% block custom_js %}
<script type="text/javascript">
// add row
$("#addRow").click(function () {
var html = '';
html += '<div id="inputFormRow">';
html += '<div class="input-group mb-3">'
html += '<input type="text" class="form-control" name="learning_obj" placeholder="Learning Objective">'
html += '<div class="input-group-append">'
html += '<button class="btn btn-danger" type="button" id="remove">Remove</button>'
html += '</div></div>'
$('#newRow').append(html);
});
// remove row
$(document).on('click', '#remove', function () {
$(this).closest('#inputFormRow').remove();
});
</script>
{% endblock custom_js %}
The form is updating correctly but the problem is with the part concerning the Learning Objectives basically.
Any suggestion?
The problem is here:
learning_objective, created = LearningObjective.objects.get_or_create(name=lo, mission_id=mission.id)
Specifically, the mission_id=mission.id part. If you want to do a lookup to a ForeignKey, you need two underscores. Therefore, the query is not finding the LearningObjective, thus it is always creating a new one. But it's not even necessary, since you've already filtered learning_objectives by mission (and there, it was done with the correct syntax).
The solution, then is to do this:
learning_objective, created = LearningObjective.objects.get_or_create(name=lo)
if not created:
learning_objective.name = lo
learning_objective.save()
The solution, though can be done much easier with update_or_create. This is the same as what you're doing, but in one line instead of 4.
learning_objective, created = LearningObjective.objects.update_or_create(name=lo, defaults={'name': lo})
Edit
I think the syntax here is actually not correct. Change it as follows:
# Change this,
# learning_objectives = LearningObjective.objects.filter(mission_id=mission)
# To this:
learning_objectives = LearningObjective.objects.filter(mission=mission)
Edit 2
I'm not sure if this problem is what's causing the learning_objectives not to save, but I now see another error in the html. You can not have a form within another form. The {{ form.as_p }} is creating another <form> tag within the one you already have. So the form is validating because all the fields of the {{ form.as_p }} are there, but those are for the Mission object. Are the other fields even being submitted? Check by print(request.POST). I'm guessing that it will not contain the name field for the learning_obj.
Possible Solutions:
Create a form, but not a ModelForm, that has everything you want to save from the two different models.
Render the {{ form }} manually, so that the <form> tags are not there. When you submit, all inputs with names will be submitted.

How to update image fields using Django forms

I am attempting to create a blogging application and in it I have 2 forms, one for editing pre-existing posts, and the other for creating them. However, I am unable to get updated images, when the edit form is submitted. All textual data goes through...
Models.py:
class Post(models.Model):
title = models.CharField(max_length=200, unique=True)
slug = models.SlugField(max_length=200, unique=True)
author = models.ForeignKey(User, on_delete=models.CASCADE, related_name= 'blog_posts')
short_description = models.TextField()
updated_on = models.DateTimeField(auto_now=True)
content = RichTextUploadingField()
created_on = models.DateTimeField(auto_now=True)
status = models.IntegerField(choices=Status, default=0)
cover_image = models.ImageField(upload_to = 'coverimages', null =True, blank = True)
captioned_image = models.ImageField(upload_to = 'captionedimages', null=True, blank = True)
caption = models.CharField(max_length=300)
featured = models.IntegerField(choices=Featured, default=1)
category = models.ForeignKey(PostCategory, on_delete=models.CASCADE, null=True, blank=True)
embedded_code = models.TextField(blank=True, null=True, default='null')
tags = models.ManyToManyField(Tag, blank=True)
class Meta:
ordering = ['-created_on']
def __str__(self):
return self.title
forms.py:
class EditForm(forms.Form):
title = forms.CharField(max_length=100, label='Post Title')
short_description = forms.CharField(widget=forms.Textarea(attrs={"rows":3, "cols":100}))
content = forms.CharField(widget=CKEditorUploadingWidget())
status = forms.NullBooleanField(label='Ready to Publish?')
image = forms.ImageField(label='Select a cover image:', required=False)
captioned_image = forms.ImageField(label='Select a captionable image:', required=False)
caption = forms.CharField(max_length=200)
try:
category = forms.ModelChoiceField(queryset=PostCategory.objects.all())
except:
category = forms.ChoiceField(choices= ('default'))
embed = forms.CharField(widget=forms.Textarea(attrs={"rows":3, "cols":100}))
tags = forms.CharField(widget=forms.Textarea(attrs = {"rows":1, "cols":150}))
editpost.html:
{% load widget_tweaks %}
<form action="" method="POST" enctype="multipart/form-data">
{% csrf_token %} {{ form.media }}
<legend>Edit Post: {{ post }}</legend>
<div class="form-group">
<label class="col-form-label mt-4" for="inputDefault">Title</label>
{% render_field form.title class="form-control" %}
</div>
<div class="form-group">
<label class="form-label mt-4" for="exampleTextarea"
>Short Description</label
>
{% render_field form.short_description class="form-control" %}
</div>
<div class="form-group">
<label class="col-form-label mt-4" for="inputDefault">Content</label>
{{ form.content }}
</div>
<div class="form-group">
<label class="form-label mt-4" for="exampleSelect1"
>Ready To Publish?</label
>
{% render_field form.status class="form-select" id="exampleSelect1"%}
</div>
<div class="form-group">
<label class="form-label mt-4" for="formFile">Cover Image</label>
{% render_field form.image class="form-control" id="formFile"%}
{% if post %}
<br>
<p>Current Image:</p>
<img src="{{ post.cover_image.url }}" alt="" style="height: 400px;">
{% endif %}
</div>
<fieldset>
<div class="form-group">
<label class="form-label mt-4" for="formFile"
>Captioned Image</label
>
{% render_field form.captioned_image class="form-control" %}
{% if post %}
<br>
<p>Current Image:</p>
<img src="{{ post.captioned_image.url }}" alt="" style="height: 400px;">
{% endif %}
</div>
<div class="form-group">
<label class="col-form-label mt-4" for="inputDefault"
>Caption</label
>
{% render_field form.caption class="form-control" %}
</div>
</fieldset>
<div class="form-group">
<label class="col-form-label mt-4" for="inputDefault">Category</label>
{% render_field form.category class="form-select"%}
</div>
<div class="form-group">
<label class="col-form-label mt-4" for="inputDefault">Embed</label>
{% render_field form.embed class="form-control"%}
</div>
<div class="form-group">
<label class="col-form-label mt-4" for="inputDefault">Tags</label>
{% render_field form.tags class="form-control"%}
</div>
<br />
<button type="submit" class="btn btn-primary">Submit</button>
</form>
After the form is submitted, the image is not saved in the media/coverimages folder, and the development server returns:
Not Found: /media/images.jpg
[23/Jan/2022 09:16:24] "GET /media/images.jpg HTTP/1.1" 404 3786
One thing I have noticed is that if I use the admin site, the image uploads properly, which leads me to believe that perhaps issue is with the form, or how the form is being handled
EDIT:
views.py:
# Converts tag string from a form to a nice iterable list
def tagsplitter(input):
input = str(input)
tags = input.split(', ')
return tags
# Fetches all the tags of a QueryObject and returns tags in a nice list
def tagstringer(object):
tags = object.tags.all()
taglist = []
for tag in tags:
taglist.append(tag.tag)
str1 = ", "
return str1.join(taglist)
#staff_member_required(login_url='login')
def edit_post(request, slug):
context = {}
post = Post.objects.get(slug=slug)
context.update({'post': post})
if request.method == "POST":
form = EditForm(request.POST, request.FILES)
if form.is_valid():
image_path = post.cover_image.path
if os.path.exists(image_path):
os.remove(image_path)
title = request.POST.get('title')
short_description = request.POST.get('short_description')
content = request.POST.get('content')
statusraw = request.POST.get('status')
if str(statusraw) == 'true':
status = 1
else:
status = 0
cover_image = request.FILES.get('image')
captioned_image = request.FILES.get('captioned_image')
caption = request.POST.get('caption')
category = request.POST.get('category')
tags = tagsplitter(request.POST.get('tags'))
embed = request.POST.get('embed')
print(f"cover image: {cover_image}")
if cover_image is not None:
if captioned_image is not None:
# Add both images
newpost = Post.objects.filter(pk=post.pk).update(title=title, cover_image = cover_image, captioned_image=captioned_image, short_description=short_description, content=content, status=status, caption=caption, category=category, embedded_code=embed)
else:
print('Adding cover image only')
# Add only cover image
newpost = Post.objects.filter(pk=post.pk).update(title=title, cover_image = cover_image, short_description=short_description, content=content, status=status, caption=caption, category=category, embedded_code=embed)
else:
if captioned_image is not None:
# Add only captioned image
newpost = Post.objects.filter(pk=post.pk).update(title=title, captioned_image=captioned_image, short_description=short_description, content=content, status=status, caption=caption, category=category, embedded_code=embed)
else:
# Add neither
newpost = Post.objects.filter(pk=post.pk).update(title=title, short_description=short_description, content=content, status=status, caption=caption, category=category, embedded_code=embed)
newpost = Post.objects.get(title = title)
newpost.tags.clear()
for tag in tags:
tag = Tag.objects.update_or_create(tag = tag)
newpost.tags.add(tag[0])
return redirect('blogger:post', slug = slug)
else:
tagstr = tagstringer(post)
init_dict = {
'title': post.title,
'content': post.content,
'short_description': post.short_description,
'status': post.status,
'cover_image': post.cover_image,
'caption': post.caption,
'embed': post.embedded_code,
'category':post.category,
'tags': tagstr
}
form = EditForm(initial = init_dict)
context.update({'form': form})
return render(request, template_name="blogger/edit_post.html", context=context)

Django- Form does not save the given argument

I do not why but the line recording.component=component in my views.py does not save the component which is given as an argument and I do not understand the reason. The only think that I have in mind is that I am using smart_select. Here is what I have:
My views.py file:
def create_recording(request, slug, inspection_id, component_id):
inspection = get_object_or_404(Inspection, pk=inspection_id)
plant = get_object_or_404(Plant, slug=slug)
component=get_object_or_404(Component, pk=component_id)
if request.method == "POST":
form = RecordingForm(request.POST)
if form.is_valid():
recording = form.save(commit=False)
recording.user = request.user
recording.plant = plant
recording.inspection=inspection
recording.component=component
recording.save()
return redirect('data:inspection_detail', slug=plant.slug, inspection_id=inspection.id)
else:
form = RecordingForm()
context = {'form': form, 'plant':plant,'inspection':inspection,}
template = 'data/create_recording.html'
return render(request, template, context)
my models.py:
class Recording(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
plant = models.ForeignKey(Plant, on_delete=models.CASCADE)
inspection = models.ForeignKey(Inspection, on_delete=models.CASCADE)
component = models.ForeignKey(Component)
group = ChainedForeignKey(Group, chained_field="component", chained_model_field="component", show_all=False, auto_choose=True, sort=True)
failure = ChainedForeignKey(Failure, chained_field="group", chained_model_field="group", show_all=False, auto_choose=True, sort=True)
def __str__(self):
return str(self.failure)
my forms.py:
class RecordingForm(forms.ModelForm):
class Meta:
model = Recording
fields = ['group', 'failure',]
my html:
<a href="{% url 'data:create_recording' slug=plant.slug inspection_id=inspection.id component_id=1 %}">
<button type="button" class="btn btn-success">
<span class="glyphicon glyphicon-plus"></span> Chair
</button>
</a>
<a href="{% url 'data:create_recording' slug=plant.slug inspection_id=inspection.id component_id=2 %}">
<button type="button" class="btn btn-success">
<span class="glyphicon glyphicon-plus"></span> Table
</button>
</a>
and the html for for my form:
<div class = "col-sm-7">
<div class="panel panel-primary">
<div class="panel-heading">
<h4>Add new recording</h4>
</div>
<div class="panel-body">
<form method='POST'>
{% csrf_token %}
{{ form|crispy }}
<button type = 'submit' class="btn btn-success">Save</button>
</form>
</div>
</div>
</div>
and my url:
url(r'^plants/(?P<slug>[-\w]+)/inspection(?P<inspection_id>[0-9]+)/create_recording/(?P<component_id>[0-9]+)$', views.create_recording, name='create_recording'),
please let me know if I need to add some more information.

Form validation failed in django

I have a simple form
forms.py
class CraveDataForm(forms.ModelForm):
class Meta:
model = crave_data
exclude=['date']
class CraveReplyForm(forms.ModelForm):
class Meta:
model = comments
exclude=['date', 'crave']
model.py
class crave_data(models.Model):
#person = models.ForeignKey(User)
post=models.TextField(blank = True,null = True)
date= models.DateTimeField()
def __unicode__(self):
return self.post
class comments(models.Model):
crave=models.OneToOneField(crave_data)
reply=models.CharField(max_length=1000, blank = True,null = True)
date= models.DateTimeField()
def __unicode__(self):
return self.reply
and views.py
def crave_view(request):
if (request.method=="POST"):
form1=CraveDataForm(request.POST, request.FILES)
if form1.is_valid():
crave_made = form1.save(commit=False)
crave_made.person = request.user
crave_made.save()
messages.success(request, 'You Registered Successfully')
else:
messages.error(request, 'Please enter all required fields')
else:
form1=CraveDataForm()
return render(request, "crave/crave.html", { 'form1' : form1 })
def comment_view(request):
if (request.method=="POST"):
form2 = CraveReplyForm(request.POST, request.FILES)
if form2.is_valid():
reply = form2.save(commit=False)
reply.person=request.user
#reply.crave = request.user
reply.save()
else:
messages.error(request, 'Please enter all required fields')
else:
form2 = CraveReplyForm()
return render(request, "crave/comment.html", { 'form2' : form2 })
my template fie crave.html
<form class="horizontal-form" role="form" action="/crave/" method="post" style="padding: 10px;">
{% csrf_token %}
<div class="form-group" >
<div class="col-sm-10">
{{ form1.post.label_tag }}{{ form1.post }} <br /><br>
</div>
</div>
<input type="submit" class="btn btn-success" value="crave" />
</form>
<form action="/crave/reply_get/">
<input type="submit">
</form>
my comment.html
<form class="horizontal-form" role="form" action="/crave/reply_get/" method="post" style="padding: 10px;">
{% csrf_token %}
<div class="form-group" >
<div class="col-sm-10">
{{ form2.reply.label_tag }} {{ form2.reply }} </br> </br>
</div>
</div>
<input type="submit" class="btn btn-success" value="reply" />
</form>
when i click on crave button i want to save data for form one only without saving data for second form. So comments will be for related posts only. Using foreign key. But i am getting the error here in "reply.crave = crave_made" i want to access the crave made from create_view view.
Help me.
Your forms are derived from UserCreationForm so fields of that form should also be present to make it valid.
But I think you want to inherit from ModelForm and not UserCreationForm.
So change your code as
class CraveDataForm(forms.ModelForm):
class Meta:
model = crave_data
exclude=['date']
class CraveReplyForm(forms.ModelForm):
class Meta:
model = comments
exclude=['date', 'crave']

Categories

Resources