[Answer]-Alternative to global variables in Django?

0đź‘Ť

âś…

Thank you @PeterRowell for pointing me in the right direction. I used django sessions to store the filters, javascript to send a request to the server to update the filters when they load the form and to delete them when they leave the form, some view functions to handle those request, added a function to the model (with the request as a parameter) to update the filters per what parts where already saved, and override the changelist_view function of the PartAdmin to use the filters in request.session to modify the query string. That was a lot of code in a lot of different files, but here are some of the highlights that will hopefully help someone looking for a solution like this:

All the models posted in the question stayed pretty much the same.

The views for the PC:

def update_filters(request):
    try:
        # get POST data
        url = request.POST['form_url']
        id = url.split('/')[-2:-1][0]
        system_type = url.split('/')[-3:-2][0]

        if id is not "new":
            system_content_type = ContentType.objects.get(app_label="systems", model=system_type.rstrip('s'))
            system = system_content_type.get_object_for_this_type(id=id)
            system.set_filters(request)
        else:
            request.session['filters'] = ''
        return HttpResponse("Filters where updated.")
    except:
        return HttpResponse("Select a part and click 'Save and continue' to set the filters.")


def delete_filters(request):
    request.session['filters'] = ''
    return HttpResponse("Filters where deleted.")

Here is the javascript that was placed in the change_form.html (added it via the extra_context param in PcAdmin add_view and change_view functions)

    function post_to_url(path, params, method) {
        method = method || "post"; // Set method to post by default, if not specified.

        // The rest of this code assumes you are not using a library.
        // It can be made less wordy if you use one.
        var form = document.createElement("form");
        form.setAttribute("method", method);
        form.setAttribute("action", path);

        for(var key in params) {
            if(params.hasOwnProperty(key)) {
                var hiddenField = document.createElement("input");
                hiddenField.setAttribute("type", "hidden");
                hiddenField.setAttribute("name", key);
                hiddenField.setAttribute("value", params[key]);

                form.appendChild(hiddenField);
             }
        }

        var frame = document.createElement("iframe");
        frame.name="hidden-form";
        form.target="hidden-form";
        document.body.appendChild(form);
        document.body.appendChild(frame);
        form.submit();
    }

    // when they load the page, set the filters
    $(document).ready(function(){
        post_to_url("/quotegenerator/systems/update_filters/",{'form_url': document.URL});
    });

    // when they exit, delete the filter cookie
    window.onbeforeunload = function() {
        post_to_url("/quotegenerator/systems/delete_filters/", {});
    }

And finally, the function that was added to PartAdmin:

    def set_filters(self, request):
            # query and get the parts
            try:
                    cpu = self.cpuChoices.get()
            except:
                    cpu = False
            try:
                    mobo = self.motherBoardChoices.get()
            except:
                    mobo = False
            try:
                    mem = self.memoryChoices.get()
            except:
                    mem = False
            try:
                    hdd = self.hardDriveChoices.get()
            except:
                    hdd = False

           # for each combo of parts, figure out whats required
            # no parts at all
            if not (mobo or cpu or mem or hdd):
                    request.session['filters'] = ''
            # mobo only
            elif mobo and not (cpu or mem or hdd):
                    request.session['filters'] = 'socket='+mobo.socket
            # cpu only
            elif cpu and not (mobo or mem or hdd):
                    request.session['filters'] = 'socket='+cpu.socket
            # memory only
            elif mem and not (mobo or cpu or hdd):
                    request.session['filters'] = 'memType='+mem.memType
            # hard drive only
            elif hdd and not (mobo or cpu or mem):
                    request.session['filters'] = 'interface='+hdd.interface
            # mobo and cpu
            elif mobo and cpu and not (mem or hdd):
                    request.session['filters'] = 'memType='+mobo.memType+'&interface='+mobo.interface
            # mobo and memory
            elif mobo and mem and not (cpu or hdd):
                    request.session['filters'] = 'socket='+mobo.socket+'&interface='+mobo.interface
            # mobo and hd
            elif mobo and hdd and not (cpu or mem):
                    request.session['filters'] = 'socket='+mobo.socket+'&memType='+mobo.memType
            # cpu and mem
            elif cpu and mem and not (mobo or hdd):
                    request.session['filters'] = 'socket='+cpu.socket+'&memType='+mem.memType
            # cpu and hd
            elif cpu and hdd and not (mobo or mem):
                    request.session['filters'] = 'socket='+cpu.socket+'&interface='+hdd.interface
            # memory and hd
            elif mem and hdd and not (mobo or cpu):
                    request.session['filters'] = 'memType='+mem.memType+'&interface='+hdd.interface
            # mobo cpu and mem
            elif cpu and mobo and mem and not hdd:
                    request.session['filters'] = 'interface='+mobo.interface
            # mobo cpu and hd
            elif mobo and cpu and hdd and not mem:
                    request.session['filters'] = 'memType='+mobo.memType
            # mobo hd and mem
            elif mobo and mem and hdd and not cpu:
                    request.session['filters'] = 'socket='+mobo.socket
            # cpu mem and hd
            elif cpu and mem and hdd and not mobo:
                    request.session['filters'] = 'socket='+cpu.socket+'&memType='+mem.memType+'&interface='+hdd.interface
            # all parts
            else:
                    request.session['filters'] = ''

Oh, and the changelist_view function of PartAdmin did change a little:

def changelist_view(self, request, extra_context=None):
    if ('filters' in request.session):
        q = request.GET.copy()
        for filter in request.session['filters'].split('&'):
            key, value = urllib.splitvalue(filter)
            # check if the request does not already use the filter
            # and that the model has the attribute to filter for
            if (not request.REQUEST.has_key(key)) and (key in self.list_filter):
                q[key] = value
        request.GET = q
        request.META['QUERY_STRING'] = request.GET.urlencode()
    return super(PartAdmin,self).changelist_view(request, extra_context=extra_context)
👤Dan Mantyla

1đź‘Ť

This is not an answer, but rather a nudge in the right direction.

There are more variable contexts that local and global. In your case the context is user or perhaps build (if the user has multiple builds going simultaneously).

Note that the changelist_view() method takes a request object. From this you can get the user, the session (with an arbitrary amount of stuff hanging off of it), and all other manner of good state information.

One further observation: in a multi-threaded, multi-process web environment, there really is no “global” in the sense you are used to thinking about it. Although it’s possible to create a “global” in such an environment (e.g. using memcached), you’re going to have to work pretty hard at it.

👤Peter Rowell

Leave a comment