django inline formset to upload multiple files not rendering form - python

I have model:
class MediaInfo(models.Model):
title = models.CharField(max_length=50,blank=True)
description = models.CharField(max_length=255,blank=True)
media_file = models.FileField(upload_to=get_upload_file_name)
def __unicode__(self):
return self.title
class Media(models.Model):
media_files = models.ForeignKey(MediaInfo)
def __unicode__(self):
return self.media_files
What I want is to render a template where I get a simple browse button and I can select and upload multiple 'media_file'.
I came to know that it can be performed from inline formset so used it in my view. My view looks like
def MediaAddView(request):
#med = MediaInfo.objects.al()
MediaInlineFormset = inlineformset_factory(MediaInfo, Media)
if request.method == "POST":
formset = MediaInlineFormset(request.POST, request.FILES)
if formset.is_valid():
formset.save()
return HttpResponseRedirect("some url")
else:
return render_to_response("media_add.html",
{"formset":formset,},
context_instance=RequestContext(request))
else:
formset = MediaInlineFormset()
return render_to_response("media_add.html",
{"formset":formset,}, context_instance=RequestContext(request))
and my template is :
<form method="post" action="" enctype="multipart/form-data">
{% csrf_token %}
{{ formset.management_form }}
{% for form in formset %}
{{form.media_file}}
{% endfor %}
<input type="submit" value="Submit" />
</form>
When I do this instead of getting a browse button to upload file I am getting only submit button.
How can I get just a browse button and add multiple files or images ?
Whats wrong in my code ?
Need help

Related

Upload any file in django

I was trying to create a function for upload file in Django. First time I running my code, it's cannot upload a file. So, I was trying to improve my code and what I got its error. I thought the error it's weird because I always used that and I never get an error. I'll show my code.
models.py
class UploadFiles(models.Model):
File = models.ImageField(upload_to = 'Images/', default='Images/')
views.py
def upload_file(request):
if request.method == 'POST':
form = UploadFile(request.POST, request.FILES)
if form.is_valid():
form.save()
return redirect('home')
else:
form = UploadFile()
return render(request, 'girl/upload.html', {'form': form})
forms.py
class UploadFile(forms.Form):
title = forms.CharField(max_length=50)
file = forms.FileField
upload.html
{% extends 'girl/base.html' %}
{% block content %}
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Upload</button>
</form>
<p>Return to home</p>
{% endblock %}
error:
django.urls.exceptions.NoReverseMatch: Reverse for '/' not found. '/' is not a valid view function or pattern name.
urls.py
url(r'^cat/upload/$', views.upload_file, name='uploads')
Any help would be appreciated.
This is the line the error is
<p>Return to home</p>
Change it to
<p>Return to home</p>
And in your forms to
class UploadFile(forms.ModelForm)
class Meta:
model=UploadFiles
fields ='__all__'

How correctly save multiple files in django?

I need form where user can create article with several images. I use django-multiupload app for image field. I can select several images but when I try to submit the form I have message under the image field: "Field is empty and field is required". Where is my mistake? Why I have such message when image field is not empty?
Also maybe someone can advice good examples or apps to save several images. I would be very grateful for any help.
models.py:
class Article(models.Model):
description = models.TextField(_('Description'))
class Image(models.Model):
article= models.ForeignKey(Article, on_delete=models.CASCADE)
image = models.FileField(_('Image'), upload_to='images/%Y/%m/%d/')
forms.py:
class ArticleForm(forms.ModelForm):
class Meta:
model = Article
fields = ('description', )
image = MultiFileField()
def save(self, commit=True):
instance = super(ArticleForm, self).save(commit)
for each in self.cleaned_data['image']:
Image.objects.create(image=each, article=instance)
return instance
views.py:
def article_add(request):
data = dict()
if request.method == 'POST':
article_form = ArticleForm(request.POST, request.FILES)
if article_form.is_valid():
article = article_form.save(commit=False)
******
article.save()
data['form_is_valid'] = True
articles = Article.objects.all
context = {'articles': articles}
context.update(csrf(request))
data['html_article'] = render_to_string('project/article_list.html', context)
else:
data['form_is_valid'] = False
else:
article_form = ArticleForm()
context = {'article_form': article_form}
data['html_article_form'] = render_to_string('project/article_add.html', context, request=request)
return JsonResponse(data)
article_add.html:
{% load widget_tweaks %}
<form method="post" action="{% url 'article_add' %}" class="article-add-form">
{% csrf_token %}
{% for field in article_form %}
<div class="form-group{% if field.errors %} has-danger{% endif %}">
<label class="form-control-label" for="{{ field.id_for_label }}">{{ field.label }}</label>
{% render_field field class="form-control" %}
{% for error in field.errors %}
<div class="form-control-feedback">{{ error }}</div>
{% endfor %}
</div>
{% endfor %}
<button type="submit">Submit</button>
</form>
Try adding "min_num" constraint on the image field,
image = MultiMediaField(min_num=1, media_type='image')
EDIT
def article_add(request):
if request.method == 'POST':
article_form = ArticleForm(request.POST, request.FILES)
if article_form.is_valid():
article = article_form.save(commit=False)
******
article.save()
#assume you have already a view in the name 'article_list'.
return redirect('article_list')
else:
article_form = ArticleForm()
context = dict(article_form=article_form)
return render(request, 'project/article_add.html', context)
The problem maybe because you were trying to render two templates in a single view, also when using django template rendering render is a shortcut function, which is mostly preferred to use, rather than string converting and parsing into json.
Also, 'article_list' must be another view, which shows the list of all the articles, after adding a new article, you should consider redirecting to the list view. Here you were trying to render multiple templates, in a single view. You could make of something like this in your list view,
def article_list(request):
articles = Article.objects.all()
context = dict(articles=articles)
return render(request, 'project/article_list.html', context)
Although, these are my personal opinion regarding the code you just shared. Try this approach...

Edit multiple objects with Get() function Django

I want to edit two forms in Django. A form for 'Motel' and its 'Images'. In my app, users can upload multiple images to the 'Motel' model. And now, editing the images with 'get()' function is giving me,
MultipleObjectsReturned get() returned more than one MotelImages -- it returned 4!
Models
class Motel(models.Model):
user= models.ForeignKey(User)
title= models.CharField(max_length=120)
body= models.TextField()
#other fields
class MotelImages(models.Model):
motel= models.ForeignKey(Motel, default=None, related_name='images')
image= models.ImageField(upload_to='company', verbose_name= 'Image')
class MotelImagesForm(forms.ModelForm):
image= forms.ImageField(label='Image',)
def __init__(self, *args, **kwargs):
super(MotelImagesForm,self).__init__(*args, **kwargs)
self.fields['image'].widget= forms.FileInput(attrs={'name':'image',
'multiple':'multiple'})
Views for saving the form
def create_motel(request):
if request.method=="POST":
motelForm= MotelForm(request.POST, request.FILES)
formset=MotelImagesForm(request.POST, request.FILES)
if motelForm.is_valid() and formset.is_valid():
human= True
motel_form= motelForm.save(commit=False)
motel_form.user= request.user
motel_form.pub_date= datetime.datetime.now()
motel_form.save()
for image in request.FILES.getlist('image',[]):
photo= MotelImages(motel=motel_form, image=image)
photo.save()
messages.success(request,
"Welldone Boy")
return HttpResponseRedirect('/view_all/')
else:
print motelForm.errors, formset.errors
else:
motelForm=MotelForm()
formset= MotelImagesForm()
return render(request, 'motels/add_motel.html',{'motelForm': motelForm, 'formset':formset})
Views for editing the form
#login_required
def edit_motel(request,motel_id=None,slug=None,template_name='motel_edit.html'):
if id:
post=get_object_or_404(Motel,id=motel_id,slug=slug)
images=MotelImages.objects.get(motel=motel_id)
else:
post=Motel(user=request.user)
images=MotelImages(user=request.user)
if request.POST:
motelform=MotelForm(request.POST,request.FILES, instance=post)
formset=MotelImagesForm(request.POST,request.FILES, instance=images)
if form.is_valid() and formset.is_valid():
form.save()
formset.save()
redirect_url=reverse('moteldetail',kwargs={'motel_id':motel_id,'slug':slug})
return render(request, 'motels/updatenotice.html')
else:
form=MotelForm(instance=post)
formset= MotelImagesForm(instance=images)
return render(request, template_name,{'formset':formset,'motelform':motelform})
Template for editing the form
<form id="post_form" method="post" action=""
enctype="multipart/form-data">
{% csrf_token %}
{% for hidden in motelform.hidden_fields %}
{{ hidden }}
{% endfor %}
{% for field in motelform %}
{{ field.name }}
{{ field }} <br />
{% endfor %}
{{ formset.management_form }}
{% for form in formset %}
{{ form }}
{% endfor %}
<input type="submit" name="submit" value="Submit" />
</form>
What am I missing?
images = MotelImages.objects.get(motel=motel_id)
Since get can return only one object, you want to use filter:
images = MotelImages.objects.filter(motel__pk=motel_id)
images will be a list of the relevant images.

Multiple file uploads using formset?

models.py
class Album(models.Model):
file_upload = models.FileField(upload_to=content_file_name)
name_content = models.CharField(max_length=100)
And Function is here
def content_file_name(instance, filename):
upload_dir = os.path.join('uploads', 'resource')
return os.path.join(upload_dir, filename)
forms.py
class Albumform(forms.Form):
name_content = forms.CharField(max_length=100)
file_upload = forms.FileField( 'please select' )
This is my views.py
from django.forms.formsets import formset_factory
def viewalbum(request):
AlbumFormSet = formset_factory(Albumform, extra=3, max_num=10,)
if request.method == 'POST':
formset = AlbumFormSet(request.POST, request.FILES)
if formset.is_valid():
albumvalue = Album()
albumvalue.name_content = request.POST.get('name_content', None)
albumvalue.file_upload = request.FILES['file_upload']
albumvalue.save()
return HttpResponseRedirect(reverse('views.viewalbum'))
else:
formset = AlbumFormSet()
return render_to_response('audio/test.html',{'formset': formset}, context_instance=RequestContext(request))
and the html looks like this
<form action="" method="POST" enctype="multipart/form-data">
{{ formset.management_form }}
{% csrf_token %}
<table>
{% for form in formset.forms %}
{{ form }}
{% endfor %}
</table>
The problem is i can only upload one file at the time. Give me solution to upload multiple file in the same time and saved into resource folder. Thanks
If you want to upload multiple files, then you need multiple filefields. That is your option A. If you choose to go for it, create formset and use it to provide multiple file upload.
your option B is to use some kind of javascript widgets that make multiple file uploads possible.

Management form error while using modelformsets ('ManagementForm data is missing or has been tampered with')

I have a models.py class as below
class Educational_Qualification(models.Model):
user = models.ForeignKey(User)
exam = models.CharField(max_length=40)
pass_month = models.CharField(max_length=40)
I have a views.py as below
def create_qualification(request):
QFormSet = modelformset_factory(Educational_Qualification, extra=3, exclude=("user",))
if request.method == "POST":
formset = QFormSet(request.POST, request.FILES)
if formset.is_valid():
formset.save()
for form in formset.forms:
if form.is_valid():
quali= form.save(commit=False)
quali.user = request.user
quali.save()
return HttpResponse("Saved")
else:
return HttpResponse("Snafu")
else:
formset = QFormSet()
return render_to_response("register/edu.html", {"formset":formset}, context_instance=RequestContext(request))
When I submit the form, it throws up the validation Error. stating that ManagementForm data is missing or has been tampered with'
I have formset.management_form in my template.
What could be the issue?
The error is not in your views or the models, but in the templates.
The right way to render the formset, is:
<form method="post" action="">
<table>
{{ formset }}
</table>
</form>
or
<form method="post" action="">
{{ formset.management_form }}
<table>
{% for form in formset.forms %}
{{ form }}
{% endfor %}
</table>
</form>
I guess, you are looping over the forms in the templates without including the management form?
It also happens if there are multiple views involved and one of them is not aware of the formset prefix.
Get view:
def someview(request):
...
formset = Formset(prefix="foo")
...
Post view (Potentially an Ajax form submit handler):
def ajaxview(request):
...
formset = Formset(request.POST, prefix="foo") # here
...

Categories

Resources