I have a Django model called StaffSettings which contains various configuration options for users in my Django app. Each User has at most one entry in the StaffSettings table.
Assume that one setting is default_year_level, and I have code for my user objects like:
def set_default_year_level(u, year_level):
obj, _created = StaffSettings.objects.get_or_create(user=u)
obj.default_year_level = year_level
obj.save()
I would prefer the body of the function to fit onto one line because it seems like a common use case, but if I defined it as
def set_default_year_level(u, year_level):
StaffSettings.objects.filter(user=u).update(default_year_level=year_level)
which works fine if the user in question already has a row in the StaffSettings table, but it won't create the relevant row if it doesn't exist.
What is the idiomatic/best way to code this? (e.g. Is there some sort of filter_or_create
function? Or do other people write decorators/helper functions to handle this idiom?)
I don't see any problem with your first function, I would have written the same for this usecase.
However if you need the same feature on a lot of fields on your model and you don't want to repeat yourself you can pass the field as parameter :
def set_default_value(u, field, value):
obj, _created = StaffSettings.objects.get_or_create(user=u)
setattr(obj, field, value)
obj.save()
And I will stay away from the update() function anyway as this function is meant to update multiple objects at once and does not trigger the save() method nor signals on your models (see https://docs.djangoproject.com/en/dev/topics/db/queries/#updating-multiple-objects-at-once)
Since Django 1.7 you can use update_or_create()
:
def set_default_year_level(u, year_level):
obj, _created = StaffSettings.objects.update_or_create(
user=u,
default_year_level=year_level
)
Or, for a more generic case as explained in the previous answer:
def set_default_values(u, **kwargs):
obj, _created = StaffSettings.objects.update_or_create(user=u, defaults=kwargs)
which also achieves your additional requirement
I would prefer the body of the function to fit onto one line
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With