Django Filter ManyToManyField Queryset - django

I have a little tricky question (I think)
I have a model called Post(models.Model): with a many to many relation called shares
class Post(models.Model):
account = models.ForeignKey(Account, related_name="account")
shares = models.ManyToManyField(Account, related_name="shares_account", through='Share')
...
class Share(models.Model):
post = models.ForeignKey(Post)
account = models.ForeignKey(Account)
new = models.BooleanField(default=True)
...
Now I need a way to filter Posts which has exact "x" shares .. eg. I have a post with id "222" this post is shared with account id 12, 13, 16 .. now I want to filter on all post shared with account id 12,13 and 16 .
How can I do so?
My bad try is like so:: ;)
posts = Post.objects.filter(reduce(and_, [Q(shares=aid) for aid in account_ids]))

I suppose this should work for you.
Post.objects.annotate(cc=Count('shares')).filter(cc=3).filter(Q(shares__id=12) & Q(shares__id=13) & Q(shares__id=16))
See this -> Django ManyToMany filtering by set size or member in the set

This is how to achieve it with reduce
post_qs = Post.objects.all()
post_qs = reduce(lambda posts, share: posts.filter(shares=share), account_ids, post_qs)
Which I would probably make it more reusable this way:
class PostQuerySet(models.QuerySet):
def having_shares(self, share_ids):
return reduce(lambda posts, share: posts.filter(shares=share), share_ids, self)
class Post(models.Model):
...
objects = PostQuerySet.as_manager(
#usage
posts = Post.objects.all().having_shares(share_ids)

Related

How to take limited amount of related (many to one ) objects. django

So I have these three models:
class Database(models.Model):
fields...
class DatabaseFieldsToCheck(models.Model):
data_base = models.ForeignKey(Database, on_delete=models.CASCADE, related_name="sql_requests_to_check")
class Result(models.Model):
result = models.ForeignKey(DatabaseFieldsToCheck, on_delete=models.CASCADE, related_name="results")
so my relation looks like this
Database ---many---> DatabaseFieldsToCheck ---many--> result
So in my view i want to get for each database only last 10 results.
how can i do it?
should i try raw sql ? or mby write some data transfer objects ?
in you model paste afield by which you can order acc to time for that first paste this field all in your model of which you want to fetch result
created = models.DateTimeField(default=timezone.now,editable=False)
then in your views
def viewname(request):
result = Result.objects.order_by('-created')[:10]
return render(request, 'home.html',{'result':result})

django efficient queryset on related fields

Suppose you have the following models
class User:
pass
class Tag:
pass
class UserTag: # user is interested in tag
user = models.ForeignKey(User)
tag = models.ForeignKey(Tag)
class Blog:
tags = models.ManyToManyField(Tag)
For a given user, I want to get all blogs that user expressed his interests by UserTag
something like
Blog.objects.filter(tags__usertag_set__user=user_id)
I can do this in multiple steps but is it the best way to do it?
user_tags = UserTag.objects.filter(user=user)
result = Blog.objects.none()
for user_tag in user_tags:
tag = user_tag.tag
q = tag.blog_set.all()
result = result | q
This inevitably iterates all user_tags and bad...
you can do
user_tags = list(UserTag.objects.filter(creator=user).values_list('id', flat=True))
Blog.objects.filter(tags__in=user_tag)

django nested foreignkey set query

I wanted to filter on the _set of an item, however in the problem below while i was doing this, it wasn't on the field i thought it was. I needed to use rating__rating to get the rating column of the rating table in the post table.
in django, i have this:
class Story(models.Model):
user = models.ForeignKey(User)
...
class Post(models.Model):
post = models.TextField(max_length=345)
story = models.ForeignKey(Story)
...
class Rating(models.Model)
rating = models.IntegerField()
post = models.ForeignKey(Post)
and then i can find all the ratings for a given post that are have a set value:
def getPostsForStory(id):
return arrangeCountOfRatings(Post.objects.filter(story=id))
def arrangeCountOfRatings(postList):
for post in postList:
post.rateA = post.rating_set.filter(rating=rateA).count()
return postList
but how do i do this from a given story? That is, say i wanted to apply the above process of getting the counts for each post, but given a Story object?
def getStoryItemsForUser(request):
return arrangeCountOfItems(Story.objects.filter(user=request.user.id)
def arrangeCountOfItems(storyList):
for story in storyList:
story.rateA = story.post_set.filter(rating=rateA).count()
return storyList
doesn't get me what i want (the counts are all wrong - either zero of, if there are posts with ratings, 1
EDIT:
ah. The problem is thus:
story.rateA = story.post_set.filter(rating=rateA).count()
does not search for what i wanted - it is searching effectively on rating__id instead of rating__rating
so i just changed it to read rating__rating, simple.
What about:
story.rateA = Rating.objects.filter(rating=ratingA, post__story=story).count()
EDIT: The same is valid for post ratings(and equivalent to your code):
post.rateA = Rating.objects.filter(rating=ratingA, post=post).count()
Counting ratings for the specified post/story.

Django model aggregation

I have a simple hierarchic model whit a Person and RunningScore as child.
this model store data about running score of many user, simplified something like:
class Person(models.Model):
firstName = models.CharField(max_length=200)
lastName = models.CharField(max_length=200)
class RunningScore(models.Model):
person = models.ForeignKey('Person', related_name="scores")
time = models.DecimalField(max_digits=6, decimal_places=2)
If I get a single Person it cames with all RunningScores associated to it, and this is standard behavior. My question is really simple: if I'd like to get a Person with only a RunningScore child (suppose the better result, aka min(time) ) how can I do?
I read the official Django documentation but have not found a
solution.
I am not 100% sure if I get what you mean, but maybe this will help:
from django.db.models import Min
Person.objects.annotate(min_running_time=Min('time'))
The queryset will fetch Person objects with min_running_time additional attribute.
You can also add a filter:
Person.objects.annotate(min_running_time=Min('time')).filter(firstName__startswith='foo')
Accessing the first object's min_running_time attribute:
first_person = Person.objects.annotate(min_running_score=Min('time'))[0]
print first_person.min_running_time
EDIT:
You can define a method or a property such as the following one to get the related object:
class Person(models.Model):
...
#property
def best_runner(self):
try:
return self.runningscore_set.order_by('time')[0]
except IndexError:
return None
If you want one RunningScore for only one Person you could use odering and limit your queryset to 1 object.
Something like this:
Person.runningscore_set.order_by('-time')[0]
Here is the doc on limiting querysets:
https://docs.djangoproject.com/en/1.3/topics/db/queries/#limiting-querysets

jqgrid and django models

I have the following models
class Employee(Person):
job = model.Charfield(max_length=200)
class Address(models.Model):
street = models.CharField(max_length=200)
city = models.CharField(max_length=200)
class EmpAddress(Address):
date_occupied = models.DateField()
date_vacated = models.DateField()
employee = models.ForeignKey()
When I build a json data structure for an EmpAddress object using the django serialzer it does not include the inherited fields only the EmpAddress fields. I know the fields are available in the object in my view as I can print them but they are not built into the json structure.
Does anyone know how to overcome this?
Thanks
Andrew
Inheritance of Django models can get a little tricky. Unless you excplicitly require EmpAddress to be subclass of Address, you might just want to duplicate the fields and let duck typing handle the fact that you aren't following traditional object oriented design. E.g:
class Address(models.Model):
street = models.CharField(max_length=200)
city = models.CharField(max_length=200)
class EmpAddress(Address):
street = models.CharField(max_length=200)
city = models.CharField(max_length=200)
date_occupied = models.DateField()
date_vacated = models.DateField()
employee = models.ForeignKey()
Another shot in the dark you might try is to use jsonpickle (I'm one of the developers), which is "smarter" than the standard json module. The latest code has some great new features, thanks to davvid.
Take a look at: http://www.partisanpost.com/2009/10/django-jquery-jqgrid-example-one/1/ as a solution to your problem. The full serializer allows you to drill down into foreignkey relationships as far as you need to go. I wrote a tutorial example of how to use it to integrate django with JqGrid, which provides an example of just what you are faced with. Hope this helps.
John,
This is view code I am using along with the models is;
def address_grid(request):
employeeId = request.GET.get('employeeId')
if request.GET.get('sidx') == '':
order = 'date_occupied'
else:
order = request.GET.get('sidx')
if request.GET.get('sord') == 'asc':
sort_order = ''
else:
sort_order = '-'
order = sort_order + order
if request.GET.get('page'):
paginated = int(request.GET.get('page'))
else:
paginated = 1
items = int(request.GET.get('rows'))
addresses = EmpAddress.objects.filter(employee__id=employeeId)
for add in addresses:
log.write(add.city+'\n') # Field from address object
total = adresses.all().count()
if total % items > 0:
items_sum = 1
else:
items_sum = 0
pages = total / items + items_sum
if paginated > pages:
paginated = 1
addresses = addresses.order_by(order)[paginated-1)*items:paginated*items]
rows = serializers.serialize("json", addresses, indent=4,)
addresses = '{total:%(pages)s, page:%(page)s, records:%(total)s, rows:%(addresses)s' \
% {'pages':pages, 'page':paginated, 'total':total, 'addresses':rows}
log.write(rows+'\n') #json object no Address fields (city is not included)
#even it is present above
return HttpResonse(addresses, mimetype="application/json")
When I print the addresses objects after the
addresses = EmpAddress.objects.filter(employee__id=employeeId)
line I have all of the objects attributes (both the Address and EmpAddress fields).
But when I print the json object I only have the EmpAddress object attributes excluding the Address attributes.