tags:

views:

292

answers:

2

I've got a django Form which contains a dictionary of strings. I've given the form a submit button and a preview button. When the preview button is pressed after entering some information, a POST is sent, and the strings in the dictionary are automagically recovered (I assume that it's done using session state or something). This is great, exactly what I wanted.

The problem is that if I don't submit the form, then do a GET (i.e. browse to the page with the form on it), enter some info and hit preview, the information that was stored in the dictionary from the first preview is still there.

How do you clear this information?

The following is my form:

class ListingImagesForm(forms.Form):   
#the following should be indented
def clear_dictionaries(self):
    self.statuses = {}
    self.thumbnail_urls = {}
    self.image_urls = {}

statuses = {}
thumbnail_urls = {}
image_urls = {}

valid_images = SortedDict() #from the django framework
photo_0 = forms.ImageField(required=False, label='First photo')
photo_1 = forms.ImageField(required=False, label='Second photo')

def clean_photo_0(self):
    return self._clean_photo("photo_0")

def clean_photo_1(self):
    return self._clean_photo("photo_1")


def _clean_photo(self, dataName):
    data = self.cleaned_data[dataName]
    if data != None:
        if data.size > max_photo_size:
            raise forms.ValidationError("The maximum image size allowed is 500KB")
        elif data.size == 0:
            raise forms.ValidationError("The image given is empty.")
        else:
            self.valid_images[dataName] = data
            self.statuses[dataName] = True
            list_of_image_locs = thumbs.save_image_and_thumbs(data.name, data)
            self.image_urls[dataName] = list_of_image_locs[0]
            self.thumbnail_urls[dataName] = list_of_image_locs[1]
    return data

And here is the view:

@login_required
def add(request):
#the following should be indented
preview = False
added = False
new_listing = None
owner = None

if request.POST:
    form = GeneralListingForm(request.POST)
    image_form = ListingImagesForm(request.POST, request.FILES)

    if image_form.is_valid() and form.is_valid(): 
        new_listing = form.save(commit=False)
        new_listing.owner = request.user.get_profile()

        if request.POST.get('preview', False):
            preview = True
            owner = new_listing.owner

        elif request.POST.get('submit', False):
            new_listing.save()
            for image in image_form.image_urls:
                url = image_form.image_urls[image]
                try:
                    new_image = Image.objects.get(photo=url)
                    new_image.listings.add(new_listing)
                    new_image.save()
                except:
                    new_image = Image(photo=url)
                    new_image.save()
                    new_image.listings.add(new_listing)
                    new_image.save()

            form = GeneralListingForm()
            image_form = ListingImagesForm()
            image_form.clear_dictionaries() 
            added = True

else:
    form = GeneralListingForm()
    image_form = ListingImagesForm()
    image_form.clear_dictionaries()

return render_to_response('add_listing.html', {'form': form, 'image_form' : image_form, 
                                                'preview': preview, 'added': added,
                                                'owner': owner, 'listing': new_listing,
                                                'currentmaintab': 'listings',
                                                'currentcategory': 'all'},
                                                                        context_instance=RequestContext(request))

I haven't been programming with django or python all that long, so any pointers on fixing up some of the code is welcome :)

+2  A: 

I suspect your misunderstanding exactly what's going on here. Are you using generic views? Is the form subclassing ModelForm?

Andy Hume
No, we're not subclassing modelform, and nor are we using generic views
Louis Sayers
+2  A: 

This code is broken in concept; it will never do what you want it to. Your dictionaries are class attributes on the ListingImagesForm class. This class is a module-level global. So you're storing some state in a global variable in-memory in a webserver process. This state is global to all users of your application, not just the user who submitted the form, and will persist (the same for all users) until it's explicitly changed or cleared (or until you just happen to have your next request served by a different process/thread in a production webserver).

[EDIT: I used "global" here in an unclear way. Class attributes aren't "global", they are encapsulated in the class namespace just as you'd expect. But you're assigning attributes to the class object, not to instances of the class (which you'd do within an __init__() method). The class object is a module-level global, and it only has one set of attributes. Every time you change them, you're changing them for everyone. If you'd modify the above code so that your three dictionaries are initialized within the __init__() method, then your "cached data" "problem" would go away; but so would the "magical" persistence behavior that you wanted in the first place.]

You need to rethink your design with a clear understanding that Django doesn't "automagically" maintain any state for you across requests. All your state must be explicitly passed via POST or GET, or explicitly saved to a session. Class attributes on a Form class should be avoided except for immutable configuration-type information, and instance attributes are only useful for keeping track of temporary state while processing a single request, they won't persist across requests (a new instance of your Form class is created on each request).

Carl Meyer
Ok -thanks for explaining, I didn't realise that the attributes of ListingImagesForm were global, I'll have to look up the encapsulation rules :)
Louis Sayers
Sorry for being unclear; it's not really an encapsulation issue, it's about the difference between class attributes and instance attributes. I'll add an edit to try to clarify.
Carl Meyer
Thanks for explaining that. I'm glad that django doesn't have this 'magic' lol
Louis Sayers