简体   繁体   中英

Django model operating on a queryset

I'm new to Django and somewhat to Python as well. I'm trying to find the idiomatic way to loop over a queryset and set a variable on each model. Basically my model depends on a value from an api, and a model method must multiply one of it's attribs by this api value to get an up-to-date correct value.

At the moment I am doing it in the view and it works, but I'm not sure it's the correct way to achieve what I want. I have to replicate this looping elsewhere.

Is there a way I can encapsulate the looping logic into a queryset method so it can be used in multiple places?

NOTE: the variable I am setting on each model instance is just a regular attribute, not saved to db. I just need to be able to set that variable, not save it.

I have this atm (I am using django-rest-framework):

class FooViewSet(viewsets.ModelViewSet):
    model = Foo
    serializer_class = FooSerializer

    bar = # some call to an api

    def get_queryset(self):
        # Dynamically set the bar variable on each instance!
        foos = Foo.objects.filter(baz__pk=1).order_by('date')
        for item in foos:
            item.needs_bar = self.bar

        return items

I would think something like so would be better:

def get_queryset(self):
    bar = # some call to an api
    # Dynamically set the bar variable on each instance!
    return Foo.objects.filter(baz__pk=1).order_by('date').set_bar(bar)

I'm thinking the api hit should be in the controller and then injected to instances of the model, but I'm not sure how you do this. I've been looking around querysets and managers but still can't figure it out nor decided if it's the best method to achieve what I want.

Can anyone suggest the correct way to model this with django?

Thanks.

You can set some new properties on queryset items, but they will not update database (will be saved just in local namespace). I suppose that you want to recalculate field of your model multiplying it by some value:

class Foo(models.Model):
     calculated_field = models.BigIntegerField(default=0)

def save(self, *args, **kwargs):
    if self.pk is not None:  # it's not a new record
       foo = kwargs.get('foo')
       if foo:
           self.calculated_field = self.calculated_field * int(foo)
    super(Foo, self).save(*args, **kwargs) # Call the "real" save() method.


 def get_queryset(self):
        bar = # some call to an api
        # Dynamically set the bar variable on each instance!
        foos = Foo.objects.filter(baz__pk=1).order_by('date')
        for item in foos:
            item.save(foo=bar)
       # return updated data
       return Foo.objects.filter(baz__pk=1).order_by('date')

At some point you might need to use transactions if you will run this code simultaneously.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM