Django - ImageField files not showing up? - django

This is my models.py:
class UserImages(models.Model):
user = models.ForeignKey(User)
photo = models.ImageField(upload_to=get_file_path)
and this is my view which uploads images:
def uploadImageView(request):
if request.method == 'POST':
form = UploadImageForm(request.POST, request.FILES)
if form.is_valid():
instance = form.save(commit=False)
instance.user = request.user
instance.save()
return redirect('/')
else:
form = UploadImageForm()
return render(request, 'image.html', {'form': form})
and this is my view which displays user's images:
def displayImageView(request):
user = request.user
img = UserImages.objects.filter(Q(user__username=user))
return render(request, "displayImage.html", {"img": img})
and this is my displayImage.html template:
{% load staticfiles %}
{% for image in img %}
<img src="{% static image.photo.url %}" alt="" />
{% endfor %}
and when I go to the URL which loads the template, it displays four images. I remember that while testing the uploadImageView, I uploaded 4 images for the viewer. The location Django saves the images was
/home/images/static
and I went to that folder and deleted two images. I then refreshed the template page and it still displayed 4 images rather than two, so then I figured that I had to delete it from the actual database rather than the folder. I then did
python manage.py shell
>>> from app.models import UserImages
>>> from django.contrib.auth.models import User
>>> a = User.objects.get(username='testUser')
>>> b = UserImages(user=a)
>>> b
<UserImages: UserImages object>
>>> b.photo
<ImageFieldFile: None>
amd as you can see, only one ImageFieldFile shows up for the user who I uploaded 4 images for. How come I can only see one?
EDIT:
my UploadImageForm() is just this:
class UploadImageForm(forms.ModelForm):
class Meta:
model = UserImages
fields = ['photo']

Your problem is here:
>>> b = UserImages(user=a)
>>> b
<UserImages: UserImages object>
>>> b.photo
<ImageFieldFile: None>
This code snippet is creating a new instance of UserImages, setting the user attribute to the object a. It is not searching the database. Since you haven't attached any images to this new instance, b is None.
To search, you need to do this instead:
>>> b = UserImages.objects.filter(user=a)
You also shouldn't upload anything to the same folder that is pointed to by STATICFILES_DIRS, as this folder is managed by django and your files here will be overwritten. I hope /home/images/static isn't listed here.
User uploads are saved in a subdirectory pointed to by MEDIA_FILES and accessed using MEDIA_URL.

When you save images in the database they will be saved in there as well as in a new location in your /static/ directory, etc.. Usually Django attaches a image_1.jpg for example if the image was originally image.jpg.
Do your images have a many-to-many relationship to the User model? Earlier, you said that there were 4 images saved to the User, then you said 1. Your UserImages model has one field, so possibly you are not looping through it correctly in the terminal shell in order to check all images. Perhaps it needs to be b.photos.all() if b = UserImages(user=a) or something to that extent?

Related

Django: Uploading Avatar Imagefile to media-Folder of Custom User Profile is not working

I'm currently trying to create a Custom User Model for being able to add a Avatar-Imagefield to ever User.
Therefore I've created a Model Profile with avatars as the directory (media/avatars/) for all Images:
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
avatar = models.ImageField('Avatar', upload_to="avatars", default="avatars/profil_picture_icon.png")
I created the needed classes ProfileInline and UserAdmin:
class ProfileInline(admin.StackedInline):
model = Profile
can_delete = False
class UserAdmin(BaseUserAdmin):
inlines = (ProfileInline,)
admin.site.unregister(User)
admin.site.register(User, UserAdmin)
I also defined the media-directory inside the settings:
MEDIA_ROOT = BASE_DIR / 'media'
MEDIA_URL = '/media/'
After that, I created a Form ProfileForm, where the User can upload the Image and a postsavereceiver to create a basic Profile-Model every time I'm creating a new User:
class ProfileForm(forms.ModelForm):
class Meta:
model = models.Profile
exclude = ('user',)
def post_save_receiver(sender, instance, created, **kwargs):
if created:
user_profile = models.Profile(user=instance)
user_profile.save()
post_save.connect(post_save_receiver, sender=settings.AUTH_USER_MODEL)
Inside my Template I then created a form with the Avatar-ImageField and a Save-Button to Upload that Image:
<form action="/profil/" method="post" id="avatar_form">
{% csrf_token %}
<img style="border-radius: 100px" id= "Profil_Image" src=" {{ user.profile.avatar.url }}">
{% load widget_tweaks %}
{{ profile_form.avatar|add_class:"profile_form" }}
<button id="update_button" style="left: 1210px; top: 385px" type="submit" form="avatar_form" name="avatar_update_btn" value="">Speichern</button>
</form>
Lastly inside my views.py the User can Update the Default-Image
elif 'avatar_update_btn' in request.POST:
profile_form = ProfileForm(request.POST, request.FILES)
models.Profile.objects.filter(user=request.user).update(avatar="avatars/" + profile_form.data['avatar'])
-> And here we got the Problem.
It's updating the Avatar-URL inside the Database with the correct Filename, but it can't find the Image after reloading the Page because the Image was not uploaded into the media/avatars/-Folder and I have no idea why.
As soon as I'm saving the Image over the admin-Page it's working perfectly and a new Image-Instance is created inside the avatars-Folder. But as soon as I'm trying to upload it with the ImageField, it's not creating a new Instance of the Image inside the Folder.
I think it must have something to do with the "update" - function of the model. Maybe with "update" it's just changing the URL without creating a new Image-Instance, that's why I've tried to upload it with the profile_form.save() - function. But it won't let me save it, since the save()-function wants to create a new Model-Instance but the Profile-Model is already existing.
Can you help me out here?
Thank you in Advance.
I believe the issue is with your settings.py. BASE_DIR is obviously the base directory of your project, where manage.py is located. Thus, your media folder should be in that directory, otherwise Django won't find it. And I take it you have a folder called avatar within the media folder. Try:
import os
BASE_DIR = os.path.dirname(os.path.abspath(__file__)) # You probably already have this
print(BASE_DIR) # Do this to check if your BASE_DIR is correct
...
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'

Django call CBV form other place

hey guys I have a specific issue.
I have a view:
class Upload(CreateView):
model = Banner
fields = ["image"]
success_url = '/url/'
def form_valid(self, form):
#some specifics operations...
This image are uploading to /upload
And in other place (e.g. /other_place, image in this dict are not uploading) I have a directory with other images. I get path to this images:
for file in glob.glob("*.jpg"):
l.append(file)
And in template:
{% for i in l %}
<img src="{{MEDIA_URL}}other_place/{i}}">
{%endfor%}
And I have nice template with all of this image. But now I need to upload selected image. specifically I need to call Upload view to upload selected image. Do you know what I mean? :D

Prevent users from seeing other user's uploaded pictures

I have a django applications that uses multi-users. Users can upload pictures on the system.I have created a picture model that has a foreignKey of a users to know which user uploaded which picture.
class Picture(models.Model):
picture = models.ImageField(upload_to='pictures')
uploader = models.ForeignKey(User)
#other specific fields like date etc
I have set up my settings file to use the MEDIA_URL and MEDIA_ROOT
settings.py
MEDIA_URL ='/media/'
MEDIA_ROOT = 'path/to/media/'
So I am able to access a picture in www.mydomain.com/media/pictures/picture.jpg. But I guess having a common MEDIA_ROOT means that any user can see this picture right?Not just the user who uploaded it. In my webpages I use
<img src={{image.picture}}>
to show images of a user. How can I prevent a user from seeing a picture a different user has uploaded(a forbidden message)? Can this be done on setup?
Your view function probably looks something like this:
#login_required
def theview(request):
...
image = Picture.objects.get(*args)
...
return render(request, 'template', {'image': image})
The point being that you can easily only pass the image along if it's the logged in user that have uploaded it. For instance
image = get_object_or_404(Picture, uploader=request.user, other_filters)
Or even
image = Picture.objects.get(*args)
image = image if image.uploader == request.user else None
Then in the django template
{% if image %}
<img ....>
{% endif %}
You can try like this:
in views:
def allpicture(request):
.....
#for all pictures
images= Picture.objects.filter(uploader=request.User)
return render(request, '/sometemplate', {'images': images})
def onepicture(request, pic_id):
....
#for one picture
image= Picture.objects.filter(id= pic_id, uploader=request.User) #url for this view should be like url(r'^pictures/(?P<pic_id>\d+)/$'
render render(request, '/sometemplate', {'image': image})

Django ModelForm not handling files correctly

I have a very basic model with an ImageField on it, and a ModelForm for uploading that image. My form is failing, saying that my image is not valid, but if I instantiate the model's image directly from the request.FILES it works perfectly. The file is uploaded and exists in my media directory. See code below
Also, this is failing in the Admin center as well.
Things I'm pretty sure it is not:
multipart/form-data
incorrect media path settings
permissions settings in those directories.
models.py
class ImageTile(BaseTile):
created_at = models.DateTimeField(default=datetime.datetime.now)
updated_at = models.DateTimeField(auto_now=True)
image = models.ImageField(upload_to='tiles/')
forms.py
class ImageTileForm(forms.ModelForm):
class Meta:
model = ImageTile
fields = ('image', )
views.py
if request.method == 'POST':
# Then we do image tiles
#if request.FILES:
image_form = ImageTileForm(request.POST, request.FILES)
if image_form.is_valid():
image_form.save()
template
<form enctype="multipart/form-data" method="post" action="">
{% csrf_token %}
{{ image_form.non_field_errors }}
{{ image_form.image.errors }}
{{ image_form.image.label_tag }}
{{ image_form.image }}
<button type="submit">Submit</button>
</form>
image_form.errors
django.forms.util.ErrorDict({'image': django.forms.util.ErrorList([u'Upload a valid image. The file you uploaded was either not an image or a corrupted image.' ])})
terminal output from doing it manually
>>> from scrapbook.models import ImageTile
>>> x = ImageTile(image=request.FILES['image'])
>>> x.save()
>>> x.id
2
>>> x.image
<ImageFieldFile: tiles/cathy_orange.jpg>
>>>
Problem was having a PIL install that didn't have jpeg support. Installed libjpeg and re-installed PIL and everything worked great.
Interesting that Django ModelForms validate this but the model does not. The model never threw an error until I tried to access the width/height attributes.

Upload Image to Blob using GAE + Django

I'm writing an application using GAE and Django in which I want to give to user the ability to upload his image. Also, I want this image be stored as blob on GAE's datastore. I have seen many examples but nothing specific to this scenario. Although, I feel that is a common issue.
All I want, is to create a new product and this new product must have an image.
1st Attempt: I have tried to add an image attribute (db.BlobProperty()) in product's model, and obviously django does not include it on the presented form.
2nd Attempt: I have created a new entity with two attributes (product as db.ReferenceProperty() and image as db.BlobProperty()). With this I tried to work parallel with django form modifying the django HTML form (including an |input type='file' name='img' /|) expecting that I could take the image from the request object but I failed once more.
This is the Product Class:
class Product(db.Model):
id = db.IntegerProperty()
desc = db.StringProperty()
prodCateg = db.ReferenceProperty(ProductCategory)
price = db.FloatProperty()
details = db.StringProperty()
image = db.BlobProperty()
This is the Django Form (HTML):
<form action="{%url admin.editProduct product.key.id%}" enctype="multipart/form-data" method="post">
<table>
{{form}}
<tr><td><input type="file" name="img" /></td></tr>
<tr><td><input type="submit" value="Create or Edit Product"></td></tr>
</table>
</form>
This is the Django Form (python):
class ProductForm(djangoforms.ModelForm):
class Meta:
model = Product
exclude = ['id']
This is the request handler:
def editProduct(request, product_id):
user = users.GetCurrentUser()
#if user is None:
# return http.HttpResponseForbidden('You must be signed in to add or edit a gift')
product = None
if product_id:
product = Product.get(db.Key.from_path(Product.kind(), int(product_id)))
if product is None:
return http.HttpResponseNotFound('No product exists with that key (%r)' %
product)
form = ProductForm(data=request.POST or None, instance=product)
##########################
# Ambitious undertaking! #
##########################
#if not product_id:
# uploadedImage = get("img")
# photo = Image()
# photo.product = product
# uploadedPhoto = request.FILES['img'].read()
# photo.image = db.Blob(uploadedPhoto)
# image.put()
if not request.POST:
return respond(request, user, 'addprod', {'form': form, 'product': product})
errors = form.errors
if not errors:
try:
product = form.save(commit=False)
except ValueError, err:
errors['__all__'] = unicode(err)
if errors:
return respond(request, user, 'addprod', {'form': form, 'product': product})
product.put()
return http.HttpResponseRedirect('/product')
As you can see the request handler is based on the Google's Gift-Tutorial
So, If anyone could put his opinion I would be very thankful!
Thank you in advance!
You may want to look at an example that uses the blobstore API with blobstoreuploadhandler and/or edit your request handler to store the uploaded file as a blobproperty or a blobreferenceproperty depending on if you use the blobstore API or just a blobproperty variable. You can be specific about http post data i.e. `
self.request.post('img').file.read()
I do recommend that you choose the blobstore API and blobstoreuploadhandler since that will do some very good things for you automatically: 1. storing MIM type and 2. storing filename 3. enabling serving via get_serving_url that has several advantages.