Django + MySQL: performance on storing multiple foreign key - django

I have two models Post and Item that hope to have their images field, which refer to instances of a model Image:
class Image(models.Model):
image = models.ImageField(upload_to='images')
The first approach I can think of is to add a TextField to both Post and Item, and store the image_instance.image.urls of Image instances, so each time I want to display all images of an item or post, I obtain the item.images and split the string into an array, and all the urls are there.
The second approach is to add post and item field to the Image model as nullable foreign key field. So each time I want to display all images of a post or item, I do something like Image.objects.filter(item=some_item_instance), and extract .image.url.
I wonder which approach is better in practice, Or there are other better approaches?

Just use a ManyToManyField to store the relationship between a Post (or Item) and an Image and then iterate across that. Have models.py like so:
class Image(models.Model):
image = models.ImageField(upload_to='images')
class Post(models.Model):
body = models.TextField()
images = models.ManyToManyField(Image)
And elsewhere, pull the set of images from a Post instance and iterate across that:
my_post = Post.objects.first()
for image in my_post.images:
print image.url

Related

how to delete forien-key Imagefield in django?

I am already using django-cleanup. But it works when imagefield was deleted.
If imagefield is realted to a model like below.
As long as I don't delete imagefield manually, It can't be working.
from django.db import models
class Listing(models.Model):
title = models.CharField(max_length=25)
class ListingImages(models.Model):
listing = models.ForeignKey(Listing, default=None)
image = models.ImageField()
Listing can have many images which isn't fixed quantities. So I implemented like that.
But now I have a problem with how I can find which image should be deleted.
Lazy algorithm is just iterate every image data when post or put request.
and delete not matched image which is related to Listing object.
But it's too expensive I think.
Is there any good solution? I was searching that 'delete foreign key image in django' this keyword. But there is no solution for me.
You can use your primary key id of ListingImages model with DELETE method to remove it. Django provides handy CRUD operations.
What you mentioned in your comment was correct. Proceed with pk it should work.

Uploading multiple images with Django

I am working on a Django app and am having some trouble with the models/forms/templates required to upload images. I have a post and I want there to be a One-to-Many relationship with posts and images. i.e. A post can have any number of images. My first question is - what would the model look like? I am guessing something like:
class Image(models.Model):
img = models.ImageField(upload_to="photos/",null=True, blank=True)
posting = models.ForeignKey(Posting, related_name="images")
class Posting(models.Model):
...
Is this correct? And my other question is how should I upload multiple images? And I can't figure out what the form should look like. If I want to set a max number of images, could I just go like:
class ImageForm(forms.ModelForm):
img1 = forms.ImageField()
img2 = forms.ImageField()
class Meta:
model = Image
fields = ('img1','img2',)
But then I have no idea how to look that up to the view correctly. I am super lost, any help would be greatly appreciated!
For this task you should use the inline formsets. Read this docs first for basic understanding of the formsets.
The models in your question are almost valid. Remove the null=True, blank=True arguments from the img field - there is no sense in the Image instances without image itself.

Non-model field in Django model

I would like to have a model in Django that has multiple pictures associated with it. I'm evaluating possible options.
One picture for one model is easily done with the models.ImageField(...).
However, I would like a array (or set) of pictures. It can be just paths, not necessarily ImageField objects.
The problem is, how do I create that field in a Django model? I am assuming I will need to create a field that is not part of models.WhateverField. Is that possible? Can I define a non-model field, such as:
class MyModel:
name = models.CharField(max_length=10)
picture_list = []
and then do:
def sample_add_picture_view(request):
picture = "sample.jpg"
model = MyModel.objects.get(id=sample_id)
model.picture_list.append(picture)
model.save()
return HttpResponseRedirect('index.html')
Could this be done? If not, what could be a better solution? Thank you !
You need to create two separate models and link them with a ForeignKey field, like so:
class Item(models.Model):
name = models.CharField(max_length=255)
class ItemImage(models.Model):
image = models.ImageField(upload_to="item_images")
item = models.ForeignKey('Item', related_name="images")
It is possible to make a custom field to store multiple items, but it's a really bad idea. You would have to serialise an array into the database, making maintenance very difficult. Using a separate model means you can store extra information such as upload times, image captions etc with little extra effort.

How to bind an image to an edit form in Django?

I have the following Model:
class Listing(models.Model):
name = models.CharField(max_length=50, verbose_name="Title")
images = models.ManyToManyField('Image')
, with the ManyToManyField linking to this Image class:
class Image(models.Model):
thumb = ImageField(upload_to='images/uploads/')
number = models.PositiveSmallIntegerField()
and a corresponding ModelForm like so:
class ListingEditForm(ModelForm):
image1 = ImageField(required=False, label="Photo 1")
image2 = ImageField(required=False, label="Photo 2")
image3 = ImageField(required=False, label="Photo 3")
class Meta:
model = Listing
exclude = ('images')
The idea is to not limit the number of images that can be associated with a Listing in the backend, but at this time I only need 3 images in the form. Uploading the images works fine, but how would you go about binding the form to a Listing instance so that the images are not 'None' when one views the edit form?
Obviously, this alone won't work, because image1, image2 and image3 are only form fields, and not part of the model:
form = forms.ListingEditForm(instance=listing)
So adding a dictionary as the first parameter seems like the obvious thing to do:
form = forms.ListingEditForm({'image1': ...},instance=listing)
but what should the value of that ... be? And how do I retrieve it from the Listing instance?
I'll answer my own question, even though it's not quite the answer I was looking for. I've looked around, and as far as I know, there is no reliable way in HTML to change the contents of a File input field. So, I could be wrong, but even if you send that information with the request, Django will have no way of showing the information in the field (since it doesn't correspond to a file on the local PC).
So, my solution is simply to send the urls of the images with the request, as one normally would:
return render_to_response('edit.html', {'image1': image1_url, ...})
Then, if this information is present, I use jQuery to place the images next to the file input field in the template, and update it if the user selects a new file. It's not the best, but it works.
I'll still be glad to hear any other solutions.
I would use foreign key relation in Image, and inlineformset_factory for generating the form.
ListingEditForm = inlineformset_factory(Listing, Image, max_num=3, extra=0)
I would also add image name field in Image model. That way user will have indication of uploaded files in form display, and he will also be able to delete images if he whishes so. If you need unlimited uploads you can simply change max_num to 0 and extra to 1.
Of course that way you cannot associate one image with more then one Listing object, but if you need user to be able to delete images that is not recommended anyway.

How to force order of pictures in a gallery

I'm building a django app that has an image gallery, and the client insists the images be displayed in specific order. I use the admin interface to upload the images and edit their properties, and I have an ImageFile class in my model that basically looks like this:
class ImageFile(models.Model):
"""represents an image file"""
# the image description
description = models.CharField(max_length=45)
# the actual image
image = models.ImageFile(upload_to='images')
# running number representing the order on the page
order = models.IntegerField()
def __unicode__(self):
return "%s" % (self.description)
class Meta:
db_table = 'images'
I'm using the IntegerField 'order' to have running number that'll control the sorting. I figured there has to be a smarter/better way to do this (another model?) and also be able to easily control it through the admin interface.
I suppouse you would like give possibility to sort images to user, (anyway if you want sort it via time add, best way is order it by id), so, if there is model like Gallery (of images) maybe you should store tuple of ids of images from the galery (in DB as a text object). After read cast it to tuple, and you have expected order. Hope I help.
if the order of the images is the order that they are uploaded you could use a timestamp to order them,.
I used the same method (with integer "order" field in the model) to define the ordering. However, I customized the admin to allow drag and drop the images belong to an album to define the order. When the admin hits "save" button, the order will be calculated automatically based on the current order after drag-and-drop. All data will be submitted to the server for saving to DB.