Accessing model instance on pre_save signal

80 views
Skip to first unread message

neridaj

unread,
Nov 24, 2009, 8:52:02 PM11/24/09
to Django users
Hello,

I'm trying to change the upload_to attribute of an ImageField so that
it is in the format "web_projects/year/slug/". The problem I am having
is that the ForeignKey model is getting saved before the related
ScreenShot model is able to call it's save method to change upload_to.
I'm trying to use a pre_save signal to reverse the order of saving but
I'm not sure how to access the current instance of the ScreenShot
model to call it's save method. Thanks for any suggestions.


class ScreenShot(models.Model):
project = models.ForeignKey(WebProject)
image = models.ImageField(upload_to="web_projects/%Y/")
page_title = models.CharField(max_length=250, help_text="Maximum 250
characters.")

def __unicode__(self):
return self.page_title

def save(self):
self.image.upload_to="web_projects/%Y/"+self.project.slug
super(ScreenShot, self).save()


def change_upload_to(sender, **kwargs):
s = ScreenShot() # not sure how to access current instance
s.save()

pre_save.connect(change_upload_to, sender=WebProject)

Tim Valenta

unread,
Nov 24, 2009, 9:21:49 PM11/24/09
to Django users
I think the answer is just in the documentation on the method:

http://docs.djangoproject.com/en/dev/ref/signals/#django.db.models.signals.pre_save

No worries though. Signals are such a strangely uncovered topic in
the main tutorials, and aren't easy to find documentation for unless
you know what you're after.

It'll be in kwargs['instance']

Tim

Preston Holmes

unread,
Nov 25, 2009, 12:46:35 PM11/25/09
to Django users
I'm a bit confused on a few points here. The upload_to field
attribute should be atomic to the imagefield - it doesn't rely on
related models.

your change_upload_to creates a new screenshot - but doesn't connect
it to the current WebProject instance. Is that what you are trying to
do?

s = ScreenShot(project=instance)

Is there a reason your WebProject is not defined when you create a
screenshot in your view?

Something about this seems like it is making it more complicated than
it needs to be. but details are lacking t

-Preston

neridaj

unread,
Nov 25, 2009, 2:08:36 PM11/25/09
to Django users
I'm trying to access the current instance of ScreenShot related to the
current instance of WebProject, in order to get the slug field of
WebProject to use as a upload directory but I don't think I can
because there's no primary key in the db yet. I need to call
change_upload_to when the instance of WebProject tries to save because
it saves before the instance of ScreenShot i.e., before slug is
obtained to append to the upload_to directory. Are you suggesting I
should just add the ImageField to the WebProject class? I don't want
to have a fixed number of ImageFields for WebProject, if there's a way
to do that without using another class that would work. Can I access
the save method of ScreenShot from WebProject? Should I just add
another slug field to ScreenShot?

class ScreenShotInline(admin.StackedInline):
model = ScreenShot
extra = 3

class WebProjectAdmin(admin.ModelAdmin):
prepopulated_fields = {'slug': ('title',)}
inlines = [ScreenShotInline]

Tim Valenta

unread,
Nov 25, 2009, 4:48:52 PM11/25/09
to Django users
I know how messed up this all seems, so I sympathize. I totally want
to store items according to a related object's name or id or whatever.

However, I'm using upload_to in a more straightforward manner, and it
seems to work out alright. Tell me if you've already tried it this
way:

class ScreenShot(models.Model):
def _image_location(instance, filename):
return ''.join("web_projects/%Y/", instance.project.slug,
"/", filename)
# ...
image = models.ImageField(upload_to=_image_location)

The thing you pass to your field's "upload_to" value can be a
callable, which takes two arguments: the instance of `ScreenShot`
being altered, and the filename of the original file that was
uploaded. You then just return a string of the path to save in,
including the filename.

It's all described here, which it looks like you've already read:
http://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models.FileField.upload_to

Does that not work for you? I do exactly the same thing for various
fields on some of my models. I could see how it might complicate
things if you were doing it on an inline..... I admit that I haven't
tried that one out, as luck would have it. If the main model already
exists, it should work, though.

Just brainstorming to find a simpler solution. Have you already tried
it that way?

Tim

neridaj

unread,
Nov 25, 2009, 5:42:04 PM11/25/09
to Django users
Thanks Tim. That's funny you just posted that because I just got done
doing that and was going to post it as solved.

Cheers,

J

On Nov 25, 1:48 pm, Tim Valenta <tonightslasts...@gmail.com> wrote:
> I know how messed up this all seems, so I sympathize.  I totally want
> to store items according to a related object's name or id or whatever.
>
> However, I'm using upload_to in a more straightforward manner, and it
> seems to work out alright.  Tell me if you've already tried it this
> way:
>
>     class ScreenShot(models.Model):
>         def _image_location(instance, filename):
>             return ''.join("web_projects/%Y/", instance.project.slug,
> "/", filename)
>         # ...
>         image = models.ImageField(upload_to=_image_location)
>
> The thing you pass to your field's "upload_to" value can be a
> callable, which takes two arguments: the instance of `ScreenShot`
> being altered, and the filename of the original file that was
> uploaded.  You then just return a string of the path to save in,
> including the filename.
>
> It's all described here, which it looks like you've already read:http://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.mod...
Reply all
Reply to author
Forward
0 new messages