I am making a custom CMS platform in Django. I want to upload a featured image from user.
Here is my forms.py
class CkEditorForm(ModelForm):
..........
..........
featuredImage = forms.ImageField(required=True)
My models.py
class Post(models.Model):
..........
..........
featuredImage = models.ImageField(upload_to="featured_image/")
My HTML Template
<div class="col-sm-6">
{{myForm.featuredImage}}
</div>
I used one more method in template but it didn't work for me-
<input type="file" name="featuredImage" accept="image/*" required id="id_featuredImage">
Note- Image is successfully uploaded via Django admin panel, But not working when I try to upload via Templates (HTML file)
Also, it was working when I use this method to render my form in html
{{myForm.as_p}}
But I want to render each form's input method as differently.
{{myForm.category}}
{{myForm.tags}}
{{myForm.featuredImage}}
Here is the views.py
def postView(request):
if request.method== "GET":
form = CkEditorForm()
return render(request,"post/post.html",{'myForm':CkEditorForm})
else:
if request.method == 'POST':
form = CkEditorForm(request.POST)
if form.is_valid():
form.save()
return render(request,"post/post.html",{'myForm':CkEditorForm})
else:
messages.error(request, "Error")
return render(request,"post/post.html",{'myForm':CkEditorForm})
I changed my Views.py and it worked for me...
def postView(request):
if request.method== "GET":
form = CkEditorForm()
return render(request,"post/post.html",{'myForm':CkEditorForm})
else:
if request.method == 'POST':
form = CkEditorForm(request.POST,request.FILES)
if form.is_valid():
form.save()
return render(request,"post/post.html",{'myForm':CkEditorForm})
else:
messages.error(request, "Error")
return render(request,"post/post.html",{'myForm':CkEditorForm})
I just change this. Add request.FILES to get image data.
form = CkEditorForm(request.POST,request.FILES)
Related
I am trying to save a file and some other details in django using forms.
And I only want it to save a CharField and a FileField but not the country field.
For country field I want it to take its value through a post request.
But the form isn't saving. The errors says "data didn't validate".
Also this method works fine if I don't use a FileField.
models.py
class Simple(models.Model):
name = models.CharField(max_length=100)
city = models.FileField(upload_to='marksheet')
country = models.CharField(max_length=100)
forms.py
class SimpForm(forms.ModelForm):
class Meta:
model = Simple
fields = ['name','city']
A snippet from upload.html
<form action="upload" method="POST" enctype="multipart/form-data">
{% csrf_token %}
<label>Test input</label>
<input type="text" name="country">
{{form.name}}
{{form.city}}
<button type="submit">Submit</button>
</form>
views.py
def upload(request):
if request.method == 'POST':
a = request.POST.get('country')
form = SimpForm(request.POST,request.FILES)
if form.is_valid():
post = form.save(commit=False)
post.country = a
post.save()
return HttpResponse('saved')
else:
return HttpResponse('ERROR SAVING')
else:
form = SimpForm()
return render(request,'upload.html',{'form':form})
You are not passing request.FILES in your form. You should pass it like this:
form = SimpForm(request.POST, request.FILES)
More information on file uploads can be found in documentation.
i want to manage(move and rename)files that user upload :
my upload form(html):
<form action="../valid_upload/" method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{form.as_p}}
<input type="submit" name="send" value="send" />
</form>
my form(django part):
class UploadImageForm(forms.Form):
image = forms.FileField()
name = forms.CharField(max_length=100)
about = forms.CharField(widget=forms.Textarea)
taq1 = forms.CharField(max_length=100)
taq2 = forms.CharField(max_length=100)
taq3 = forms.CharField(max_length=100)
url.py(just a one line):
url(r'valid_upload/', views.valid_upload, name='valid_upload'),
and view.py(just a part of that):
if 'username' in request.session:
if request.method == 'POST':
if 'image' in request.FILES:
form = UploadImageForm(request.POST, request.FILES)
if form.is_valid():
# Here goes the documentation code
return HttpResponse(request.FILES['image'].content_type)
//here i want to rename and move uploaded files
else:
return redirect('/upload_image')
else:
return redirect('/login/')
i want to know how to rename uploaded file and move them on my directories.if you can help me :)
You can pass the request data to your form, and let the form manage your needs. Here is an example:
if 'username' in request.session:
if request.method == 'POST':
if 'image' in request.FILES:
form = UploadImageForm(request.POST, request.FILES)
if form.is_valid():
# Here goes the documentation code
return HttpResponse(request.FILES['image'].content_type)
//here i want to rename and move uploaded files
else:
return redirect('/upload_image')
else:
return redirect('/login/')
You can use a django model too.
Here is the documentation:
https://docs.djangoproject.com/en/1.11/topics/http/file-uploads/
# models.py
class Profile(models.Model):
name = models.CharField(max_length=255)
image = models.ImageField(upload_to=image_path, blank=True, null=True)
# forms.py
class ProfileForm(ModelForm):
class Meta:
model = Profile
fields = '__all__'
# views.py
def profile(request, id):
p = get_object_or_404(Profile, pk=id)
profile_form = ProfileForm(request.POST or None,
files=request.FILES or None,
instance=p)
if request.method == 'POST':
if profile_form.is_valid():
profile_form.save()
return render(request, 'profile.html', {'form': profile_form})
#profile.html
<form method="post" action="" enctype="multipart/form-data" >
{% csrf_token %}
{{ form }}
<input type="submit" value="Submit" />
</form>
If a user GETs /profile/1 and 1 exists, they get the form prefilled with all the values, including the image (if any)
If the user then POSTs updates to any of the fields except the image (clearing or changing), The page renders correctly after the update.
However, if the user changes the Image (clear or change), the change is not reflected in the rendered result: The image is always shown as empty. a quick GET solves the situation and displays the changed situation.
Does anyone know why the image field doesn't show the update in this situation?
Don't you have to do some sort of redirection to somewhere(obviously with a GET) when the profile form is successfully saved? You were always returning render.... and if you are having a POST request the form is going to stay with the POST data. So it should be:
# views.py
def profile(request, id):
p = get_object_or_404(Profile, pk=id)
profile_form = ProfileForm(request.POST or None, files=request.FILES or None, instance=q)
if request.method == 'POST':
if profile_form.is_valid():
profile_form.save()
# do the GET request to some page
return redirect('some-view-name', foo='bar')
return render(request, 'profile.html', {'form': profile_form})
Looking to upload 2 files into a Django Form using HTML5 (since it supports multi-file upload). The problem I'm facing is it's targets the 1st one for uploading. It knows there are 2 files, because when it saves, it saves twice (as per the for loop below). I thought to use the dictionary to loop over the names, but I receive an error that says this keyword can't be an expression. Maybe this is something simple, but if you need more, I can provide. Just a note, I did not use the forms.py for the file upload, but instead just the regular HTML <input tag. Thanks.
#page.html
<form action="" method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form_a.as_p }}
<input type="file" name="img" multiple>
<input type="submit" value="Submit" />
</form>
#models.py
def contact(request):
if request.method == 'POST':
form_a = RequestForm(request.POST, request.FILES)
if form_a.is_valid():
#assign form data to variables
saved_first_name = form_a.cleaned_data['First_Name']
saved_last_name = form_a.cleaned_data['Last_Name']
saved_department = form_a.cleaned_data['Department']
saved_attachments = request.FILES.getlist('img')
#create a dictionary representing the two Attachment Fields
tel = {'keyword1': 'Attachment_2', 'keyword1': 'Attachment_1'}
for a_file in saved_attachments:
#for every attachment that was uploaded, add each one to an Attachment Field
instance = Model(
Attachment_1=a_file,
Attachment_2=a_file
)
instance.save()
all_together_now = Model(First_Name=saved_first_name, Last_Name=saved_last_name,
Department=saved_department, Attachment_1=???, Attachment_2=???)
#save the entire form
all_together_now.save()
else:
#just return an empty form
form_a = RequestForm()
return render(request, 'vendor_db/contact.html', {'form_a': form_a})
Here is a way that worked for me. I loop each occurrence of an InMemoryUploadedFile in request.FILES and re-assign it back onto request.FILES, then save each one by one.
forms.py
class PhotosForm(forms.ModelForm):
file = forms.FileField(widget=forms.ClearableFileInput(attrs={'multiple': True}))
class Meta:
model = Photos
fields = ['file']
views.py
def photos(request):
photos = Photos.objects.all()
if request.method == 'GET':
form = PhotosForm(None)
elif request.method == 'POST':
for _file in request.FILES.getlist('file'):
request.FILES['file'] = _file
form = PhotosForm(request.POST, request.FILES)
if form.is_valid():
_new = form.save(commit=False)
_new.save()
form.save_m2m()
context = {'form': form, 'photos': photos}
return render(request, 'app/photos.html', context)
The view that **renders** is
def codequestion(request, question_id):
question = Question.objects.get(pk=question_id)
return render(request, 'polls/codequestion.html', {'question': question})
the view that is called on submission is
def codequestion_evaluate(request, question_id):
form = CodeForm()
print request.method
if request.method == 'POST':
form = CodeForm(request.POST)
if form.is_valid():
data = form.cleaned_data
return HttpResponse("Your code is %s" % data['solution'])
else:
return HttpResponse("not valid")
else:
return HttpResponse("Error")
class
from django import forms
class CodeForm(forms.Form):
solution = forms.CharField(widget=forms.Textarea)
template
<form action="{% url 'codequestion_evaluate' question.id %}" method="post">
{% csrf_token %}
{{form.as_p}}
<input type="submit" value="Submit" />
</form>
I do not get the form field display in the HTML page, I can only see the submit button.
The view that is suppose to show the unfilled form doesn't create the form object at all. It should create a form object and pass it to the template, like this:
def codequestion(request, question_id):
question = Question.objects.get(pk=question_id)
form = CodeForm()
return render(request, 'polls/codequestion.html', {'question': question, 'form': form})
But better yet you should follow the pattern described in Django documentation. To do this you should:
Delete the codequestion. All actions (displaying the unfilled form, displaying a submitted form with errors, processing a correctly submitted form) will be handled by a single view.
Configure your url routing so codequestion_evaluate view handles the page showing the unfilled form.
Change codequestion_evaluate so it follows the pattern:
def codequestion_evaluate(request, question_id):
if request.method == 'POST':
form = CodeForm(request.POST)
if form.is_valid():
# The form has been submitted and is valid
# process the data and redirect to a "thank you" page
data = form.cleaned_data
return HttpResponseRedirect('/thanks/')
else:
# just display an empty form
form = CodeForm()
# you can optionally add 'question' if you need it in your template
question = Question.objects.get(pk=question_id)
return render(request, 'polls/codequestion.html', {'form': form, 'question': question})
form refers to a variable in your context data, since you haven't included it in the context data, it can't find it so there isn't anything to render, you need to include it.
def codequestion(request, question_id):
question = Question.objects.get(pk=question_id)
return render(request, 'polls/codequestion.html',
{'question': question, 'form': CodeForm()})
Try changing
class CodeForm(forms.Form):
to
class CodeForm(forms.ModelForm):
I faced same problem but it got resolved from this.
The recent distributions of django don't have widgets included. So:
pip install django-widgets
should do the trick.