Django taggit doesn't work exclude - django

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

Related

How to use query results in url regex in Django

I want to use a database query to generate my URL configuration. Something like:
states = State.objects.all().values_list('pk', flat=True)
And then a regex like:
(r'^state/(?P<state>' + '|'.join(states) + ')/$'
The idea is that I can have URLs like:
/state/ca/
/state/az/
Etc.
The problem is that when I do syncdb, the query above fails, throwing a DatabaseError.
Is there a good way to do this? I've tried the obvious change, which would be:
try:
states = State.objects.all().values_list('pk', flat=True)
except DatabaseError:
# First sync, use dummy data
states = []
But this doesn't work because the exception is thrown at the regex, not at the query definition.
Ideas?
Why do you need to constrain this in the URL pattern itself? Much better to accept all two-letter codes, and check in the view.
(r'^state/(?P<state_code>\w{2})/$'
def view_state(request, state_code):
state = get_object_or_404(State, pk=state_code)

MongoEngine get_or_create Alternatives

I've been using the get_or_create method with MongoEngine in a Django app. Today, I noticed there were a few duplicate entries. I came across this in the MongoEngine API Reference for get_or_create:
This requires two separate operations and therefore a race condition exists. Because there are no transactions in mongoDB other approaches should be investigated, to ensure you don’t accidentally duplicate data when using this method. This is now scheduled to be removed before 1.0
Should I be using something like this?:
from models import Post
post = Post(name='hello')
try:
Posts.objects.get(name=post.name)
print "exists"
except:
post.save()
print "saved"
Will that solve my problem?
Is there a better way?
To perform an upsert use the following syntax:
Posts.objects(name="hello").update(set__X=Y, upsert=True)
That will add a post with the name "hello" and where X = Y if it doesn't already exist, otherwise it will update an existing post just setting X = Y.
If you need pass a dictionery, can do this:
post = Post.objects(name="hello").first() or Post(name="hello")
then you can update with something like this:
# data = dictionary_with_data
for field, value in data.items():
post[field] = value
post.save()

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

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.

Django: Querying comments based on object field

I've been using the built-in Django comments system which has been working great. On a particular page I need to list the latest X comments which I've just been fetching with:
latest_comments =
Comment.objects.filter(is_public=True, is_removed=False)
.order_by('submit_date').reverse()[:5]
However I've now introduced a Boolean field 'published' into the parent object of the comments, and I want to include that in the query above. I've tried using the content_type and object_pk fields but I'm not really getting anywhere. Normally you'd do something like:
Comment.objects.filter(blogPost__published=True)
But as it is not stored like that I am not sure how to proceed.
posts_ids = BlogPost.objects.filter(is_published=True).values_list('id', flat=True) #return [3,4,5,...]
ctype = ContentType.objects.get_for_model(BlogPost)
latest_comments = Comment.objects.filter(is_public=True, is_removed=False, content_type=ctype, content_object__in=posts_ids).order_by('-submit_date')[:5]
Comments use GenericForeignKey to store the relation to parent object. Because of the way generic relations work related lookups using __<field> syntax are not supported.
You can accomplish the desired behaviour using the 'in' lookup, however it'll require lot of comparisons when there'll be a lot of BlogPosts.
ids = BlogPost.objects.filter(published=True).values_list('id', flat=True) # Get list of ids, you would probably want to limit number of items returned here
content_type = ContentType.objects.get_for_model(BlogPost) # Becasue we filter only comments for BlogPost
latest_comments = Comment.objects.filter(content_type=content_type, object_pk__in=ids, is_public=True, is_removed=False, ).order_by('submit_date').reverse()[:5]
See the Comment model doc for the description of all fields.
You just cannot do that in one query. Comments use GenericForeignKey. Documentation says:
Due to the way GenericForeignKey is implemented, you cannot use such
fields directly with filters (filter() and exclude(), for example) via
the database API.

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)