views:

130

answers:

2

I'm developing a portfolio application. Within this application, I have a model called "Project" which looks something like this:

class Project(models.Model):
    ... 
    images = models.ManyToManyField(Image)
    ...

so, basically, this Project can contain a set of images (any of these images may belong to another Project as well).

Now, what I'd like to add is a way of specifying that one of these "images" is a "lead_image".

So I could add something like this:

class Project(models.Model):
    ... 
    images = models.ManyToManyField(Image, related_name='images')
    lead_image = models.ForeignKey(Image, related_name='lead_image')
    ...

However, the problem with this is that in this case, lead_image can be ANY image. What I really want is for it to be one of the "images" that belongs to to this model instance.

I'm thinking that I need to use "ForeignKey.limit_choices_to" argument, but I'm unsure of how to use this...especially since when the model instance is first created, there won't yet be any images in the "images" directory.

Any help would be greatly appeciated.

Doug

+2  A: 

Another approach to your problem is to use a intermediate table with a boolean property 'is_lead_image'.

class Image(models.Model):
    ...

class Project(models.Model):
    images = models.ManyToManyField(Image, through='ProjectImage')
    ...

class ProjectImage(models.Model):
    image = models.ForeignKey(Image)
    project = models.ForeignKey(Project)
    is_lead_image = models.Boolean(default=False)

    def save(self, *args, **kwargs):
        if self.is_lead_image:
            self._default_manager.filter(project=self.project).update(is_lead_image=False)
        return super(ProjectImage, self).save(*args, **kwargs)

*Note: If you like and if you have access you can also just add the is_lead_image field and the save directly to the Image class.

Jason Christa
Interesting. I will try this out.
Douglas
+1  A: 

If you're wanting to achieve the limiting effect in the admin tool, you can override the formfield-for-foreignkey method and insert your own filter.

class ProjectAdmin(admin.ModelAdmin):

    # ...

    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        if db_field.name == "lead_image":
            kwargs["queryset"] = self.model.images.all()
            return db_field.formfield(**kwargs)
        return super(ProjectAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)

The problem I see here (with this general idea of only picking from picked images) is that for new models, initially model.images won't be set when the page loads. You'll probably face this problem no matter what server-side trick you go with.

It could work, but it requires an extra click: When the model is first created the ManyToMany model.images will be picked. After picked, if "Save and Continue" is clicked, then those images should appear in the model.lead-image FK field.

Your other option would be to override the default admin form and create something custom (custom as in custom fancy-pants javascript to auto-update the 'lead image' field combo box).

T. Stone
Thanks. This seems like a good way to go. I don't think there is an 'ideal' solution for this.
Douglas