How to force order of pictures in a gallery - django

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.

Related

How to apply DEBUG to the django admin forms fields?

I am working with fields in a model in which the value of a field depend of a selected option in a previous field in a form (for the moment via django administrator), by which I am using django-smart-selects
I would share this video for a better understanding about of my question or situation and the reason about of ask the way of apply DEBUG or depuration in relation with the fields which I am working in this scenario.
The parent field Segmento afectado in the video let me select multiple choices
The child field Movimiento in the video, detail the movements that a affected segment (selected in the parent field) can perform
My situation about it
In the video is detailed of a way clear that when I select only a affected segment in the parent field, the options of movements are deployed in the child field, and my log console of Django Server appear the status code HTTP/1.1 200 with the GET operation, indicating to me that was possible get and deploy successfully the movements that correspond to the affected segment selected in the parent field
But, when I select more than one affected segment in the parent field (If I select two or more segments in forward), inmediately my django server at the console show me the status code HTTP/1.1 404 (Not Found in yellow color), because not perform the second selection or the second affected segment that the user select, and due to this reason also don't deploy or appear in the child field the movements associated that these second affected segment can perform
I don't know how to address this situation, due to this form in which are the parent (Segmento Afectado) and child (Movimiento) fields are represented inside the django administrator.
I have a model named AffectedSegment and another model named Movement and through of functionality of ChainedManyToManyField of django-smart-selects is the way in how to I get the values deployed in the child field accord to the selection in the parent field.
My models and the chaining of values for this behavior are:
class AffectedSegment(models.Model):
SEGMENTO_ESCAPULA = 'ESCAPULA'
SEGMENTO_HOMBRO = 'HOMBRO'
SEGMENTO_CODO = 'CODO'
SEGMENTO_ANTEBRAZO = 'ANTEBRAZO'
SEGMENTO_CARPO_MUNECA = 'CARPO_MUNECA'
SEGMENTO_MANO = 'MANO'
SEGMENTO_CHOICES = (
(SEGMENTO_ESCAPULA, u'Escápula'),
(SEGMENTO_HOMBRO, u'Hombro'),
(SEGMENTO_CODO, u'Codo'),
(SEGMENTO_ANTEBRAZO, u'Antebrazo'),
(SEGMENTO_CARPO_MUNECA, u'Carpo/Muñeca'),
(SEGMENTO_MANO, u'Mano'),
)
affected_segment = models.CharField(max_length=12, choices=SEGMENTO_CHOICES, blank=False, verbose_name='Segmento afectado')
class Meta:
verbose_name = 'Segmentos corporale'
def __str__(self):
return "%s" % self.affected_segment
class Movement(models.Model):
type = models.CharField(max_length=255,verbose_name='Tipo de movimiento')
corporal_segment_associated = models.ManyToManyField(AffectedSegment, blank=False, verbose_name='Segmento corporal asociado')
class Meta:
verbose_name = 'Movimiento'
def __str__(self):
return "%s" % self.type
And the way in which or I get that appear the movements in the child field accord to the selection on the parent field is perform of this way:
class RehabilitationSession(models.Model):
affected_segment = models.ManyToManyField(AffectedSegment,verbose_name='Segmento afectado')
movement = ChainedManyToManyField(
Movement, #Modelo encadenado
chained_field = 'affected_segment',
chained_model_field = 'corporal_segment_associated',
verbose_name='Movimiento'
)
class Meta:
verbose_name = 'Sesiones de Rehabilitación'
def __str__(self):
return "%s" % self.affected_segment
I don't know how to can I address this situation.
What another alternatives can I have?
JS, some framework forntend?
Another django app?
Any support, orientation about it, will be highly appreciated
:D
Just by briefly looking to your video and the code of "django-smart-select" application, I can see that this application was not meant to do what you are trying.
When you select only one option, the ending of your url looks like this:
"../RehabilitationSession/movement/4/"
But when you select two options, your url looks like this:
"../RehabilitationSession/movement/4,5/"
and then you get the 404 error.
Reason for you error lies in the fact that the application "django-smart-select" don't have an appropriate url pattern to deal with "4,5" block. For this to work, it would need to accept comma-separated integers and then have some kind of parser implemented in the app to filter your results by multiple conditions.
I cannot give you the complete answer, but I can tell you that you have few options:
If you have the skill, you can try and extend the mentioned app and implement the parser and url patterns yourself.
You can do the same thing in your admin class by overriding the query of your field based on the selection of the above field, but without jQuery tinkering, it wont have real-time changes.
You can try some other application, but I cannot guarantee that you will find a suitable solution for your problem.

Django + MySQL: performance on storing multiple foreign key

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

Customize ImageField url/path

I have a Page model that basically describes an HTML page. Pages are then served with URLs, such as http://www.mysite.com/page/1234/ for the page of id (pk) 1234.
I want to be able to add or attach images to my page. Therefore, I would like to use an Image class with a foreign key to a Page object:
class Page(models.Model):
title = ...
content = ...
class Image(models.Model):
page = models.ForeignKey(Page)
image = models.ImageField(...)
Here is my problem: I would like to deliver images to the client with urls of the form:
http://www.mysite.com/images/1234/image_name.jpg, i.e a URL that includes the page id. Also on the server, the paths should reflect the page structure: /path/to/media/images/1234/image_name.jpg
I don't know how to tackle this problem. On one hand, I would like to keep the features of an ImageField related to path formatting. For example when uploading two images with the same name, Django creates two paths ending with "image.jpg" and "image_2.jpg" or so to make the difference between both images.
On the other hand, the upload_to option has limited capability, and I don't know how to insert the page id in the path. Especially, some tricky cases such as uploading an image at the same time a page is created (using the same form), which means a page id should be generated before uploading the image.
Is it reasonably easy to make an image model that would behave as described above? If so, how do I have to modify the Image model to insert the page id in the image path?
I have seen the question Customize save path for ImageField, but it does not address the problem of primary key that might not be assigned.
Thanks.
Actually, a simple function passed as an upload_to parameter works, and there is no problem of non-existing id. So I guess that Django's default behaviour saves the image after saving the parent page model, as I wanted to.
In the Image model:
image = models.ImageField(upload_to=get_image_path)
with the following function:
def get_image_path(instance, filename):
return 'pics/' + str(instance.page.id) + '/' + filename

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.