Unkle UU
Unkle UU

Reputation: 46

Action vise versa in Admin Django

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

Answers (2)

zsepi
zsepi

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

Siva Arunachalam
Siva Arunachalam

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

Related Questions