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?

```python
class UpdatedSequence:
    def __init__(self, update_func):
        self.update_func = update_func
        self.restart = True

        self.data = None
        self.index = 0


    def __iter__(self):
        # we're our own iterator
        return self


    def __next__(self):
        # if we're iterating from the beginning, call the function
        # and cache the result
        if self.restart:
            self.data = self.update_func()
            self.index = 0

        try:
            datum = self.data[self.index]
        except IndexError:
            # we reached the limit, start all over
            self.restart = True
            raise StopIteration
        else:
            self.index += 1
            self.restart = False

        return 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:

```python
class TimedCache:
    '''A function wrapper that caches the result for a while.'''
    def __init__(self, f, timeout):
        self.f = f
        self.timeout = timeout
        self.last_executed = None
        self.cache = None
        self.__name__ = f.__name__ + ' (Cached %ds)' % 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.

