django dynamic Q objects in generic view - django

I want to be able to pass a variable caught in the URL to a Q object for a generic view.
I created a generic view which is imported as my_views.view which handles things like pagination, sorting, filtering etc...
I need to use Q objects because for some pages there will need some OR filters. Each page will also be filtering based on different fields (and models) (hence the generic view).
Example:
view_customers_info = {
"queryset" : Customer.all(),
'qobject': Q(status=stat),
"extra_context" : {
"title" : 'View Customers',
},
'template_name': 'customer/view.html',
}
urlpatterns = patterns('',
url(r'^customer/(?P<stat>\w+)/$', my_views.view, view_customers_info),
)
In this example, this line complains about stat not being a global name:
'qobject': Q(status=stat),
How can I pass the variable caught in the URL to the dictionary view_customers_info?
I can't simply move that Q object into the generic view because other pages will have Q objects like the following:
'qobject': (Q(type=type) | Q(status=stat)),
Thanks.

I think you can only do this by wrapping the generic view with a custom view/function. See also here:
http://docs.djangoproject.com/en/1.1/topics/generic-views/#complex-filtering-with-wrapper-functions

I think your just missing the quotes around the field name.
'qobject': Q(status=("%s" % stat)),

Related

Django: How to access the model id's within an AJAX script?

I was wondering what is the correct approach,
Do I create HiddenInput fields in my ModelForm and from the
View I pass in the primaryKey for the models I am about to edit into
the hiddenInput fields and then grab those hiddenInput fields from
the AJAX script to use it like this?
item.load(
"/bookmark/save/" + hidden_input_field_1,
null,
function () {
$("#save-form").submit(bookmark_save);
}
);
Or is there is some more clever way of doing it and I have no idea?
Thanks
It depends upon how you want to implement.
The basic idea is to edit 1. you need to get the existing instance, 2. Save provided information into this object.
For #1 you can do it multiple ways, like passing ID or any other primary key like attribute in url like http://myserver/edit_object/1 , Or pass ID as hidden input then you have to do it through templates.
For #2, I think you would already know this. Do something like
inst = MyModel.objects.get(id=input_id) # input_id taken as per #1
myform = MyForm(request.POST, instance=inst)
if myform.is_valid():
saved_inst = myform.save()
I just asked in the django IRC room and it says:
since js isn't processed by the django template engine, this is not
possible.
Hence the id or the object passed in from django view can't be accessed within AJAX script.

Django: grabbing parameters

I'm having the hardest time with what should be super simple. I can't grab the passed parameters in django.
In the browser I type:
http://localhost:8000/mysite/getst/?term=hello
My url pattern is:
(r'^mysite/getst/$', 'tube.views.getsearchterms')
My View is
def getsearchterms(request):
my_term = some_way_to_get_term
return HttpResponse(my_term)
In this case it should return "hello". I am calling the view, but a blank value is returned to me. I've tried various forms of GET....
What should some_way_to_get_term be?
The get parameters can be accesses like any dictionary:
my_term = request.GET['term']
my_term = request.GET.get('term', 'my default term')
By using arbitrary arguments after ? and then catching them with request.GET['term'], you're missing the best features of Django urls module : a consistent URL scheme
If "term" is always present in this URL call it must be meaningful to your application,
so your url rule could look like :
(r'^mysite/getst/(?P<term>[a-z-.]+)/', 'tube.views.getsearchterms')
That means :
That you've got a more SEO-FRIENDLY AND stable URL scheme (no ?term=this&q=that inside)
That you can catch your argument easily in your view :
Like this
def getsearchterms(request,term):
#do wahtever you want with var term
print term

Django: Passing data to view from url dispatcher without including the data in the url?

I've got my mind set on dynamically creating URLs in Django, based on names stored in database objects. All of these pages should be handled by the same view, but I would like the database object to be passed to the view as a parameter when it is called. Is that possible?
Here is the code I currently have:
places = models.Place.objects.all()
for place in places:
name = place.name.lower()
urlpatterns += patterns('',
url(r'^'+name +'/$', 'misc.views.home', name='places.'+name)
)
Is it possible to pass extra information to the view, without adding more parameters to the URL? Since the URLs are for the root directory, and I still need 404 pages to show on other values, I can't just use a string parameter. Is the solution to give up on trying to add the URLs to root, or is there another solution?
I suppose I could do a lookup on the name itself, since all URLs have to be unique anyway. Is that the only other option?
I think you can pass a dictionary to the view with additional attributes, like this:
url(r'^'+name +'/$', 'misc.views.home', {'place' : place}, name='places.'+name)
And you can change the view to expect this parameter.
That's generally a bad idea since it will query the database for every request, not only requests relevant to that model. A better idea is to come up with the general url composition and use the same view for all of them. You can then retrieve the relevant place inside the view, which will only hit the database when you reach that specific view.
For example:
urlpatterns += patterns('',
url(r'^places/(?P<name>\w+)/$', 'misc.views.home', name='places.view_place')
)
# views.py
def home(request, name):
place = models.Place.objects.get(name__iexact=name)
# Do more stuff here
I realize this is not what you truly asked for, but should provide you with much less headaches.

Pass session data onto URL

I have some information that is set in the sessions, and I was wondering if it's possible to pass this info onto the URL for the view that uses this session data. I want this to be working in such a way that if the user bookmarks the page from that view, the session data is used to pass the variables onto the view. How can I do this?
I'm having a filter view so I want the currently selected filters displayed on the URL...sorta like www.mysite.com/filter1/filter2/filter3/ then if filter2 is cleared I'll have www.mysite.com/filter1/filter3/
Currently my URLConf for the filter view looks like this:
(r'^filter/$', 'filter'),
(r'^filter/(?P<p>\d{2})/$', 'filter'),
As you say, propagate the data on the url, rather than in session. But use the query-string - not the path, as you seem to suggest in your question.
There is no magic way to do this - you'll have to manually append the variables to all urls. You can however wrap the url-creation in a function, to make this more manageable. Eg.:
$GLOBALS['url_state'] = array();
function url($base, $params = array()) {
global $url_state;
$q = http_build_query(array_merge((array) $url_state, $params));
return $q ? "$base?$q" : $base;
}
function define_url_state($name, $default = null) {
global $url_state;
if (isset($_GET[$name])) {
$url_state[$name] = $_GET[$name];
} elseif ($default !== null) {
$url_state[$name] = "$default";
}
}
If you use this to build all your urls in the application, you can now easily make a variable "sticky". Eg. at the top of your page, you could use it like this:
define_url_state('page', 1);
And further down the page, you can generate urls with url(). You would then get either the default value (1) or whatever the user passed to the page's $_GET.
In django you don't use $_GET, but request.GET
lets say your url is http://example.com?filter=filter1&filter=filter2&filter=filter5
you can get the filter names in a view using getlist() like this:
def some_view(request):
filters = request.GET.getlist('filter')
so you URL conf (urls.py) will look something like this:
from django.conf.urls.defaults import *
urlpatterns = patterns('',
url(r'^filters/$', 'your_app.views.some_view', name='filter_view'),
)

Adding more CoC to Django

I come from a Cake background, and I'm just starting to learn Django now. I'm liking it quite a bit, but I kinda wish it used convention over configuration like cake does. So,
How can I get Cake-style URLs automatically? For example, if I went to mysite.com/posts/view/5 it would load up mysite.posts.views.view and pass an argument 5 to it? I was thinking I could add something like (r'^(.*)/(.*)', 'mysite.$1.$2'), to urls.py, but of course, that won't work.
How can I automatically load up a template? Each view function should automatically load a template like templates/posts/view.html.
Is this even possible, or do I have to hack the core of Django?
Here's my solution, based on what Carl suggested:
urlpatterns = patterns('',
# url pats here
url(r'^(?P<app>\w+)/(?P<view>\w+)/(?P<args>.*)$', 'urls.dispatch')
)
def dispatch(req, app, view, args): # FIXME: ignores decorators on view func!
func = get_callable(app+'.views.'+view)
if args:
ret = func(req, *args.split('/'))
else:
ret = func(req)
if type(ret) is dict:
return render_to_response(app+'/'+view+'.html', ret)
else:
return ret
Seems to be working pretty well with initial tests. Solves both problems with a single function. Probably won't support GET-style arguments tho.
Those points are both implementable without hacking Django core, but either one will require a non-trivial level of familiarity with advanced Python techniques.
You can do the generic URL pattern with a pattern like this:
url(r'^(?P<appname>\w+)/(?P<viewfunc>\w+)/(?P<args>.*)$', 'myresolverfunc')
Then define a 'myresolverfunc' "view" function that takes "appname", "viewfunc", and "args" parameters, and implement whatever logic you want, splitting args on "/" and dynamically importing and dispatching to whatever view function is referenced. The trickiest part is the dynamic import, you can search Django's source for "importlib" to see how dynamic imports are done internally various places.
The automatic template loader can be implemented as a view function decorator similar to the various "render_to" decorators out there, except you'll generate the template name rather than passing it in to the decorator. You'll have to introspect the function object to get its name. Getting the app name will be trickier; you'll probably just want to hardcode it as a module-level global in each views.py file, or else work in conjunction with the above URL dispatcher, and have it annotate the request object with the app name or some such.
I don't you'll need to hack the core of Django for this. It sounds like you might be in need of generic views. Also check out the Generic Views topic guide.
The first example given in the generic views documentation sounds like your first bullet point:
Example:
Given the following URL patterns:
urlpatterns = patterns('django.views.generic.simple',
(r'^foo/$', 'direct_to_template', {'template':'foo_index.html'}),
(r'^foo/(?P<id>\d+)/$', 'direct_to_template', {'template':'foo_detail.html'}),
)
... a request to /foo/ would render the template foo_index.html, and a request to /foo/15/ would render the foo_detail.html with a context variable {{ params.id }} that is set to 15.