i have a model with FileField, when i submit a form uploading images it submits for the first time. But when i want to upload another image i get this error: get() returned more than one Image -- it returned 2!
class Image(models.Model):
imageuploader_profile = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.CASCADE, null=True, blank=True)
first_upload_image = models.FileField(upload_to ='pictsagram/',null=True)
second_upload_image = models.FileField(upload_to ='pictsagram/',null=True)
def home(request):
all_images = Image.objects.filter(imageuploader_profile=request.user.id)
try:
upload_images = Image.objects.get(imageuploader_profile=request.user.id)
except Image.DoesNotExist:
upload_images = None
all_users = Profile.objects.all()
next = request.GET.get('next')
if next: return redirect(next)
context = {
'all_images': all_images,
'all_users': all_users,
'upload_images': upload_images,
}
return render(request,'home.html', context,)
def upload(request):
form = PostForm(request.POST,request.FILES)
if request.method == "POST":
print(request.FILES)
if form.is_valid():
post = form.save(commit=False)
post.imageuploader_profile = request.user
post.save()
return redirect('/')
else:
form = PostForm()
return render(request, 'upload.html', {"form": form})
{% if upload_images.first_upload_image %}
<img src="{{ upload_images.first_upload_image.url }}" class="img-fluid d-block w-100" alt="orange tree" />
{% endif %}
{% if upload_images.second_upload_image %}
<img src="{{ upload_images.second_upload_image.url }}" class="img-fluid d-block w-100" alt="orange tree" />
{% endif %}
If you use modelname.objects.get("field_name"="**")
It will always give you a single object that matches your query.
If your database contains more than one objects that matches your query you should use filter
modelname.objects.filter("field_name"="**")
This happens because every time when you submit the form you write a new record in the database instead of updating the current one.
Assuming that imageuploader_profile can only have one row in the table
def upload(request):
upload_images = Image.objects.filter(imageuploader_profile=request.user.id).first()
form = PostForm(instance=upload_images)
if request.method == "POST":
form = PostForm(request.POST, request.FILES, instance=upload_images)
if form.is_valid():
post = form.save(commit=False)
post.imageuploader_profile = request.user
post.save()
return redirect('/')
return render(request, 'upload.html', {"form": form})
Related
I'm trying to make model based form but something went wrong.
model:
class Topic(models.Model):
name = models.CharField(max_length=200)
icon = models.ImageField(upload_to = 'images/')
form:
class TopicCreationForm(ModelForm):
class Meta:
model = Topic
fields = '__all__'
view:
def TopicCreateView(request):
form = TopicCreationForm()
if request.method == 'POST':
form = TopicCreationForm(request.POST)
if form.is_valid():
form.save()
return redirect('home')
else:
print('aaa') # It displays in console
context = {'form':form}
return render(request, 'blog/topic_form.html', context)
my form html part
<form method="POST">
{% csrf_token %}
<fieldset >
<legend> New Topic</legend>
{{ form|crispy }}
</fieldset>
<div>
<input type="submit" value="submit" class="button-33" role="button">
</div>
</form>
where did i make mistake ?
You need to pass both request.POST and request.FILES [Django-doc], so:
def topic_create(request):
if request.method == 'POST':
form = TopicCreationForm(request.POST, request.FILES)
if form.is_valid():
form.save()
return redirect('home')
else:
print('aaa') # It display in console
else:
form = TopicCreationForm()
context = {'form':form}
return render(request, 'blog/topic_form.html', context)
In the HTML form, you need to specify that the files should be encoded with the enctype="…" attribute [mdn]:
<form method="post" enctype="multipart/form-data">
…
</form>
Multiple files do not save in admin, only the first saved in admin.
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/')
image_caption = models.CharField(max_length=700)
def upload(request):
form = PostForm(request.POST,request.FILES)
if request.method == "POST":
if form.is_valid():
for f in request.FILES.getlist('image'):
post = Image(image=f)
post = form.save(commit=False)
post.imageuploader_profile = request.user
print(request.user)
post.save()
form.save()
return redirect('/')
else:
form = PostForm()
return render(request, 'upload.html', {"form": form})
class PostForm(forms.ModelForm):
class Meta:
model = Image
fields = ('image_caption', 'image',)
<form action="{% url 'site:upload' %}" method="post" enctype="multipart/form-data">
{%csrf_token%}
<input type="file" name="file" multiple onchange="loadFile(event)" required="" id="id_file">
<button type="submit">Post</button>
</form>
It looks like your form is for an Image object, but you're trying to create multiple images from a single form submit.
You are creating the Image(), but it doesn't look like you're attaching it to the form. So you'll probably need to reorganize the view something like:
def upload(request):
if request.method == "POST":
for image_file in request.FILES.getlist('image'):
form = PostForm(request.POST, image_file)
if form.is_valid():
image = form.save(commit=False)
image.imageuploader_profile = request.user
image.save()
form.save()
return redirect('/')
else:
form = PostForm()
return render(request, 'upload.html', {"form": form})
Also, cut/paste can mess up formatting, but always double-check your indentation for intended flow.
use this code:-----------------------------
def upload(request):
form = PostForm(request.POST,request.FILES)
if request.method == "POST":
if form.is_valid():
for f in request.FILES.getlist('file'):
post = Image(image=f)
post = form.save(commit=False)
post.imageuploader_profile = request.user
print(request.user)
post.save()
form.save()
return redirect('/')
else:
form = PostForm()
return render(request, 'upload.html', {"form": form})
class PostForm(forms.ModelForm):
class Meta:
model = Image
fields = ('image_caption', 'image',)
<form action="{% url 'site:upload' %}" method="post" enctype="multipart/form-data">
{%csrf_token%}
<input type="file" name="file" multiple onchange="loadFile(event)" required="" id="id_file">
<button type="submit">Post</button>
</form>
To new readers: Neverwalkaloner's solution solved the initial error but the photo upload is still required and making required false in forms.py gives me a MultiValueDictKeyError. Any help on making it optional would be greatly appreciated.
I have a model and form to upload either a picture and text, or just text. My intention, actually was to make it a choice between an image, text or both and any help with that would be appreciated, but I digress. Uploading only works when an image is included, if it is just text, I get the error:
The view lesyeux.views.posts didn't return an HttpResponse object. It
returned None instead.The view lesyeux
My model is:
class Post(models.Model):
image = models.ImageField(upload_to='uploaded_images', blank=True,
null=True)
text_post = models.CharField(max_length=1000)
author = models.ForeignKey(User)
My form is:
class PostForm(forms.ModelForm):
image = forms.FileField(label='Select an image file',
help_text='Please select a photo to upload')
text_post = forms.CharField(help_text="Please enter some text.")
class Meta:
model = Post
fields = ('image', 'text_post',)
exclude = ('author',)
My view is:
def posts(request, id=None):
neighborhood = get_object_or_404(Neighborhood, id=id)
form = PostForm()
if request.method == 'POST':
form = PostForm(request.POST, request.FILES)
if form.is_valid():
post = Post(image = request.FILES['image'])
post = form.save(commit=False)
post.author = request.user
post = post.save()
next = request.POST.get('next', '/')
return HttpResponseRedirect(next)
else:
form = PostForm()
posts = Post.objects.all().order_by('-id')
return render(request, 'posts.html', context = {'form':form,
'posts':posts, 'neighborhood':neighborhood})
and my form is:
<form id="PostForm" method="post" action="/view/{{ neighborhood.id }}/posts/" enctype="multipart/form-data">
{% csrf_token %}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{% for field in form.visible_fields %}
{{ field.errors }}
{{ field.help_text }}
{{ field }}
{% endfor %}
<input type="hidden" name="next" value="{{ request.path }}">
<input type="submit" name="submit" value="Post" />
</form>
Your view doesnt return response if form is not valid. To fixt it rewrite view like this:
def posts(request, id=None):
neighborhood = get_object_or_404(Neighborhood, id=id)
form = PostForm()
if request.method == 'POST':
form = PostForm(request.POST, request.FILES)
if form.is_valid():
post = Post(image = request.FILES['image'])
post = form.save(commit=False)
post.author = request.user
post = post.save()
next = request.POST.get('next', '/')
return HttpResponseRedirect(next)
else:
form = PostForm()
posts = Post.objects.all().order_by('-id')
return render(request, 'posts.html', context = {'form':form, 'posts':posts, 'neighborhood':neighborhood})
I am not getting any errors in the template. It just gives me back the form without error. Although the uploading function works fine, but if I don't give any input it doesn't give me any errors. How would I get the errors if there are in my template?
html:
{% block content %}
<form action="/{{ user.username }}/upload_photos/" method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Upload"/>
</form>
{% endblock %}
views.py:
def upload_photos(request, user_name):
user = User.objects.get(username=unquote(user_name))
if request.method=='POST':
form = PhotoForm(request.POST, request.FILES)
if form.is_valid():
forum = form.save(commit=False)
forum.user = user
forum.save()
return HttpResponseRedirect('/'+user.username+'/photos')
else:
form = PhotoForm()
return render(request, 'upload_photos.html',{'form':form})
else:
form = PhotoForm()
return render(request, 'upload_photos.html',{'form':form})
I've commented out the line that empties your form.
def upload_photos(request, user_name):
user = User.objects.get(username=unquote(user_name))
if request.method=='POST':
form = PhotoForm(request.POST, request.FILES)
if form.is_valid():
forum = form.save(commit=False)
forum.user = user
forum.save()
return HttpResponseRedirect('/'+user.username+'/photos')
else:
# form = PhotoForm() Don't overwrite the submitted form.
return render(request, 'upload_photos.html',{'form':form})
else:
form = PhotoForm()
return render(request, 'upload_photos.html',{'form':form})
I've excluded a field in a ModelForm but it doesn't seem to affect the form's display .as_p. It even displays it when I instantiate with nothing!
Here's the ModelForm:
class WorkoutForm(ModelForm):
class Meta:
model = Workout
exclude = ('user',)
and the associated view:
def addworkout(request, uid):
thisuser = get_object_or_404(User, pk=uid)
if request.method == 'POST':
form = WorkoutForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect('/u/'+str(uid))
else:
w = Workout(user=thisuser)
#creates a form for thisuser
form = WorkoutForm(instance = w)
return render_to_response('addworkout.html', {'form':form, 'user':thisuser}, RequestContext(request))
and also the template:
<body>
<p>"{{request.path}}" </p>
Add a new workout, {{user.name}}!
<form action="/u/1/addworkout" method="POST">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value= "Submit" />
</form>
</body>
What is this?
else:
w = Workout(user=thisuser)
Shouldn't it be something like:
w = Workout.objects.get(user=thisuser)
If so, does it fix the bug?
In your POST request block, you also need to pass in the instance such that form = WorkoutForm(request.POST, instance=w)
Re-written, your view should look like this:
def addworkout(request, uid):
thisuser = get_object_or_404(User, pk=uid)
w = get_object_or_404(Workout, user=thisuser)
form = WorkoutForm(instance = w)
if request.method == 'POST':
form = WorkoutForm(request.POST, instance=w)
if form.is_valid():
form.save()
return HttpResponseRedirect('/u/'+str(uid))
return render_to_response('addworkout.html', {'form':form, 'user':thisuser}, RequestContext(request))