Reputation: 46
i write an action for class in admin.py
class YarnsAdmin(admin.ModelAdmin):
actions = [make_stockable_unstockable]
i want this action to change status vise versa of stockable for the product.
my try is:
def make_stockable_unstockable(self, request, queryset):
for product in queryset:
if product.stockable:
queryset.filter(id=product.id).update(stockable=False)
else:
queryset.filter(id=product.id).update(stockable=True)
self.message_user(request, "Position(s) were updated")
it works, but i think this takes a lot of resources. if anyone has an idea to optimize it?
Upvotes: 0
Views: 28
Reputation: 1662
Since Django 1.8, Conditional Expressions (SQL
's Case..When..
) are supported.
Thus the following django ORM single update statement should accomplish what you need
from django.db.models import Case, When, F, Q, BooleanField, Value
queryset.annotate(new_value=Case(
When(Q(stockable=False), then=Value(True)),
default=Value(False),
output_field=BooleanField()
)).update(stockable=F('new_value'))
it generates the following sql
UPDATE `yourmodel`
SET `stockable` = CASE WHEN `yourmodel`.`stocakble` = 0 THEN 1 ELSE 0 END
WHERE <queryset's filters>
for the record, here is the original, wrong solution I initially proposed
you could issue just two updates instead of looping:
queryset.filter(stockable=False).update(stockable=True)
queryset.filter(stockable=True).update(stockable=False)
which will flip the flag with two update statements
Upvotes: 1
Reputation: 7750
You can try to use the bulk update which fires single query for bunch of records instead of one query per record.
def make_stockable_unstockable(self, queryset):
queryset.filter(stockable=False).update(stockable=True)
queryset.filter(stockable=True).update(stockable=False)
Upvotes: 0