At work I'm writing an API using Django/DRF. Suddenly I had to write an
application (just a few pages for calling a few endpoints), so I (ab)used DRF's
Serializer
s to build them. One of the problems I faced while doing this was
that DRF's ChoiceField
accepts only a sequence with the values for the
dropdown, unlike Django's, who also accepts callables. This means that once you
gave it a set of values, it never ever changes, at least until you restart
the application.
Unless, of course, you cheat. Or hack. Aren't those synonyms?
classUpdatedSequence:def__init__(self, update_func):
self.update_func = update_func
self.restart =True
self.data =None
self.index =0def__iter__(self):# we&aposre our own iteratorreturn self
def__next__(self):# if we&aposre iterating from the beginning, call the function# and cache the resultif self.restart:
self.data = self.update_func()
self.index =0try:
datum = self.data[self.index]exceptIndexError:# we reached the limit, start all over
self.restart =TrueraiseStopIterationelse:
self.index +=1
self.restart =Falsereturn datum
This simple class tracks when you start iterating over it and calls the function
you pass to obtain the data. Then it iterates over the result. When you reach
the end, it marks it to start all over, so the next time you iterate over it, it
will call the function again. The function you pass can be the all()
method of
a QuerySet
or anything else that goes fetch data and returns an iterable.
In my case in particular, I also added a TimedCache
so I don't read twice the
db to fill two dropdown with the same info in the same form:
classTimedCache:&apos&apos&aposA function wrapper that caches the result for a while.&apos&apos&aposdef__init__(self, f, timeout):
self.f = f
self.timeout = timeout
self.last_executed =None
self.cache =None
self.__name__= f.__name__+&apos (Cached%ds)&apos% timeout
def__call__(self):
now = time.monotonic()if self.cache is None or(now - self.last_executed) > self.timeout:
self.cache = self.f()
self.last_executed = now
return self.cache
I hope this helps someone.