I have a form where I am supposed to upload an image, but I can't get the image to save. Everything else in the form works properly except the image.
I'm sure there are some issues with my addGame method, but I've tried it dozens of different ways with no luck.
I've gone through the documentation, but it appears I'm still doing something wrong, as the image never gets saved.
(Just as a side note: I'm using Pillow for cropping the image, and I'm not sure if I'm doing that properly either, but I just added that in recently, and since the image doesn't save I have no way of knowing whether that is implemented correctly. I'm leaving the cropping part commented out while I try to get the upload to work.)
forms.py
class GameForm(forms.ModelForm):
image = forms.ImageField()
code = forms.Textarea()
deleteGame = forms.BooleanField(required=False, widget=forms.HiddenInput())
class Meta:
model = Game
fields = ('title', 'image', 'description', 'requirements', 'code', 'deleteGame')
views.py:
#login_required
def add_game(request):
user = request.user
if request.method == 'POST':
form = GameForm(request.POST, request.FILES)
if form.is_valid():
form = form.save(commit=False)
image = request.FILES['image']
box = (200, 200, 200, 200)
cropped = image.crop(box)
form.image = cropped
form.user = request.user
form.save()
return HttpResponseRedirect('/userprofile')
else:
form = GameForm()
args = {}
args.update(csrf(request))
args['user'] = user
args['form'] = form
return render_to_response('addgame.html', args)
models.py
class Game(models.Model):
user = models.ForeignKey(User, blank=True)
title = models.CharField(max_length=256)
image = models.ImageField(upload_to='games', blank=True)
description = models.CharField(max_length=256)
requirements = models.CharField(max_length=256)
code = models.TextField()
deleteGame = models.BooleanField(default=False)
def __unicode__(self):
return self.title
My media settings look like this:
MEDIA_ROOT = 'media/'
MEDIA_URL = '/media/'
File Structure:
If I add an image via the admin portal, it saves properly, but I get an error like this in my log:
Not Found: /media/games/Screen_Shot_2015-12-29_at_1.03.05_AM.png
The enctype="multipart/form-data" is needed in the form tag in your template if you intend to send files along with the form data.
Related
I am a beginner with Django and I have been enjoying it so far. I figured out how to use model formsets, but I cannot figure out how to make my form automatically use logged in User as the 'updated_by' field.
models.py
class Inventory(models.Model):
item = models.CharField(max_length=50, unique=True)
stock = models.IntegerField()
par = models.IntegerField()
date_updated = models.DateTimeField(auto_now=True)
updated_by = models.ForeignKey(User, on_delete=models.PROTECT)
def __str__(self):
return self.item
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
image = models.ImageField(default='default.jpg', upload_to='profile_pics')
phone = PhoneField(blank='True', help_text='Contact Phone Number')
def __str__(self):
return f'{self.user.username} Profile'
def save(self):
super().save()
I think the problem lies in your views.py. Try getting request.user before saving the form.
i think you should have made form for Inventory if yes(let InvntoryForm) than in view.py file you have done something like this:-
if request.method == 'POST':
Inven_form=InventoryForm(data=request.POST)
if Inven_form.is_valid():
user=Inven_form.save()
#in between add this
Inven_form.updated_by=request.user.username
user.save()
I would use the 'commit=False' argument which will create a new object and assign it without saving to your database. You can then set the user attribute and call save() with no arguments.
For example, this is how I assigned the user attribute to my blog app.
in views.py
if form.is_valid():
# Create a new entry and assign to new_article.
new_article = form.save(commit=False)
# Set the new article attribute to the current user.
new_article.user = request.user
# Save to database now the object has all the required data.
new_article.save()
Here is the full code for the add_article view if this helps.
#login_required
def add_article(request):
""" Add a new article. """
if request.method != 'POST':
# No data submitted, create a blank form.
form = AddArticleForm()
else:
# POST data submitted, process data.
form = AddArticleForm(request.POST, request.FILES)
if form.is_valid():
new_article = form.save(commit=False)
new_article.author = request.user
new_article.save()
return back_to_blog_page()
context = {'form': form}
return render(request, 'add_article.html', context)
I have a user profile page connected to a model which amongst other fields contain the following:
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
image = models.ImageField(default='default.jpg', upload_to='profile_pics')
That works like it should; the profile image connected to the user in question is loaded, and the distinction between users is made.
What I'm trying to do now is connect a separate gallery model to the profile page, that the users may have a small image gallery to goof around with.
The gallery model looks like this:
class GalleryModel(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
img_1 = models.ImageField(default='default.jpg', upload_to='images')
img_2 = models.ImageField(default='default.jpg', upload_to='images')
img_3 = models.ImageField(default='default.jpg', upload_to='images')
The views.py file looks like this:
class ProfileDetailView(DetailView):
model = Profile # Is something iffy here? Should this refer to the GalleryModel as well?
template_name = 'account/view_profile.html'
def get_object(self):
username = self.kwargs.get('username')
if username is None:
raise Http404
return get_object_or_404(User, username__iexact=username, is_active=True)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
username = self.object.username
context['person'] = GalleryModel.objects.get(user__username=username) #loads username string
context['img_1'] = GalleryModel.objects.last().img_1
context['img_2'] = GalleryModel.objects.last().img_2
context['img_3'] = GalleryModel.objects.last().img_3
return context
I've tried a bunch of ideas (i.e. various approaches to the filter() and get() methods) and scrutinizing https://docs.djangoproject.com/en/2.1/topics/db/queries/ and sifting through what I could find on SO, but I can't work it out.
For instance filter(username__iexact=username) doesn't seem to do the trick, nor do variations upon the theme produce anything but error messages, that I don't really understand.
I can get the username to go through if I insert {{ person }} in the template, but how do I get the objects (images) connected to the username in the GalleryModel?
Trying for the following is a no go:
GalleryModel.objects.get(user__username=username).img_1
As always, I have an eerie feeling that I'm missing something rather simple :)
NB!: I know that the last() method is not what I'm supposed to do, obviously, but thus far it's the only way I've managed to get images to render unto the template.
If you want to connect the Gallery to the Profile, you have to add Profile as ForeignKey, not User.
class GalleryModel(models.Model):
profile = models.ForeignKey(Profile, on_delete=models.CASCADE)
Except if you have another kind of Gallery, use Gallery(models.Model).
I've tried to research and understand on the documentation, but unable to solve my problem.
I've a ModelForm which allows me to select and upload multiple files.
However, upon saving, only 1 file is saved to my media root folder despite multiple selection.
My guess is that the filename for all files in getlist are same (since they're uploaded at the same time), it overwrites each other in a way and end up only saving 1 media. Appreciate the assistance from the community, thank you !
forms.py
class FileFieldForm(forms.ModelForm):
stuff_image = forms.FileField(widget=forms.ClearableFileInput(attrs={'multiple': True}))
class Meta:
model = Thing
fields = ('title', 'description', 'quantity','stuff_image')
--
model.py
def generate_filename(instance, filename):
ext = filename.split('.')[-1]
return '' + str(int(time())) + '.' + ext
class Thing(models.Model):
title = models.CharField(max_length=255)
description = models.TextField(blank = True)
quantity = models.IntegerField(blank =True)
creation_date = models.DateTimeField(auto_now_add=True)
stuff_image = models.FileField(upload_to=generate_filename)
def __unicode__(self):
return self.title
class Meta:
ordering = ['title']
#receiver(post_delete, sender=Thing)
def stuff_post_delete_handler(sender, **kwargs):
Thing = kwargs['instance']
storage, path = Thing.stuff_image.storage, Thing.stuff_image.path
storage.delete(path)
--
view.py
def create_stuff(request):
if request.method == 'POST':
form = FileFieldForm(request.POST, request.FILES)
files = request.FILES.getlist('stuff_image')
if form.is_valid():
for f in files:
form.save()
return redirect('list-stuff')
else:
form = FileFieldForm()
return render(request, 'stuffapp/create_stuff.html', {'form': form})
If you want to have multiple images linked to Thing model, you need to create an Image model with ForeignKey of Thing model. The FileField can only relate to one file at a time.
To upload multiple images/files in django, preferabble use the package django-multiupload, see the (documentation)[https://pypi.python.org/pypi/django-multiupload] or (GitHub Page)[https://github.com/Chive/django-multiupload]. Just follow the instructions and the examples. Works flawlessly.
Here i have two models:
ProfilePic
Member
ProfilePic's user variable extends from Member's username (this is so i can have one username in the DB for all other forms and models).
Now ProfilePic is used as a form, and in my views.py I want to add:
member_obj = Member.objects.get(pk=username)
to my ProfilePic form. However, when I run my code, it doesn't give an error but it doesn't render the information in the db either. So I'm confused as to whats going on here.
What am i doing wrong? Thanks in advance !
# models.py
class ProfilePic(models.Model):
user = models.ForeignKey(Member, related_name='%(class)s_user', null=True)
text = models.TextField(max_length=4096)
thumbnail = models.FileField(upload_to='media', null=True)
class Member(models.Model):
username = models.CharField(max_length=16, primary_key=True)
password = models.CharField(max_length=16)
profile = models.OneToOneField(Profile, null=True)
following = models.ManyToManyField("self", symmetrical=True)
# forms.py
from django import forms
from .models import ProfilePic
class UploadFileForm(forms.ModelForm):
class Meta:
model = ProfilePic
fields = ['text','thumbnail']
# views.py
def profile(request):
username = request.session['username']
member_obj = Member.objects.get(pk=username)
if request.POST:
invitations = Invitation.objects.filter(to_user=username)
form = UploadFileForm(request.POST,request.FILES, instance=member_obj)
form.save()
picture = ProfilePic.objects.all()
return render(request, 'social/profile.html', {
'appname': appname,
'username': username,
'invitations':invitations,
'picture' : picture,
'form' : form,
'loggedin': True}
)
You are passing a Member instance to a ProfilePic model form.
What you want to do is:
form = UploadFileForm(request.POST, request.FILES,
instance=member_obj.profile_pic_user)
So you get a ProfilePic instance.
View is just a function. You get a Member object from the database, assign it to a member_obj variable, but you are not actually doing anything with it. You want to assign it to a ProfilePic object. Also, I don't think this line picture = ProfilePic.objects.all() does what you intend to do. You are getting a list of all profile picture objects instead of just one.
You have to add it to the saved object. You do that by telling the form to create the object, but not saving it to the DB yet.
Then, set the field, and save to the DB.
Add this lines to the view, instead of the form.save():
profile_pic = form.save(commit=False) #not saving to db
member_obj = Member.objects.get(username=request.user.username)
profile_pic.user = member_obj
profile_pic.save() # now it's saved
So I'm working on a portfolio site, and I've got a form called Work that represents the works in the portfolio. A Work has an M2M field for normal images, and one ImageField for the main image that is to be used for thumbnails etc.
My problem is the following, when I go to the update view I created for Work, the old Image (that is already in the database) is listed in the form, but no in the field itself. It says current: [name of the image], and then the regular filefield with label edit.
I don't want the user to only be able to update a work if they upload the image again. How do I pass the current image to the form?
#models.py
class Work(models.Model):
name = models.CharField(max_length=255)
image = models.ImageField( upload_to="images" )
#forms.py
class Meta:
model = Work
exclude = ('slug',)
#views.py
def workEdit(request, pk):
if request.method == "POST":
form = WorkForm(request.POST, request.FILES)
if form.is_valid():
new_work = form.save(commit=True)
return redirect("/portfolio/beheer/werk")
else:
print(form)
print(form.errors)
else:
work = get_object_or_404(Work, pk=pk)
form = WorkForm(request.POST ,request.FILES, instance=work)
context = {
'form': form,
}
return render(request, 'submit.html', context)