views:

1098

answers:

2

Hello! I have made a function that connects to a models 'pre_save' signal. Inside the function I am trying to check if the model instance's pk already exists in the table with:

sender.objects.get(pk=instance._get_pk_val())

The first instance of the model raises an error. I catch the error and generate a slug field from the title. In a second instance, it doesn't throw the error. I checked the value of instance._get_pk_val() on both instances and they are the same: None

So:

# This one raises an error in the sluggit function
instance1 = Model(title="title 1")
instance1.save()

# This one doesn't raise an error
instance2 = Model(title="title 2")
instance2.save()

This is my 3rd day messing around with python and django. So I am sorry if it something newbish that I am not seeing.

Edit:

The Model:

class Test(models.Model):
    title = models.CharField(max_length=128)
    slug = models.SlugField(max_length=128)
    slug.prepopulate_from=('title',)

signals.pre_save.connect(package.sluggit, sender=Test)

The Function Basics:

def sluggit(sender, instance, signal, *args, **kwargs):
    try:
        sender.objects.get(pk=instance._get_pk_val())
    except:
        # Generate Slug Code

@S.Lot told me to override the save() method in the comments. I'll have to try that. I would still like to know why the second call to model.objects.get() isn't raising an error with this method.

Edit 2 Thank you @S.Lot. Overriding the save method works perfectly. Still curious about the signal method. Hmm, weird.

Edit 3 After playing around a little more, I found that using instance.objects.get() instead of sender.objects.get() works:

def sluggit(sender, instance, signal, *args, **kwargs):
    try:
        sender.objects.get(pk=instance._get_pk_val())
    except:
        # Generate Slug Code

needs to be:

def sluggit(sender, instance, signal, *args, **kwargs):
    try:
        instance.objects.get(pk=instance._get_pk_val())
    except:
        # Generate Slug Code

A bug? For some reason I thought sender.objects.get() would be the same as Test.objects.get().

+1  A: 

S.Lott is correct... use save(), as you've already acknowledged that you have started doing.

As for the signal question, I can honestly see nothing wrong with your code. I've even run it locally myself with success. Are you sure that you're representing it properly in the question? Or that instance2 isn't already an existing database object (perhaps a goof in your test code)?

Jarret Hardie
I tried testing this in the manage.py shell. This is exactly what I tried:>>>from testing.models import Test>>>t1 = Test(title="a test title")>>>t1.save()>>>t1.slug'a-test-title'>>>t2 = Test(title="a test title")>>>t2.save()>>>t2.slug''
Matt
Wow, that's ugly. Hmm, I'll look over my code and see if I made a mistake.
Matt
I just noticed "prepopulate_from"... what version of django are you using? Failing that... what's the code in "Generate Slug Code"?
Jarret Hardie
I haven't written the actual code for that part yet. Right now it sets the slug to a static value: setattr(instance, 'slug', 'a-test-title'). django.VERSION 1,0,2 final
Matt
Well, I'm glad you have it working. I'm a little worried by your Edit 3, since the behaviour you're seeing is exactly backwards (your expectation is correct... and is what I see on my system) but it sounds like you're on a debugging trail, so I'm sure you'll figure it out.
Jarret Hardie
Thank you very much for your help. :)
Matt
A: 

Thanks for posting this. The top google results (at the time I'm posting this) are a little outdated and show the old way of connecting signals (which was recently rewritten, apparently). Your edits, with the corrected code snippets showed me how it's done.

I wish more posters edited their comments to place a fix in it. Thanks. :-)

hendrixski