django how do i mix an order_by and a get in a listview url? - django

So i want to create:
select * from Post where Post.is_chosen = true order_by create_date
and i want this to occur in the urls.py (that is, not have to define anything, just stick it in the ListView parameters)
How do i do this?
I currently have:
url(r'^$',ListView.as_view(
queryset=Post.objects.get(is_chosen = True).order_by('-pub_date')[:20],
context_object_name='latest_post_list',
template_name='posts/index.html')),
but this has an error - i cannot call order_by on the return object of the "get" This makes sense, but how can i do what i want?
I am open to calling the command from a defined function if it is impossible to do in the url definition!
UPDATE: ARGH I am an idiot.
"get" only returns one item, so of course "order_by" won't work on it. I use filter instead now!

Like the docs say, use .filter() instead.

Related

Filter all queries based on url parameters

I have in a Django project all my urls based on the following syntax:
/ID_PROGRAM/ID_PROJECT/blablabla
I would like by default that all my queries have the following filters:
.filter(program=ID_PROGRAM).filter(project=ID_PROJECT)
How can I apply these filters automatically to all my queries? My idea was to define a new manager. But is the manager able to access to the url parameters? I this the best way to do?
To complet the question, I want to enrich all my queries without having to pass explicitly the view parameters to the manager.
You could have just tried it to see if it works.
Yes, managers do accept parameters
class MyModelManager(models.Manager):
def my_filters(self, id_prog, id_proj):
return super(MyModelManager, self).get_query_set().filter(program=id_prog, project=id_proj)
and in the views:
MyModelManager.objects.my_filters(id_prog, id_proj)
Documentation on custom managers
Python promotes "Explicit is better than implicit"
karthikr is almost right, but you can also use:
1 - decorator above your function. Decorator will get args from url and put objects to any variable
2 - write mixin and aply it to view. Mixin will get args from url at overriden dispatch and save filter result to self.custom_context. Override get_context_data to merge contexts.

Django taggit doesn't work exclude

I am using Django-taggit and works fine for me but the exclude has a problem.
Keyword is a string like 'key1 key2 key3'. The code is:
keyword = form.cleaned_data['keyword']
qlist = lambda x: [Q(name__icontains=x), Q(author__name__icontains=x),Q(tags__name__icontains=x)]
item_list = Item.objects.distinct()
for key in keyword.split():
if ('-'==key[0]):
print 'exclude: %s'%(key[1:])
item_list = item_list.exclude(reduce(operator.or_,qlist(key[1:])))
else:
print 'include: %s'%(key)
item_list = item_list.filter(reduce(operator.or_,qlist(key)))
It works fine for filter() and for the exclude() Q(name_icontains=x), Q(author_name_icontains=x).
But, when I try to use exclude() with Q(tags_name__icontains=x) it doesnt work.
Regards,
Cristian
I'm not really too versed in taggit intricacies, but... Looking at the code, it seems like the "name" is dynamically built in a lazy way.
So, if you're not populating the query explicitly, you're going to get empty request, so Q(tags__name__icontains=key) will be empty, and exclude(...) will just be like filter(not null).
Try to force populating the tag query via a select_related() or something similar.
I think, It is not supported. I found this link:
https://github.com/alex/django-taggit/issues/31

Django get() query not working

this_category = Category.objects.get(name=cat_name)
gives error: get() takes exactly 2 non-keyword arguments (1 given)
I am using the appengine helper, so maybe that is causing problems. Category is my model. Category.objects.all() works fine. Filter is also similarily not working.
Thanks,
Do you have any functions named name or cat_name? If so, try changing them or the variable names you are using and trying again.
The helper maps the Django model manager (Category.objects in this case) back to the class instance of the model via the appengine_django.models.ModelManager. Through the inheritance chain you eventually come to appengine.ext.db.Model.get(cls, keys, **kwargs) so that is why you are seeing this error. The helper does not support the same interface for get that Django does. If you do not want to get by primary key, you must use a filter
To do your query, you need to use the GAE filter function like this:
this_category = Category.objects.all().filter('name =', cat_name).get()

How can I get access to a Django Model field verbose name dynamically?

I'd like to have access to one my model field verbose_name.
I can get it by the field indice like this
model._meta._fields()[2].verbose_name
but I need to get it dynamically. Ideally it would be something like this
model._meta._fields()['location_x'].verbose_name
I've looked at a few things but I just can't find it.
For Django < 1.10:
model._meta.get_field_by_name('location_x')[0].verbose_name
model._meta.get_field('location_x').verbose_name
For Django 1.11 and 2.0:
MyModel._meta.get_field('my_field_name').verbose_name
More info in the Django doc
The selected answer gives a proxy object which might look as below.
<django.utils.functional.__proxy__ object at 0x{SomeMemoryLocation}>
If anyone is seeing the same, you can find the string for the verbose name in the title() member function of the proxy object.
model._meta.get_field_by_name(header)[0].verbose_name.title()
A better way to write this would be:
model._meta.get_field(header).verbose_name.title()
where header will be the name of the field you are interested in. i.e., 'location-x' in OPs context.
NOTE: Developers of Django also feel that using get_field is better and thus have depreciated get_field_by_name in Django 1.10. Thus I would suggest using get_field no matter what version of Django you use.
model._meta.get_field_by_name('location_x')[0].verbose_name
You can also use:
Model.location_x.field.verbose_name
Model being the class name. I tested this on my Animal model:
Animal.sale_price.field.verbose_name
Animal.sale_price returns a DeferredAttribute, which has several meta data, like the verbose_name
Note: I'm using Django 3.1.5
If you want to iterate on all the fields you need to get the field:
for f in BotUser._meta.get_fields():
if hasattr(f, 'verbose_name'):
print(f.verbose_name)
# select fields for bulk_update : exclude primary key and relational
fieldsfields_to_update = []
for field_to_update in Model._meta.get_fields():
if not field_to_update.many_to_many and not field_to_update.many_to_one and not field_to_update.one_to_many and not field_to_update.one_to_one and not field_to_update.primary_key and not field_to_update.is_relation :
fields_to_update = fields_to_update + [field_to_update.name]
Model.objects.bulk_update(models_to_update , fields_to_update)

Django's list_details views saving queryset to memory (not updating)?

I have a custom model manager that looks like this:
class MyManager(models.Manager)
def get_query_set(self):
'''Only get items that are 'approved' and have a `pub_date` that is in
the past. Ignore the rest.'''
queryset = super(MyManager, self).get_query_set()
queryset = queryset.filter(status__in=('a',))
return queryset.filter(pub_date__lte=datetime.utcnow())
And this works well enough; however, I have a problem using Django's generic.list_detail views object_detail and object_list: the queryset seems to be only loading once and, because of this, it isn't fetching the items it should be because, I assume, the utcnow() time has been called only once (when it first loaded).
I assume this is intentional and meant as a performance boost - however, it means that video's show up elsewhere on the site (in places I am not in a object_detail view) before they are available in an object_detail view (see urls.py below). This is leading to 404s ...
Any ideas ? Or do I have to write my own custom views to avoid this ?
Thanks!
urls.py
url(r'^video/(?P<object_id>\d+)$',
list_detail.object_detail,
{ 'queryset': Video.objects.all(), },
name='video_detail',
),
It is not a problem of cache: as you do it now, the queryset definition is evaluated once, while parsing urls, and then, it is never evaluated again.
Solution is actually pretty simple and described in the online documentation: Complex filtering with wrapper functions: just create a small custom view, that will simply call the generic view.
I am actually using a similar solution quite a lot and I feel it quite comfortable.
By the way, a small side note, for this case I would suggest not using a custom manager, and go back instead on a normal filtering.
Try correcting urls.py to:
url(r'^video/(?P<object_id>\d+)$',
list_detail.object_detail,
{ 'queryset': Video.objects.all, }, # here's the difference
name='video_detail',
)
Edit:
If this fail, try apply similar technique(passing callable instead of calling it) to filter():
return queryset.filter(pub_date__lte=datetime.utcnow)
I have an almost identical model Manager to thornomad, and the same problem with generic views.
I have to point out that neither of the suggestions above work:
doing Video.objects.all without parentheses gives an error
doing queryset.filter(pub_date__lte=datetime.utcnow), again without the parentheses, does not give an error but does not fix the problem
I have also tried another way, which is to use a lambda to return the queryset, eg:
qs = lambda *x: Video.objects.all()
url(r'^video/(?P<object_id>\d+)$',
list_detail.object_detail,
{ 'queryset': qs(), },
name='video_detail',
),
...it didn't work either and I can see now I must have been desperate to think it would :)
lazy_qs = lambda *x: lazy(Post.live_objects.all, QuerySet)
blog_posts = {
'queryset': lazy_qs(),
...doesn't work either (gives an error) as utils.functional.lazy doesn't know how to convert the result to a QuerySet properly, as best I can tell.
I think Roberto's answer of wrapping the generic view is the only one that will help.
The django docs should be amended to point out the limitations of the queryset used by generic views (currently the docs have a special note to tell you everything will be okay!)