2

I have noticed a weird behavior in one of my Django applications, running with apache/mod_wsgi. There is a screen that displays a form, basically a dropown list with a list of availability to schedule a given site, computed from the difference between a given weekly capacity (3 sites/wk) and the total number of sites already scheduled at a given week.

This form (ScheduleForm) is rendered from following view (followup/views.py):

def schedule(request, site_id):
    site = Site.objects.get(pk=site_id)
    if request.method == 'POST':
        form = ScheduleForm(request.POST)
        if form.is_valid():
            (year, week) = request.POST['available_slots'].split('/')
            site.scheduled = week2date(int(year), int(week[1:]))
            site.save()
            return HttpResponseRedirect('/stats/')
    else:
        form = ScheduleForm()

    return render_to_response('followup/schedule_form.html',{
            'form': form,
            'site': site
        }, context_instance=RequestContext(request))

Here is the form class (followup/forms.py):

class ScheduleForm(forms.Form):
    """
    Temporary lists
    """
    schedules = Site.objects.filter(
            scheduled__isnull=False
        ).values('scheduled').annotate(Count('id')).order_by('scheduled')
    integration = {}
    available_integration = []

    # This aggregates all schedules by distinct weeks
    for schedule in schedules:
        if schedule['scheduled'].strftime('%Y/W%W') in integration.keys():
            integration[schedule['scheduled'].strftime('%Y/W%W')] += schedule['id__count']
        else:
            integration[schedule['scheduled'].strftime('%Y/W%W')] = schedule['id__count']

    for w in range(12): # Calculates availability for the next 3 months (3months*4 weeks)
        dt = (date.today() + timedelta(weeks=w)).strftime('%Y/W%W')
        if dt in integration.keys():
            capacity = 3-integration[dt]
        else:
            capacity = 3

        if capacity>0:
            available_integration.append([dt, capacity])

    """
    Form
    """
    available_slots = forms.ChoiceField(
        [[slot[0], '%s (%s slots available)' % (slot[0], slot[1])] for slot in available_integration]
    )

class IntegrateForm(forms.Form):
    integrated_on = forms.DateField(widget=AdminDateWidget())

This actually works fine but the only problem is that the list of availability is not refreshed when a site is scheduled, unless I restart the apache process each time I schedule a site.

It's like if the availability list would be cached by the form class...

Any idea would be warmly welcomed. Thank you in advance for any kind of help.

Sebastien Damaye
  • 385
  • 2
  • 15
  • Sebastien I edited your question to include your corrected form. If you have the time please delete your answer, since it should be an `edit` in your original question. – rantanplan Nov 09 '12 at 11:01
  • @Sebastien please see [here](http://meta.stackexchange.com/q/155173/155556) for why your answer was undeleted. – Naftali Nov 09 '12 at 15:20

2 Answers2

3

This has to do with how python works and not django.

This code below

class ScheduleForm(forms.Form):
    """
    Temporary lists
    """
    schedules = Site.objects.filter(
            scheduled__isnull=False
        ).values('scheduled').annotate(Count('id')).order_by('scheduled')
    integration = {}
    available_integration = []

will be evalutated only once - when the server starts.

You shouldn't do these things on the class level, but on the instance level. Most likely inside the __init__ method of your form.

See the examples below:

Community
  • 1
  • 1
rantanplan
  • 7,283
  • 1
  • 24
  • 45
2

I have modified my code as follows and it's now working like a charm :) I provide it here in case it helps anyone with a similar problem.

class ScheduleForm(forms.Form):
    available_slots = forms.ChoiceField()

    def __init__(self, *args, **kwargs):
        super(ScheduleForm, self).__init__(*args, **kwargs)

        schedules = Site.objects.filter(
                scheduled__isnull=False
            ).values('scheduled').annotate(Count('id')).order_by('scheduled')
        integration = {}
        available_integration = []

        # This aggregates all schedules by distinct weeks
        for schedule in schedules:
            if schedule['scheduled'].strftime('%Y/W%W') in integration.keys():
                integration[schedule['scheduled'].strftime('%Y/W%W')] += schedule['id__count']
            else:
                integration[schedule['scheduled'].strftime('%Y/W%W')] = schedule['id__count']

        for w in range(12): # Calculates availability for the next 3 months (3months*4 weeks)
            dt = (date.today() + timedelta(weeks=w)).strftime('%Y/W%W')
            if dt in integration.keys():
                capacity = 3-integration[dt]
            else:
                capacity = 3

            if capacity>0:
                available_integration.append([dt, capacity])

        self.fields['available_slots'].choices = [[slot[0], '%s (%s slots available)' % (slot[0], slot[1])] for slot in available_integration]
Sebastien Damaye
  • 385
  • 2
  • 15