As the title suggests, I have multiple sets of queries that each return a values list. I then use the values list to filter another queryset. At the moment I can only do this second step one queryset at a time. Is it possible to combine my initial values lists into one super long list? I'm trying to create an activity/news feed like feature.
views.py:
cookie_ids = Cookie.objects.filter(board__pk=self.kwargs['pk']).values_list('id',
flat=True)
sugar_ids = Sugar.objects.filter(board__pk=self.kwargs['pk']).values_list('id',
flat=True)
**then:
context['cookie_actions'] = Action.objects.filter(target_id__in=cookie_ids)
context['sugar_actions'] = Action.objects.filter(target_id__in=sugar_ids)
Edit: I think this is the only model that might matter
Models.py:
class Action(models.Model):
user = models.ForeignKey(User,
related_name='actions',
db_index=True)
verb = models.CharField(max_length=255)
target_ct = models.ForeignKey(ContentType,
blank=True,
null=True,
related_name='target_obj')
target_id = models.PositiveIntegerField(null=True,
blank=True,
db_index=True)
target = GenericForeignKey('target_ct', 'target_id')
created = models.DateTimeField(auto_now_add=True,
db_index=True)
class Meta:
ordering = ('-created',)
You can use chain to combine your querysets
from itertools import chain
cookie_ids = Cookie.objects.filter(board__pk=self.kwargs['pk']).values_list('id',flat=True)
sugar_ids = Sugar.objects.filter(board__pk=self.kwargs['pk']).values_list('id',flat=True)
ids_list = chain(cookie_ids, sugar_ids)
context['total_actions'] = Action.objects.filter(target_id__in=ids_list)
I think this is what you want
cookie_ids=Cookie.objects.filter(board__pk=self.kwargs['pk']).values_list('id',flat=True)
sugar_ids=Sugar.objects.filter(board__pk=self.kwargs['pk']).values_list('id',Ôflat=True)
ids_list = list(cookie_ids) + list(sugar_ids)
context['total_actions'] = Action.objects.filter(target_id__in=ids_list)
Using union
cookie_ids = Cookie.objects.filter(board__pk=self.kwargs['pk']).values_list('id',
flat=True)
sugar_ids = Sugar.objects.filter(board__pk=self.kwargs['pk']).values_list('id',
flat=True)
target_ids = cookie_ids.union(sugar_ids)
My References:
Django QuerySet union link
Related
I want to create a custom object list in the view and pass it to the template. In the template I want to loop over the list and display the information.
My models are
class CustomUser(AbstractUser):
def __str__(self):
return self.email
class Post(models.Model):
author = models.ForeignKey(CustomUser,on_delete=models.CASCADE,)
text = models.TextField()
created_date = models.DateTimeField(default=timezone.now)
published_date = models.DateTimeField(blank=True, null=True)
post_url = models.URLField(max_length = 200, blank = True)
slug = models.SlugField(unique=True, blank=True)
class subscription(models.Model):
creator = models.ForeignKey(CustomUser,default=None, null=True,on_delete=models.CASCADE,related_name='creator',)
booster = models.ForeignKey(CustomUser,default=None, null=True,on_delete=models.CASCADE,related_name='booster')
sub_value = models.FloatField(blank = True)
sub_id = models.TextField(blank = True)
status = models.BooleanField(default=False)
dateSubscribed = models.DateTimeField(default=timezone.now)
dateSubscriptionEnded = models.DateTimeField(default=timezone.now)
paymentCount = models.FloatField(default= 0)
I want to filter objects from subscription model like below
subs = subscription.objects.filter(booster = request.user)
Then find creators in the above subs object list and for each creator get the name, numbers Posts, and number of Subscribers. Add this to custom list and pass it to the template to loop over and display the information in the template. Can someone help me how to create this custom list. Thanks!
Ok so here are the basics minus the subscribers because I don't see the relation clearly. This is how to parse the name and the number of posts. \
my_list = []
for sub in subs:
name = sub.creator.name
auth_id = sub.creator.id
posts = Post.objects.filter(author=auth_id)
num_of_posts = len(posts)
my_list.append({
'name':name,
'post_count': num_of_posts,
})
then you would pass mylist thru the template context.
It is a common mistake to name the related_name=… parameter [Django-doc] to the same value as the name of the field. The related_name parameter however is the name of the reverse relation Django will automatically add. So here it means a relation to access for example the related subscription objects of a given CustomUser.
Therefore it makes more sense to rename these, for example like:
class Subscription(models.Model):
creator = models.ForeignKey(
CustomUser,
default=None,
null=True,
on_delete=models.CASCADE,
related_name='created_subscriptions'
)
booster = models.ForeignKey(
CustomUser,
default=None,
null=True,
on_delete=models.CASCADE,
related_name='boosted_subscriptions'
)
sub_value = models.FloatField(blank=True)
sub_id = models.TextField(blank =True)
status = models.BooleanField(default=False)
dateSubscribed = models.DateTimeField(default=timezone.now)
dateSubscriptionEnded = models.DateTimeField(default=timezone.now)
paymentCount = models.FloatField(default=0)
Next we can make a query where:
from django.db.models import Count
CustomUser.objects.filter(
created_subscriptions__booster=request.user
).annotate(
number_of_posts=Count('post', distinct=True)
)
This is a QuerySet of CustomUsers where each CustomUser that arises from this QuerySet has an extra attribute .number_of_posts that contains the number of posts. You thus can iterate over the queryset directly in the template.
I want to merge these two QuerySets. HotkeyAndPrefix do not have entries for every Collection in all_collections. This means len(all_collections) >= len(all_collections_hotkeys_and_prefixes). How can i merge these two QuerySets? If there is no entrie found for a Collection in HotkeyAndPrefix I want hotkey = None, prefix=None. Can I achieve this in one query?
models.py:
class Collection(models.Model):
creator = models.ForeignKey(User, blank=True, null=True)
...
class HotkeyAndPrefix(models.Model):
user = models.ForeignKey(User, null=True)
assigned_collection = models.ForeignKey(Collection, null=True)
hotkey = models.CharField(max_length=1, blank=True, null=True)
prefix = models.CharField(max_length=20, blank=True, null=True)
class Meta:
unique_together = ('user', 'assigned_collection')
view.py
admin = User.objects.filter(username='admin')[0]
all_collections = Collection.objects.filter(creator=admin)
current_user = request.user
all_collections_hotkeys_and_prefixes = HotkeyAndPrefix.objects.filter(assigned_collection__in=all_collections, user=current_user)
You need to use exclude() query. You can take the list of values which are in the
HotkeyAndPrefix.objects.filter(assigned_collection__in=all_collections, user=current_user) queryset
using
all_collections_hotkeys_and_prefixes_values = all_collections_hotkeys_and_prefixes.values_list('assigned_collection',flat=True)
and you can filter out the value, not in the all_collections_hotkeys_and_prefixes_values with one more query
all_collections_hotkeys_and_prefixes_excluded = all_collections.exclude(pk__in=all_collections_hotkeys_and_prefixes_values)
now you have two querysets, one of collection for which a user has hotkey/prefix and another for which the user doesn't
I have following two models.
class TeacherInfo(models.Model):
name = models.CharField(max_length=200)
school_id = models.ForeignKey('admin_app.School')
timestamp = models.DateTimeField(auto_now=True, blank=True)
class AssignedSheetStatus(models.Model):
level = models.ForeignKey('admin_app.Levels')
subject = models.ForeignKey('admin_app.Subject')
set = models.ForeignKey('admin_app.Set')
teacher = models.ForeignKey('teacher.TeacherInfo')
assigned_count = models.PositiveIntegerField(default=0)
corrected_count = models.PositiveIntegerField(default=0)
timestamp = models.DateTimeField(auto_now_add=True)
Now I want to join these two tables such that I have name from TeacherInfo and sum of assigned_count , corrected_count.
Normally for one teacher I would do :
AssignedSheetStatus.objects.filter(teacher__id=teacher_id).aggregate(Sum('assigned_count'), Sum('corrected_count'))
But here I want this for all of the teachers in TeacherInfo.
What is the best way to achieve this?
You can do it the other way arround. Annotate over the TeacherInfo:
TeachInfo.objects.annotate(Sum('assignedshetsstatus__assigned_count'), Sum('assignedsheetstatus__corrected_count'))
I want to find the number of articles for which a specific user has created articlehistory records.
The models for that look like this:
class Article(models.Model):
"""The basic entity of this app.)"""
documentID = models.CharField(blank=True, max_length=1000)
cowcode = models.IntegerField(blank=True, null=True)
pubdate = models.DateField(default=datetime.datetime.today)
headline = models.CharField(blank=True, max_length=1500)
source = models.CharField(blank=True, max_length=5000)
text = models.TextField(blank=True, max_length=1000000)
assignments = models.ManyToManyField(Assignment)
class Meta:
ordering = ['pubdate']
def __unicode__(self):
return self.headline
class ArticleHistory(models.Model):
"""(Modelname description)"""
article = models.ForeignKey(Article, related_name='Article History')
coder = models.ForeignKey(User, related_name='Article History')
last_updated = models.DateTimeField(default=datetime.datetime.now)
def __unicode__(self):
return self.last_updated
The way I'm trying to do this at the moment is like this:
assignment.finished_articles = Article.objects.filter(cowcode=country).filter(pubdate__range=(start_date,end_date), articlehistory__coder=request.user.id).count()
This doesn't work, however and exhibits another weird behaviour:
I try to do this:
for assignment in assignments:
country = assignment.country.cowcode
start_date = assignment.start_date
end_date = assignment.end_date
articles = Article.objects.filter(cowcode=country).filter(pubdate__range=(start_date,end_date)).select_related()
assignment.article_num = articles.count()
#assignment.finished_articles = Article.objects.filter(cowcode=country).filter(pubdate__range=(start_date,end_date), articlehistory__coder=request.user.id).count()
This works fine, unless I try to include finished_articles, then article_num gets shortened to one result.
It would be really great if anyone has a pointer to who to solve this.
Make use of reverse relation of ForeignKey created by parameter related_name:
Rename attribute related name to "article_history_set".
Now, it gives you easy pointer: user.article_history_set is a set of Article History objects where coder is set to this user.
Then you can find which article it is related to by doing article_history.article.
At the end, you have to get rid of repetition and get length of that list.
Here you have more about related_name attribute: https://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models.ForeignKey.related_name
class TagSynonym(models.Model):
source_tag_name = models.CharField(max_length=255, unique=True)
target_tag = models.ForeignKey(Tag, related_name='tag_synonyms', null=True)
class Tag(models.Model):
name = models.CharField(max_length=255, unique=True)
used_count = models.PositiveIntegerField(default=0)
class Meta:
ordering = ('-used_count', 'name')
For a given query q:
I want all the tags which contain the query in its name or in the related synonym's source_tag_name.
I also want the sort order to be preserved by ordering.
I have a query like the following
tags_by_name = tag_all.filter(name__contains=q)
tags_by_synonyms = tag_all.select_prefetched('tag_synonyms').filter(tag_synonyms__source_tag_name__contains=q).distinct()
tags = tags_by_name | tags_by_synonyms
tags = tags.distinct()
I'm not sure if the above code is correct.
Are there better way to do this?
You can do this with Django Q object:
from django.db.models import Q
qs = Tag.objects.select_prefetched('tag_synonyms').filter(
Q(name__contains=q) | Q(tag_synonyms__source_tag_name__contains=q)) \
.distinct()