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
Related
I am creating a simple Pizza Delivery website and trying to add an option to choose a topping. When I want to print Ingredients it returns QuerySet and Values in it separated by a comma. Is there any option how can I get values based on their variable names (ex. ingredients.all[0].toppingName -> cheese) or is there any methods which allows to get values separately. Of course, kludge with .split works but it is awful
UPD:
As for admin panel the provided solution worked. But it does not work in html template, so I found this code. Maybe it will useful for somebody.
In Django, if you want to get only a specific column value you can use
Model.objects.all().values('column_name')
You can also filter the queryset and get values as
Model.objects.filter(condition).values('column_name')
I have an app that I want to build a "recent activity"/firehose feed of 2-3 combined types of activity such as posts, comments, and likes of posts, and something else + maybe more later. I assume this is done with a query of taking the last of the appropriate object added to the DB and combining it with the last of the other type of object and ordering the new combined list of objects by their timestamps. What is the best way to do something like this? For now, I have something like this for every time someone refreshes the page:
NewPost.objects.all().order_by('-postdate')[0:10] #takes the last 16 recently added posts
Comment.objects.all().order_by('-commentdate')[0:10] #takes equal number of comments site wide ordered by timestamp
So what is the best way to take both of these querysets and render the different Models in 1 list ordered by their timestamp? I assume the type of logic will be the same for adding additional types of objects, so I just want to know how to do it with just 2. Thanks!
I don't really like your approach since when you want to put another object on the firehose you'd need to add a third line (AnotherObject.objects.all ... etc ) to all places you need to display that firehose !
For me, the best way to do this is to create a Firehose Model with fields like: date, action (add/delete/update etc) and object (a generic Foreign Key to the object that was changed). Now, whenever you make a change to an object that you want to add to the firehose, you'd add a new instance of the FirehoseClass with the correct field values. Finally, whenever you want to display the firehose you'll just display all firehose objects.
To combine the lists, you can use create a list by using chain() from itertools, and then sort them by using sorted():
from itertools import chain
combined_lists = list(chain(new_post_list, comment_list))
sorted_combinened_list = sorted(combined_list, key=lambda instance: instance.postdate)
However, as you see, the sorting is only done by using one key. I don't know of any method to use two different keys when sorting. You could fix this by simply add a property to the Comment class, named postdate that simply returns commentdate. Or, even better, you should use the same name for creation time for all your models, e.g. created_at.
This has been answered earlier and more detailed here: How to combine 2 or more querysets in a Django view?
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()
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.
I have to work with a queryset, that is already filtered, eg. qs = queryset.filter(language='de') but in some further operation i need to undo some of the already applied filtering, eg not to take only the rows with language='de' but entries in all languages. Is there a way to apply filter again and have the new parameters connected to the already existing ones using OR not add, eg. if the queryset is already filtered for language='de' and i would be able to connect an 'OR language='en' to that, it would give me what i'm looking for!
Thanks!
I don't believe it is possible to do what you are asking.
The way you do ORs in django is like this:
Model.objects.filter(Q(question__startswith='Who') | Q(question__startswith='What'))
so if you actually wanted to do this:
Model.objects.filter(Q(language='de') | Q(language='en'))
you would need to put them both in the same filter() call so you wouldn't be able to add the other or clause in a later filter() call.
I think the reason you may be trying to do this would be that you are concerned about hitting the database again but the only way to get accurate results would be to hit the database again.
If you are simply concerned about producing clean, DRY code, you can put all the filters that are common to both queries at the top and then "fork" that query set later, like this:
shared_qs = Model.objects.filter(active=True)
german_entries = shared_qs.filter(language='de')
german_and_english = shared_qs.filter(Q(language='de') | Q(language='en'))