upload multiple files in django - django

I am new to django, I am trying to upload more than one file from the browser and store them somewhere in computer storage but I am not storing them successfully with this code please help me out to find my mistake or improvements that I can do. Thanks in advance to help.
views.py
from django.shortcuts import render
from django.http import HttpResponse
# Create your views here.
def Form(request):
return render(request, "index/form.html", {})
def Upload(request):
for count, x in enumerate(request.FILES.getlist("files")):
def process(f):
with open('/Users/benq/djangogirls/upload/media/file_' + str(count), 'wb+') as destination:
for chunk in f.chunks():
destination.write(chunk)
process(x)
return HttpResponse("File(s) uploaded!")
app/urls.py
from django.conf.urls import url
from index import views
urlpatterns = [
url(r'^form/$', views.Form),
url(r'^upload/$', views.Upload)
]
form.html
<form method="post" action="../upload/" entype="multipart/form-data"> {% csrf_token %}
<input type="file" name="files" multiple />
<input type="submit" value="Upload" />

my model to save Document
class Document(models.Model):
file = models.FileField('Document', upload_to='mydocs/')
#property
def filename(self):
name = self.file.name.split("/")[1].replace('_',' ').replace('-',' ')
return name
def get_absolute_url(self):
return reverse('myapp:document-detail', kwargs={'pk': self.pk})
you can try a django create view in my code i use this DocumentCreateView
class DocumentCreate(CreateView):
model = Document
fields = ['file']
def form_valid(self, form):
obj = form.save(commit=False)
if self.request.FILES:
for f in self.request.FILES.getlist('file'):
obj = self.model.objects.create(file=f)
return super(DocumentCreate, self).form_valid(form)
my form html file
<script>
$(document).ready(function(){
$('#id_file').attr("multiple","true");
})
</script>
<form method="post" enctype="multipart/form-data" action="">{% csrf_token %}
{{ form.file }}
<input type="submit" value="upload" />
</form>

Answer from official django documentation
file_field = forms.FileField(widget=forms.ClearableFileInput(attrs={'multiple': True}))
https://docs.djangoproject.com/en/3.0/topics/http/file-uploads/#uploading-multiple-files

views.py
from django.shortcuts import render
from django.http import HttpResponse
# Create your views here.
def Form(request):
for x in request.FILES.getlist("files"):
def process(f):
with open('/Users/benq/djangogirls/upload/media/file_' + str(x), 'wb+') as destination:
for chunk in f.chunks():
destination.write(chunk)
process(x)
return render(request, "index/form.html", {})
urls.py
from django.conf.urls import url
from index import views
urlpatterns = [
url('form', views.Form),
]
worked for me.

Just an update from Django 3.2 and above. According to docs you have to:
If you want to upload multiple files using one form field, set the multiple HTML attribute of field’s widget:
from django import forms
class FileFieldForm(forms.Form):
file_field = forms.FileField(widget=forms.ClearableFileInput(attrs={'multiple': True}))
Then override the post method of your FormView subclass to handle multiple file uploads:
from django.views.generic.edit import FormView
from .forms import FileFieldForm
class FileFieldView(FormView):
form_class = FileFieldForm
template_name = 'upload.html' # Replace with your template.
success_url = '...' # Replace with your URL or reverse().
def post(self, request, *args, **kwargs):
form_class = self.get_form_class()
form = self.get_form(form_class)
files = request.FILES.getlist('file_field')
if form.is_valid():
for f in files:
... # Do something with each file.
return self.form_valid(form)
else:
return self.form_invalid(form)

I was able to solve the multi uploads portion in the create view here: Django Class based UpdateView with Form for Multiple Uploaded Files , however, now the update get function is what I am currently stuck on.

Related

Reverse for 'entrypage' with no arguments not found. 1 pattern(s) tried: ['wiki/(?P<title>[^/]+)$']

VIEWS.PY
from django.shortcuts import render
from django.shortcuts import redirect
from django.urls import reverse
from django.http import HttpResponseRedirect
from django import forms
import markdown2
from . import util
class AddPageForm(forms.Form):
title = forms.CharField(max_length=20)
content = forms.CharField(widget=forms.Textarea(
attrs={
"class": "form-control",
"placeholder": "Tell us more!"
})
)
def add_page(request):
if request.method == "POST":
form = AddPageForm(request.POST)
entries = util.list_entries()
if form.is_valid():
title = form.cleaned_data['title']
content = form.cleaned_data['content']
util.save_entry(title, content)
for entry in entries:
if title.upper() == entry.upper():
return render(request, "encyclopedia/errorpage.html")
else:
return HttpResponseRedirect(reverse('encyclopedia:entrypage'))
else:
return render(request, "encyclopedia/addpage.html", {
"form": AddPageForm()
})
URLS.PY
app_name = "encyclopedia"
urlpatterns = [
path("", views.index, name="index"),
path("wiki/<str:title>", views.entry_page, name="entrypage"),
path("search", views.search, name="search"),
path("add_page", views.add_page, name="addpage"),
]
ADDPAGE.HTML
<form action="{% url 'encyclopedia:addpage' %}" method="post">
{% csrf_token %}
{{ form }}
<input type="submit" value="Submit" class="btn btn-secondary">
</form>
LAYOUT.HTML
<div>
Create New Page
</div>
<div>
I have tried updating the urls and the views to this but i keep getting error responses
path("add_page/<str:title>", views.add_page, name="addpage"),
def add_page(request, title):
Please advise where this error response could be coming from as the above edits is what i saw in some other stackoverflow responses to clear the error but this didn't work for me.
Thank you
When you make a redirect to entrypage, you need to specify the title, so:
from django.shortcuts import redirect
def add_page(request):
if request.method == "POST":
form = AddPageForm(request.POST)
entries = util.list_entries()
if form.is_valid():
title = form.cleaned_data['title']
content = form.cleaned_data['content']
util.save_entry(title, content)
for entry in entries:
if title.upper() == entry.upper():
return render(request, "encyclopedia/errorpage.html")
# specify title &downarrow;
return redirect('encyclopedia:entrypage', title=title)
# …
I would also strongly advise to make use of a database, and not fetch all entries from the utility: a database is optimized to search effective, whereas accessing the list of files takes linear time to search. If you define a database model, you can add db_index=True [Django-doc] to build an index which can boost searching enormously.

how do i get the specific profile of user that created a post in django

i ve been stuck for days now trying to find a way to solve this, i am trying to return the specific profile of user that created a post in django but when i try it i get a VectorDetails() missing 1 required positional argument: 'pk'. Let me show my views.py and urls.py
Views.py (views for showing the posts and returning specific users )
def VectorDetails(request, pk, vectors_slug):
vector = get_object_or_404(Vectors, slug=vectors_slug)
vectors = Vectors.objects.filter(status='published').order_by('?')[:6]
creators = Profile.objects.filter(creator=True)
creator = Profile.get_object_or_404(pk=pk)
context = {
'vector': vector,
'vectors': vectors,
'creators':creators
}
return render(request, 'vector-details.html', context)
views.py (view for returning the specific user)
from django.shortcuts import render, get_object_or_404
from userauths.models import Profile
def creator_profile_detail(request, pk):
creators = get_object_or_404(Profile, pk=pk)
context = {
'creators': creators
}
return render(request, 'creator_profile_detail.html', context)
urls.py
from django.urls import path
from . import views
app_name = 'creators'
urlpatterns = [
path('<int:pk>', views.creator_profile_detail, name="creator_profile_detail"),
]
template.html
<div class="premium_uyhau mt-4">
<div class="urip_widget_avater">
<img src="{{vector.creator.profile.image.url}}" class="img-fluid circle" alt="">
<div class="veryfied_author"><img src="assets/img/verified.svg" class="img-fluid" width="15" alt=""></div>
</div>
<div class="widget_avater_124">
<h4 class="avater_name_214">{{vector.creator|title}}</h4>
<span>{{vector.creator.profile.bio|title}}</span>
</div>
</div>
This was how i fixed the bug
def profile(request, username):
if request.user.is_authenticated:
user = get_object_or_404(User, username=username)
profile = Profile.objects.get(user=user)
...
Then in main project urls.py add
path('u/<username>/', profile, name="profile"),

How to redirect an UpdateView upon success?

I created a small Django application to manage data that fits a simple a model. For now I only need two views: one to list all records and another to edit a record with a generic form. Everything functions as expected, except the redirection from the edit view upon a successful update. In urls.py are the following contents:
from django.urls import path
from . import views
app_name = 'reqs'
urlpatterns = [
path('', views.IndexView.as_view(), name='index'),
path('<int:pk>/', views.ReqUpdateView.as_view(), name='update'),
]
In forms.py:
from django.forms import ModelForm
from .models import Requirement
class RequirementForm(ModelForm):
class Meta:
model = Requirement
fields = ['name', 'priority', 'source' , 'rationale']
And the templeate requirement_form.html:
<h1>{{ requirement.id }} - {{ requirement.name }}</h1>
<form method="post" novalidate>
{% csrf_token %}
<table>
{{ form.as_table }}
<tr><td></td><td><button type="submit">Save</button></td></tr>
</table>
</form>
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
<br><br>
Back to list
Finally views.py, on a first attempt to redirect the update to the list:
from django.views.generic import ListView, UpdateView
from django.urls import reverse_lazy
from .models import Requirement
from .forms import RequirementForm
class IndexView(ListView):
template_name = 'reqs/index.html'
context_object_name = 'requirements_list'
def get_queryset(self):
return Requirement.objects.order_by('subject')
class ReqUpdateView(UpdateView):
model = Requirement
form_class = RequirementForm
success_url = reverse_lazy('/')
With this formulation the Save button produces this error:
Reverse for '/' not found. '/' is not a valid view function or pattern name.
I also tried an empty string as argument to reverse_lazy, as well as the path name index, but a similar error message is produced.
On a second attempt I tried to redirect to the same page, redefining the get_success_url method to do nothing:
class ReqUpdateView(UpdateView):
model = Requirement
form_class = RequirementForm
context_object_name = 'requirement_update'
def get_success_url(self):
pass #return the appropriate success url
This returns a 404 error trying to redirect the browser to /reqs/1/None.
A third attempt to redirect to the form with the same record:
class ReqUpdateView(UpdateView):
model = Requirement
form_class = RequirementForm
context_object_name = 'requirement_update'
def get_success_url(self):
pk = self.kwargs["pk"]
return reverse("update", kwargs={"pk": pk})
Which complains about not finding the view:
Reverse for 'update' not found. 'update' is not a valid view function or pattern name.
How can I redirect success to a valid URL? It can either be the items list or the item update view, as long as it works.
There are few misconception that you did
reverse parameter should be as documented
URL pattern name or the callable view object
You have set namespace but you are not reversing with namespace as documented
So in your case
def get_success_url(self):
pk = self.kwargs["pk"]
return reverse("reqs:update", kwargs={"pk": pk})
reverse / reverse_lazy are used to get the url using view name or pattern name. If you want to use a url directly just write:
success_url = '/'
For the case of return reverse("update", kwargs={"pk": pk}) not working since you set app_name = 'reqs' you should be using return reverse("reqs:update", kwargs={"pk": pk}) instead.

Form Field not displaying in Template

I'm new to Django and am having a bit of trouble with forms. I'm trying to display a single text input so that users can enter their phone number and it will be sent to my email. I'm actually going to have it stored in a postgre database but want to get the basics down first. The submit button is being displayed but the text input field isn't. I tried putting the forms.py inside of the views.py to see if the PhoneForm() function and file wasn't importing but that didn't do anything.
views.py
from django.shortcuts import render, redirect
from django.http import HttpResponse, HttpResponseRedirect
from django.core.mail import send_mail
from .forms import PhoneForm
# Create your views here.
def index(request):
# Render the index.html template with a context dictionary
return render(request, "index.html")
def get_number(request):
# if this is a POST request we need to process the form data
if request.method == 'POST':
#create a form instance
form = PhoneForm(request.POST)
if form.is_valid():
cd = form.cleaned_data
send_mail(
cd['phone_form'],
['siteadmin#example.com'],
)
return HttpResponseRedirect('/thanks/')
else:
form = PhoneForm()
return render(request, 'index.html', {'form': form})
index.html
<form action="" method="post">
{% csrf_token %}
{{ form }}
<input type="submit" value="Submit" />
</form>
forms.py
from django import forms
class PhoneForm(forms.Form):
phone_form = forms.CharField(widget=forms.TextInput())
EDIT: Adding urls.py (the one in the app)
from django.conf.urls import include, url
from django.contrib import admin
from . import views
urlpatterns = [
url(r'^$', views.index, name='index'),
url(r'^$', views.get_number, name='get_number'),
]
Both urls in urls.py have the same expression r'^$' and django looks for them in order, therefore the first one (index) will always be selected. This links to the index view not the get_number view. This means the form is not passed to the template and the form does not show up.
To solve this move url(r'^$', get_number), to the top of 'urlpatterns'.
Change from {{form}} to {{form.phone_form}} in index.html

Django form is_valid always false

In my django application the form never returns true even if I add the same data as in the admin application. My model.py looks like:
from django.db import models
from django.db.models import ImageField, signals
from django.dispatch import dispatcher
from django.forms import ModelForm
# Create your models here.
class Image(models.Model):
emailAddress = models.EmailField(max_length=75)
image = ImageField(upload_to='photos')
caption = models.CharField(max_length=100)
class UploadForm(ModelForm):
class Meta:
model = Image
My views.py looks like:
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render_to_response
from competition.models import Image, UploadForm
# Create your views here.
def index(request):
images = Image.objects.all().order_by('emailAddress')
return render_to_response('images/index.html', {'images': images})
def uploadImage(request):
if request.method == 'POST': # If the form has been submitted...
form = UploadForm(request.POST) # A form bound to the POST data
if form.is_valid(): # All validation rules pass
emailAddress = form.cleaned_data['emailAddress']
image = form.cleaned_data['image']
caption = form.cleaned_data['caption']
i = Image(emailAddress=emailAddress, image = image, caption = caption)
i.save()
return HttpResponseRedirect('../image/')
else:
return render_to_response('images/upload.html', {'form': form})
else:
form = UploadForm() # An unbound form
return render_to_response('images/upload.html', {'form': form})
My template looks like:
<html>
<body>
<form enctype="multipart/form-data" action="/image/uploadImage" method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" />
</form>
</body>
</html>
I can get it work correctly if I use the admin application but need a generic form and this does't work as it keeps asking for a either the email address or image (the error appears above the image field). So why might my form not be valid?
You need to instantiate your form with request.FILES as well as request.POST.
As an aside, you can save the model form instead of creating the Image by hand in the view.
You have a required image but you aren't binding the file data to the form.
form = UploadForm(request.POST)
should be
form = UploadForm(request.POST, request.FILES)
See https://docs.djangoproject.com/en/1.3/ref/forms/api/#binding-uploaded-files
FileField and ImageField fields have two places need to notice:
Require enctype="multipart/form-data" in form element.
<form enctype="multipart/form-data" method="post" action="/foo/">
Require request.FILES for form constructor.
form = UploadFileForm(request.POST, request.FILES)
Please refer:
https://docs.djangoproject.com/en/2.2/topics/http/file-uploads/
https://docs.djangoproject.com/en/2.2/ref/forms/api/#binding-uploaded-files