Django conditionally excluding fields - python

I am new to Django and am having some trouble with filtering. Please excuse the contrived example. I have some model for events, with a one to many relationship with attendees. From my set of events I want to exclude events occurring in Boston, but only if there's only 1 attendee. The code below is what I've tried that definitely does not work:
queryset = queryset.annotate(attendees_count=Count('attendees')).exclude(attendees_count=1, event_location__city="Boston")
I don't get an error. Rather it just filters out "Boston" regardless of "attendees_count".
In addition to a query that actually does what I want it to do, I'd like to understand why what I did doesn't work. Thanks in advance.

Are you sure that your original queryset includes Boston with >1 attendee?
https://docs.djangoproject.com/en/dev/ref/models/querysets/#django.db.models.query.QuerySet.exclude
Multiple parameters are joined via AND in the underlying SQL
statement, and the whole thing is enclosed in a NOT()

Related

Django models - assign id instead of object

I apologize if my question turns out to be silly, but I'm rather new to Django, and I could not find an answer anywhere.
I have the following model:
class BlackListEntry(models.Model):
user_banned = models.ForeignKey(auth.models.User,related_name="user_banned")
user_banning = models.ForeignKey(auth.models.User,related_name="user_banning")
Now, when i try to create an object like this:
BlackListEntry.objects.create(user_banned=int(user_id),user_banning=int(banning_id))
I get a following error:
Cannot assign "1": "BlackListEntry.user_banned" must be a "User" instance.
Of course, if i replace it with something like this:
user_banned = User.objects.get(pk=user_id)
user_banning = User.objects.get(pk=banning_id)
BlackListEntry.objects.create(user_banned=user_banned,user_banning=user_banning)
everything works fine. The question is:
Does my solution hit the database to retrieve both users, and if yes, is it possible to avoid it, just passing ids?
The answer to your question is: YES.
Django will hit the database (at least) 3 times, 2 to retrieve the two User objects and a third one to commit your desired information. This will cause an absolutelly unnecessary overhead.
Just try:
BlackListEntry.objects.create(user_banned_id=int(user_id),user_banning_id=int(banning_id))
These is the default name pattern for the FK fields generated by Django ORM. This way you can set the information directly and avoid the queries.
If you wanted to query for the already saved BlackListEntry objects, you can navigate the attributes with a double underscore, like this:
BlackListEntry.objects.filter(user_banned__id=int(user_id),user_banning__id=int(banning_id))
This is how you access properties in Django querysets. with a double underscore. Then you can compare to the value of the attribute.
Though very similar, they work completely different. The first one sets an atribute directly while the second one is parsed by django, that splits it at the '__', and query the database the right way, being the second part the name of an attribute.
You can always compare user_banned and user_banning with the actual User objects, instead of their ids. But there is no use for this if you don't already have those objects with you.
Hope it helps.
I do believe that when you fetch the users, it is going to hit the db...
To avoid it, you would have to write the raw sql to do the update using method described here:
https://docs.djangoproject.com/en/dev/topics/db/sql/
If you decide to go that route keep in mind you are responsible for protecting yourself from sql injection attacks.
Another alternative would be to cache the user_banned and user_banning objects.
But in all likelihood, simply grabbing the users and creating the BlackListEntry won't cause you any noticeable performance problems. Caching or executing raw sql will only provide a small benefit. You're probably going to run into other issues before this becomes a problem.

haystack solr search ALL fields

I have a solr search engine set up with multiple fields and I want to be able to search ALL fields.
I can do a .filter(content='string') but this only searches whatever fields are in the document=True
EDIT
Also, some of the non document=True fields have different filters/tokenisers applied so im guessing that would not work with adding them into a single field...
Maybe you can make a second field with 'use_template' and a template displaying ALL fields.
I never tried to do this, but this sound a good way to do it to me.
EDIT since OP comment:
Then my best bet is to eaither sublass SearchQueryset to add a method or to create a function that will loop and all fields in your SearchIndex and do something like:
qs = SearchQuerySet().filter(content=query)
for field in fieldlist:
qs = qs.filter_or(**{'field':query})
I have no idea if this works at all but that's worth trying.
#neolaser: I think what you want can be achieved by using DisMax search. It allows searching through multiple fields and specify the boost value for each of them. For more details:
http://wiki.apache.org/solr/SolrRelevancyFAQ
http://wiki.apache.org/solr/DisMaxQParserPlugin
You can search all the fields buy including them all into your filtering query parameter or by naming them in the query string (e.g. if you need to search for "keyword" search for "((field_1:keyword) OR (field_2:keyword) OR (field_3: keyword))" instead).
However, it is usually better to have a dedicated field concatenating all the others you need to search and search this single field. You can set up a copyfield in your schema to have that content generated automatically when your document is indexed.

Designing a Tag table that tells how many times it's used

I am trying to design a tagging system with a model like this:
Tag:
content = CharField
creator = ForeignKey
used = IntergerField
It is a many-to-many relationship between tags and what's been tagged.
Everytime I insert a record into the assotication table,
Tag.used is incremented by one, and decremented by one in case of deletion.
Tag.used is maintained because I want to speed up answering the question 'How many times this tag is used?'.
However, this seems to slow insertion down obviously.
Please tell me how to improve this design.
Thanks in advance.
http://www.pui.ch/phred/archives/2005/06/tagsystems-performance-tests.html
If your database support materialized indexed views then you might want to create one for this. You can get a large performance boost for frequently run queries that aggregate data, which I think you have here.
your view would be on a query like:
SELECT
TagID,COUNT(*)
FROM YourTable
GROUP BY TagID
The aggregations can be precomputed and stored in the index to minimize expensive computations during query execution.
I don't think it's a good idea to denormalize your data like that.
I think a more elegant solution is to use django aggregation to track how many times the tag has been used http://docs.djangoproject.com/en/dev/topics/db/aggregation/
You could attach the used count to your tag object by calling something like this:
my_tag = Tag.objects.annotate(used=Count('post'))[0]
and then accessing it like this:
my_tag.used
assuming that you have a Post model class that has a ManyToMany field to your Tag class
You can order the Tags by the named annotated field if needed:
Tag.objects.annotate(used=Count('post')).order_by('-used')

Checking for group membership (Many to Many in Django)

I have two models in Django: groups and entries. Groups has a many-to-many field that connects it to entries. I want to select all entries that have a group (as not all do!) and be able to access their group.title field.
I've tried something along the lines of:
t = Entries.objects.select_related().exclude(group=None)
and while this returns all entries that have groups, I can't do t[0].groups to get the title. Any ideas on how this could be done?
Edit: more info
When ever I use Django's shell to inspect what is returned in t (in this example), t[0].group does not exist. The only way I can access this is via t[0].group_set.all()[0].title, which seems inefficient and like I'm doing something incorrectly.
You don't show the model code, so I can't be sure, but instead of t[0].groups, I think you want:
for g in t[0].groups.all():
print g.title

Dealing with URLs in Django

So, basically what I'm trying to do is a hockey pool application, and there are a ton of ways I should be able to filter to view the data. For example, filter by free agent, goals, assists, position, etc.
I'm planning on doing this with a bunch of query strings, but I'm not sure what the best approach would be to pass along the these query strings. Lets say I wanted to be on page 2 (as I'm using pagination for splitting the pages), sort by goals, and only show forwards, I would have the following query set:
?page=2&sort=g&position=f
But if I was on that page, and it was showing me all this corresponding info, if I was to click say, points instead of goals, I would still want all my other filters in tact, so like this:
?page=2&sort=p&position=f
Since HTTP is stateless, I'm having trouble on what the best approach to this would be.. If anyone has some good ideas they would be much appreciated, thanks ;)
Shawn J
Firstly, think about whether you really want to save all the parameters each time. In the example you give, you change the sort order but preserve the page number. Does this really make sense, considering you will now have different elements on that page. Even more, if you change the filters, the currently selected page number might not even exist.
Anyway, assuming that is what you want, you don't need to worry about state or cookies or any of that, seeing as all the information you need is already in the GET parameters. All you need to do is to replace one of these parameters as required, then re-encode the string. Easy to do in a template tag, since GET parameters are stored as a QueryDict which is basically just a dictionary.
Something like (untested):
#register.simple_tag
def url_with_changed_parameter(request, param, value):
params = request.GET
request[param] = value
return "%s?%s" % (request.path, params.urlencode())
and you would use it in your template:
{% url_with_changed_parameter request "page" 2 %}
Have you looked at django-filter? It's really awesome.
Check out filter mechanism in the admin application, it includes dealing with dynamically constructed URLs with filter information supplied in the query string.
In addition - consider saving actual state information in cookies/sessions.
If You want to save all the "parameters", I'd say they are resource identifiers and should normally be the part of URI.

Categories