File does not upload from web form in Django - django

Howdy - I've written a very simple app to accept job applications including a resume upload.
Running the bundled server for development locally, I can successfully upload files via the web form on the front end and the admin interface. Running it on the remote server (Apache with mod_python) I can successfully upload files via the admin interface but attempts over the web front end yield no uploaded file.
I've added FILE_UPLOAD_PERMISSIONS = 0644 to settings, checked the two settings files, and looked for similar problems described elsewhere. Figure I'm either forgetting a setting or need to go about this a different way. Any suggestions?
For reference, code included.
The model:
class Application(models.Model):
job = models.ForeignKey('JobOpening')
name = models.CharField(max_length=100)
email = models.EmailField()
date_applied = models.DateField()
cover_letter = models.TextField()
resume = models.FileField(upload_to='job_applications', blank=True)
def __str__(self):
return self.name
def save(self):
if not self.date_applied:
self.date_applied = datetime.today
super(Application, self).save()
The form:
class JobApplicationForm(ModelForm):
class Meta:
model = Application
def save(self, commit=True, fail_silently=False):
super(JobApplicationForm, self).save(commit)
The view:
def job_application(request):
ajax = request.GET.has_key('ajax')
if request.method == 'POST':
form = JobApplicationForm(request.POST, request.FILES)
if form.is_valid():
new_application = form.save()
return HttpResponseRedirect('/about/employment/apply/sent/')
elif request.GET.has_key('job'):
job = request.GET['job']
form = JobApplicationForm({'job': job})
else:
return HttpResponseRedirect('/about/')
t = loader.get_template('employment/job_application.html')
c = Context({
'form': form,
})
return HttpResponse(t.render(c))

You don't show the template. If I had to guess, seeing as the upload works via the admin interface, I'd say you've forgotten to put the enctype in your form tag:
<form enctype="multipart/form-data" method="post" action="/foo/">

First, Have you made sure your template has the enctype="multipart/form-data" flag in it?
<form action="." method="POST" enctype="multipart/form-data">
...
</form>
First, there's no need to override save() in your ModelForm since you're not doing any extra work in it.
Second, there's no need to store the new_application variable, simply call form.save().
Third, you should be using a slug field in your JobOpening model and passing that in the querystring. Remember, this isn't PHP, use pretty urls like /jobs/opening/my-cool-job-opening/, that's what slugs are for; unique human readable urls. Your GET code in your view is very fragile as it stands.
Finally, you may want to use the render_to_response shortcut function as it will save you having to verbosely call template loaders, create context and render them manually.

Related

Upload multiple images at once django

How can I submit 3 images at once with a single input.
class Image(models.Model):
imageuploader_profile = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.CASCADE, null=True, blank=True)
image = models.FileField(upload_to ='pictsagram/')
I do not think this is too complicated. You just need a form with a file input having the multiple attribute and then save all the files in your view.
E.g. a very basic example
#forms.py
class ImageForm(forms.Form):
images = forms.FileField(widget=forms.ClearableFileInput(attrs={'multiple': True}))
Your html form
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{ form }}
<button type="submit">Upload</button>
</form>
And then create your images in your view, using getlist on the field
# views.py
def images_upload(request):
if request.method == 'POST':
form = ImageForm(request.POST, request.FILES)
if form.is_valid():
for img in request.FILES.getlist('images'):
Image.objects.create(imageuploader_profile=request.user, image=img)
return redirect('images_upload')
form = ImageForm()
context = {'form': form}
return render(request, 'images.html', context)
So, I think this is an instance of where you need to make use of the ManyToMany relationship field, creating a new model instance which stores one image, e.g., (and this is a simplistic version of something like what you would need).
from django.db import models
class ImageAttachment(models.Model):
file = models.FileField(upload_to ='pictsagram/')
Then, in your Image model:
class Image(models.Model):
imageuploader_profile = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.CASCADE, null=True, blank=True)
images = models.ManyToManyField(ImageAttachment)
The user will then pass up X number of images to the server, at which point you will create multiple images, and append them to the images field for the Image model.
As code organisation goes, I would also consider renaming you Image model, as it is actually storing multiple images ...

Tinymce not rendering in form

Attempting to use tinyMCE to allow rich input in blog content. I am constrained in that I am inside of Messanine using django 1.11.20. There seems to be many versions of tinyMCE so it is hard to google the right solution.
I used the documentation from Fosstack to install django-tinymce4-lite. Then integrated it into an existing update blog form. The form did not show the change, it still is rendering as a standard CharField. (TextField not supported in this version of django)
in views.py
class TinyMCEWidget(TinyMCE):
` def use_required_attribute(self, *args):
return False
class UpdateForm(forms.ModelForm):
content = forms.CharField(
widget=TinyMCEWidget(
attrs={'required': False, 'cols': 30, 'rows': 10}
)
)
class Meta:
model = BlogPost
fields = ['content']
def UpdateContent(request, slug):
blog_post = BlogPost.objects.get(id=slug)
if request.method == 'POST':
form = UpdateForm(request.POST)
if form.is_valid():
blog_post.content = form.cleaned_data['content']
blog_post.save()
return HttpResponseRedirect('/write/')
else:
form = UpdateForm(instance=blog_post)
return render(request, 'blog_my_update.html', {'form' : form})
in blog_my_update.html
<h1>Update Story</h1>
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
` Update the Story
I expected to see the tinyMCE render the form. But got a normal text box. Anyone know how to fix this? Thanks in advance.
You are sure that the css and javascript files of the library if they are being imported, try using {{form.media}} in the template, this should work if the library uses the django media form, otherwise, manually add the necessary files for the editor (css, javascript) and make sure you have some class or id that the editor usually uses to render the component

Django forms. Save data but do not validate until submission

I am new to Django and have been doing lots of reading so perhaps this is a noob question.
We have applications that involve many forms that users fill out along the way. One user might fill out the budget page and another user might fill out the project description page. Along the way any data they input will be SAVED but NOT validated.
On the review page only data is shown and no input boxes / forms. At the bottom is a submit button. When the user submits the application I then want validation to be performed on all the parts / pages / forms of the application. If there are validation errors then the application can not be submitted.
My model fields are mostly marked as blank=True or null=True depending on the field type. Some fields are required but most I leave blank or null to allow the users to input data along the way.
Any advice on best practices or do not repeat yourself is greatly appreciated.
There is an app in django called form wizard. Using it you can split form submission process for multiple steps.
After a lot of learning, playing and reading I think I have figured a few things and will share them here. I do not know if this is right, however it is progress for me.
So first comes the models. Everything needs to accept blank or null depending on the field type. This will allow the end user to input data as they get it:
class exampleModel(models.Model):
field_1 = models.CharField(blank=True, max_length=25)
field_2 = models.CharField(blank=True, max_length=50)
.........
Then we create our model form:
from your.models import exampleModel
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, Row, Column
class exampleForm(ModelForm):
class Meta:
model = exampleModel
fields = ('field_1','field_2')
def __init__(self, *args, **kwargs):
# DID WE GET A VALIDATE ARGUMENT?
self.validate = kwargs.pop('validate', False)
super(ExampleForm, self).__init__(*args, **kwargs)
# SEE IF WE HAVE TO VALIDATE
for field in self.fields:
if self.validate:
self.fields[field].required = True
else:
self.fields[field].required = False
self.helper = FormHelper()
self.helper.form_tag = False
self.helper.layout = Layout(
Row(
Column('field_1', css_class='col-lg-4 col-md-4'),
Column('field_2', css_class='col-lg-4 col-md-4')
)
)
def clean(self):
cleaned_data = super(ExampleForm, self).clean()
field_1 = cleaned_data.get('field1')
field_2 = cleaned_data.get('field2')
if self.validate and field_2 != field_2:
self.add_error('field_1', 'Field 1 does not match field2')
return cleaned_data
Here is the important part. I've learned a lot about forms and binding. As I mentioned I needed users to be able to fill out forms and not validate the data till the very end. This is my solution which helped me. I could not find a way to bind a form to the model data, so I created a function in my lib called bind_queryset_to_form which looks like this:
def bind_queryset_to_form(qs, form):
form_data = {}
my_form = form()
for field in my_form.fields:
form_data[field] = getattr(qs, field, None)
my_form = form(data=form_data, validate=True)
return my_form
The view:
from your.models import exampleModel
from your.form import exampleForm
from your.lib.bind_queryset_to_form import bind_queryset_to_form
from django.shortcuts import render, get_object_or_404
def your_view(request, pk):
query_set = get_object_or_404(exampleModel, id=pk)
context = dict()
context['query_set'] = query_set
# SAVE THE FORM (POST)
if request.method == 'POST':
form = exampleForm(request.POST, instance=query_set)
form.save()
context['form'] = form
# GET THE DATA.
if request.method == 'GET':
if request.session.get('validate_data'):
# BIND AND VALIDATE
context['form'] = bind_queryset_to_form(query_set, exampleForm)
else:
# NO BIND, NO VALIDATE
context['form'] = exampleForm(instance=query_set)
return render(request, 'dir/your.html', context)
The template:
{% load crispy_forms_tags %}
<div id="div_some_tab">
<form id="form_some_tab" action="{% url 'xx:xx' query_set.id %}" method="post">
{% crispy form form.helper %}
</form>
</div>
What does all the above allow?
I have many views with many data inputs. The user can visit each view and add data as they have it. On the review page I set the flag / session "validate_data". This causes the app to start validating all the fields. Any errors will all be displayed on the review page. When the user goes to correct the errors for the given view the bind_queryset_to_form(query_set, exampleForm) is called binding the form with data from the queryset and highlighting any errors.
I cut out a lot of the exceptions and permission to keep this as transparent as possible (the goat would hate that). Hope this idea might help someone else or someone else might improve upon it.

Making Django forms return forms.instance in templates

I have complex user-defined permissions for my users. But to make thinks simpler, let's imagine there's only read-only or write permissions for each user.
I am using Django forms to edit and save model objects. And my goal is to render <input> in the Django HTML template for those users who have the permission to edit a given model instance, and a hard-coded data (without <input> tag) if the user has only read-only permission.
Currently, I have the following code in my Django template to achieve this:
{%if user.has_permission_to_edit %}
{{my_form.my_field}}
{% else %}
{{my_form.instance.my_field}}
{% endif %}
And here's my_form:
class MyForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(MyForm, self).__init__(*args, **kwargs)
for field_name, field in self.fields.items():
field.widget.attrs['class'] = 'form-control input-sm'
if field.required == True:
field.widget.attrs['required'] = ''
class Meta:
model = MyModel
fields = ('my_field',)
The problem with the code in the template is that I have to use multiple {% if %}{% else %} blocks. I am relatively new to Django, and I know that there is plethora of advanced tools making Django code potentially super DRY, so I want to asked you guys, what is the most DRY method to organize what I described in the template. Specifically, is there any way to make Django forms return instance values based on some condition specified inside the form definition? Or do I have to some used-defined tag ? Or maybe some totally different architecture is used to achieve such goals?
For what I understood form your question, you want to pass the instance of the data fetched from your data-source.
from .forms import MyForm
from django.shortcuts import render
assuming you have created a forms.py file at the views.py level.
Fetching data from data-source(Detail is the model in below example)
detail_instance = Detail.objects.get(user=request.user.id)
reg_form = MyForm(instance=detail_instance or None)
# In case of edit scenario you can pass in the post params to the form as well
reg_form = MyForm(request.POST, instance=detail_instance)
# Or form with uploads
reg_form = MyForm(request.POST, request.FILES, instance=detail_instance)
Now once we have data inside our reg_form parameter we can pass it in the template
return render(request, 'applicant/register.html', { 'my_form' : reg_form})
Do whatever you wish, with you my_form variable in the template.
BASED ON THE UPDATED QUESTION
You can pass parameter to the init function of a form
reg_form = MyForm(exist = exist, some_param = param_value, instance=detail_instance or None)
After passing the param, the param can be fetched and processed in the init function of the form
class MyForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
exist = kwargs.pop('exist', None)
pk_reg = kwargs.pop('param', None)
super(MyForm, self).__init__(*args, **kwargs)
#do some stuff with you custom params here
if exist == True or pk_reg:
self.fields['username'].widget.attrs['readonly'] = True
The above approach has an alternative as well for having separate forms for separate permission and calling the appropriate form based on the user permissions.

Hidden validation form - Django

I'm having really hard time trying to make this code work. I'm using Python 2.7 and Django 1.3
When I try to submit the form, it leads me to the error page, like the form has something wrong.
I have a model class with an image field:
class Livro (models.Model):
Titulo = models.CharField(max_length=200)
Autor = models.CharField(max_length=200)
Genero = models.CharField(max_length=100)
Editora = models.CharField(max_length=200)
Capa = models.ImageField(upload_to='media', blank=True, null=True)
ISBN = models.CharField(max_length=200)
Serie = models.CharField(max_length=200)
Data = models.DateField()
Tipocapa = models.CharField(max_length=100)
Lingua = models.ForeignKey(PropObra,'Lingua', related_name="lingualivro")
def __unicode__(self):
return self.Titulo
This is the view I have implemented:
def salvalivro(request):
if request.method == 'POST':
form = LivroForm(request.POST, request.FILES)
if form.is_valid():
form = LivroForm()
if not form.is_valid():
return HttpResponseRedirect('/erro/')
return render_to_response('salvalivro.html', {'form': form,}, context_instance=RequestContext(request))
And this is the code I have inside the template:
<form enctype="multipart/form-data" method="POST" action="/salvalivro/" >{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Salvar" />
</form>
Maybe the error is in front of my nose, but I've been working on this for about three days and had no result. I've read Django's documentation and many other questions around StackOverflow, but still got nothing. I really need some help...
Your view code doesn't make a whole lot of sense. You're creating a new instance of the form after checking that the previously created one is valid, then redirecting to an error page if it's not. So, your code looks to me like it's working as expected as described in your question.
Try this view instead (assumes Django 1.3):
def salvalivro(request):
form = LivroForm(request.POST or None, request.FILES or None)
if request.method == 'POST':
if form.is_valid():
form.save() #or whatever else you need
return render(request, 'salvalivro.html', {'form': form})
Your view is very odd. If it's a post, you instantiate the form using the post data. Then, you check it's valid: then you re-instantiate the form with no data and check if it isn't valid! Of course, at that point it can't ever be valid, because the second instantiation has no data. So, naturally, it always redirects - but again, because you're redirecting to a different view, you'll never see the actual error messages generated by the form.
You should look more closely at the standard documentation on using a form in a view - it has the exact pattern you should follow.