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)
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.
- [Answer]-Django-like no reverse for url
- [Answer]-Celery cannot import Schedules
- [Answer]-How to make serializer to accept id insted of url for related object.
- [Answer]-Error during syncdb django python