Re: DRY violation using get_or_create with defaults

78 views
Skip to first unread message

Kurtis Mullins

unread,
Jun 11, 2012, 8:59:18 PM6/11/12
to django...@googlegroups.com
hmm, have you considered creating a custom Model Manager with a custom method for this purpose? I don't really have any ideas at the moment, sorry!

On Mon, Jun 11, 2012 at 9:44 AM, ojno <m...@jonathanfrench.net> wrote:
Hi all,

In my app, which involves doing background tasks and possibly rerunning them a number of times, I find myself using this pattern a lot:

instance, created = Model.objects.get_or_create(key1=key1, key2=key2,
                                                defaults={"field1":field1, "field2":field2})
if not created:
    instance.field1 = field1
    instance.field2 = field2
    instance.save()

This is unsatisfyingly WET. Does anyone know a better way to do this that still preserves all the integrity and lack of race conditions get_or_create gives you?

Thanks,
ojno

--
You received this message because you are subscribed to the Google Groups "Django users" group.
To view this discussion on the web visit https://groups.google.com/d/msg/django-users/-/6f0-bPejkBkJ.
To post to this group, send email to django...@googlegroups.com.
To unsubscribe from this group, send email to django-users...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/django-users?hl=en.

Jerome Baum

unread,
Jun 11, 2012, 11:44:31 PM6/11/12
to django...@googlegroups.com
Drop the "defaults" kwarg to get_or_create as apparently you're not using it. Also drop the conditional on those set/save statements.

Gelonida N

unread,
Jun 12, 2012, 4:44:41 AM6/12/12
to django...@googlegroups.com
On 06/12/2012 05:44 AM, Jerome Baum wrote:
> Drop the "defaults" kwarg to get_or_create as apparently you're not
> using it. Also drop the conditional on those set/save statements.
>
>

Wouldn't this create more db accesses than the original code?

Jerome Baum

unread,
Jun 12, 2012, 4:59:52 AM6/12/12
to django...@googlegroups.com
On 12 Jun 2012, at 10:44, Gelonida N wrote:

> On 06/12/2012 05:44 AM, Jerome Baum wrote:
>> Drop the "defaults" kwarg to get_or_create as apparently you're not
>> using it. Also drop the conditional on those set/save statements.
>>
>>
>
> Wouldn't this create more db accesses than the original code?

get_or_create causes one or two accesses (depending), and the save() call causes another (I think). Two scenarios:

1. Object existed already. Original code: get_or_create causes one access, save() another, for a total of two. New code: ditto.

2. Object didn't exist. Original code: get_or_create causes two access, no save() call, for a total of two. New code: get_or_create causes two accesses, save() another, for a total of three.

So yes one more call if the object didn't exist. But DRY.

Alternatively create a utility method to handle this. Example ("pseudo-code"):

def get_or_create_ensuring(qs=None, filters={}, ensure={}):
"""
get_or_create with defaults. If the object existed then change it.
"""
obj, created = qs.get_or_create(**filters, defaults=ensure)
if not created:
obj.__dict__.update(ensure)
obj.save()

You can also create a new query manager, though it won't work on all models. Alternatively a wrapping query manager (i.e. __init__ it based on an existing one).


.-.-.

--
No situation is so dire that panic cannot make it worse.
--
Please encrypt sensitive information before emailing it:
https://jeromebaum.com/pgp/encrypt.html
--
PGP: 2C23 EBFF DF1A 840D 2351 F5F5 F25B A03F 2152 36DA

Jonathan French

unread,
Jun 12, 2012, 7:51:53 AM6/12/12
to django...@googlegroups.com
On 12 June 2012 04:44, Jerome Baum <jer...@jeromebaum.com> wrote:
Drop the "defaults" kwarg to get_or_create as apparently you're not using it. Also drop the conditional on those set/save statements.

Ah, I should have made clear that some of the fields in defaults are NOT NULL, so it's necessary to pass them in defaults. That's the problem, really. I did start off by just doing get_or_create, set fields, save, with no conditional, but then some of the fields I needed to set started becoming NOT NULL.

I guess I'm probably going to have to create a custom manager or utility function. It's annoying since I use some other custom managers already, but oh well.

Thanks for all your suggestions.

- ojno

Sells, Fred

unread,
Jun 12, 2012, 9:58:34 AM6/12/12
to django...@googlegroups.com

My application is VERY low volume, so I just do this to KISS

 

        (resident, created) = models.Resident.objects.get_or_create(pk=resid, defaults=r)

        resident.__dict__.update(r)

        resident.save()

--

You received this message because you are subscribed to the Google Groups "Django users" group.

Reply all
Reply to author
Forward
0 new messages