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.
Related
Two models Users (built-in) and Posts:
class Post(models.Model):
post_date = models.DateTimeField(default=timezone.now)
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, related_name='user_post')
post = models.CharField(max_length=100)
I want to have an API endpoint that returns the percentage of users that have posted. Basically I want SUM(unique users who have posted) / total_users
I have been trying to play around with annotate and aggregate, but I am getting the sum of posts for each users, or the sum of users per post (which is one...). How can I get the sum of posts returned with unique users, divide that by user.count and return?
I feel like I am missing something silly but my brain has gone to mush staring at this.
class PostParticipationAPIView(generics.ListAPIView):
queryset = Post.objects.all()
serializer_class = PostSerializer
def get_queryset(self):
start_date = self.request.query_params.get('start_date')
end_date = self.request.query_params.get('end_date')
# How can I take something like this, divide it by User.objects.all().count() * 100, and assign it to something to return as the queryset?
queryset = Post.objects.filter(post_date__gte=start_date, post_date__lte=end_date).distinct('user').count()
return queryset
My goal is to end up with the endpoint like:
{
total_participation: 97.3
}
Thanks for any guidance.
BCBB
EDIT
OK, I am still struggling a bit. I tried to create a serializer that just had a decimal field for participation_percentage like:
percentage_participation = serializers.DecimalField(max_digits=5, decimal_places=2, max_value=100, min_value=0)
Then I calculate in the view, but I get an error:
Got AttributeError when attempting to get a value for field percentage_participation on serializer ParticipationSerializer.
The serializer field might be named incorrectly and not match any attribute or key on the str instance.
Original exception text was: 'str' object has no attribute 'percentage_participation'.
Error was the same if I made it a CharField (in case there was some string coercion?).
So then I tried to move it to a Serializer Method and put all the calculation logic in there. This calculated fine, but if I had to provide a query_set in the view. If provided a model object, it just returned the percentage as many times as the query (say Posts.objects.all() had a total of 100 posts, it returned the percentage 100 times).
So then I tried to override the get_queryset in the view, but I HAVE to return something. If I just return { "meh", "hello" } then I return the percentage from the SerializerMethodField one time and the end result is exactly what I want.
I just have no idea as to WHY or how to do this correctly.
Thanks for your help.
EDIT #2
OK so I realized why I was only getting one, it was iterating over the string I returned, which was one character. When I returned "meh" it gave me three of the percentage, iterating over each character in the string...
I am not understanding from playing around, reading the docs, or using GoogleFu how to do this properly. I just want to be able to perform some kind of summary logic on records from the DB - how can I do this properly?!?!
Thank you for all your time.
BCBB
something like this should work
# get total user count
total_users = User.objects.count()
# get unique set of users with post
total_users_who_posted = Post.objects.filter(...).distinct("user").count()
# calculate_percentage
percentage = {
"total_participation": (total_users_who_posted*100)/ total_users
}
# take caution of divion by zero
I don't think it is possible to use djangos orm to do this completely but you can use the orm to get the user counts (with posts and total):
from django.db.models import BooleanField, Case, Count, When, Value
counts = (User
.objects
.annotate(posted=Case(When(user_post__isnull=False,
then=Value(True)),
default=Value(False),
output_field=BooleanField()))
.values('posted')
.aggregate(posted_users=Count('pk', filter=Q(posted=True)),
total_users=Count('pk', filter=Q(posted__isnull=False)))
# This will result in a dict containing the following:
# counts = {'posted_users': ...,
# 'total_users': ....}
I want to implement this thing, Like Facebook showing ads when we are scrolling posts, after 4th or 5th post we see some ads, how can I do that please can someone tell me? If any video link is available please share
Between two post like this
I am showing all the post by for loop, if any nested for loops available please share how can I loop two different model in single loop , showing 1st item of one model after 5th item of another model loop
**I am not using google ad sense, you can imagine its like I will create my own model , maybe same post model where is_ads=True be a field like that.
This is my post model-
class Post(models.Model):
postuuid = models.UUIDField(default=uuid.uuid4,unique=True,editable=False)
user = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.CASCADE, null=True)
title = models.CharField(max_length=150,blank=False)
text = models.TextField(null=True,blank=False)
image = models.ImageField(upload_to='post_images/',null=True,blank=True,default="")
created_at = models.DateTimeField(auto_now_add=True, null=True)
likes = models.ManyToManyField(User, blank=True, related_name="post_like")
tag= models.CharField(max_length=150,blank=True)
post_url=models.URLField(max_length=150,blank=True)
video = models.FileField(upload_to='post_videos/',null=True,blank=True,default="")
# community = models.ForeignKey(communities,on_delete=models.CASCADE)
def __str__(self):
return self.title
Looking at this, I think your best option would be to create a view function that creates two querysets and merges them together into a single one that you can pass to the context. It would be something like this:
# settings.py
AD_POST_FREQUENCY = 5 # Use this to control the frequency of ad posts appearing in the list of posts.
# views.py
from settings import AD_POST_FREQUENCY
def post_list(request):
ad_posts = Post.objects.filter(is_ad=True)
non_ad_posts = Post.objects.filter(is_ad=False)
posts = []
non_ad_post_section_count = 0
for i, post in enumerate(non_ad_posts):
posts.append(post)
if i % AD_POST_FREQUENCY == 0:
ad_post = ad_posts[non_ad_post_section_count]
posts.append(ad_post)
non_ad_post_section_count += 1
context = {
'posts': posts,
}
return render(request, 'your_template.html', context=context)
Using this approach, you would be able to essentially create a single list of posts to return to your template. Then you would only need to loop through the list in the template to display all the posts.
I haven't tried this myself but hopefully, it helps you.
According to the docs then you should be able to catch reverse relations when those relations are onetoone with a select_related(). But it is not working, so what could I be missing?
My class looks like this:
class MainPage(models.Model):
book = models.OneToOneField(Book, primary_key=True)
text = models.TextField(blank=True)
I can do this fine:
book = Book.objects.get(id=book_id, active=True)
main_page = book.mainpage
But doing like so does not lower the database calls:
book = Book.objects.select_related('mainpage').get(id=book_id, active=True)
main_page = book.mainpage
I guess you intend to hit only a single sql query (using one to one join). This might work for that:
book = Book.objects.get(mainpage__book_id=book_id, active=True)
EDIT:
The query in your question does not work because select_related works only with the querysets while .get returns an instance object. Thus this should work:
book = Book.objects.select_related('mainpage').filter(id=book_id, active=True)[0]
main_page = book.mainpage
I have two models, Recieved_order and order,
class Order(SmartModel):
restaurant = models.ForeignKey(Restaurant,null=True,blank=True,default = None,help_text="The restaurant the customer order from")
#contact info
email = models.EmailField(max_length=50,help_text="Needed as alternative")
mobile = PhoneNumberField(max_length=20,default='+25078######')
class Recieved_Order(SmartModel):
item = models.ForeignKey(Item)
date_added = models.DateTimeField(auto_now=True,auto_now_add=True)
quantity = models.IntegerField(default=0)
price = models.DecimalField(max_digits=9,decimal_places=2)
order = models.ForeignKey(Order)
i want a restaurant manager(user), to be able to receive orders(Recieved_order) made to his specific restaurants when logged in, to achieve this, i have the following in views.py
class Recieved_OrderCRUDL(SmartCRUDL):
model = Recieved_Order
actions = ('create','read','update','delete','list')
permissions = True
class List(SmartListView):
fields = ('order_email','order_mobile','order_billing_city','item.name','item.price','quantity','order_id','order_restaurant')
search_fields = ('date_added',)
def get_queryset(self,*args,**kwargs):
queryset = super(Recieved_OrderCRUDL.List, self).get_queryset(*args,**kwargs)
if self.request.user.is_superuser:
return queryset
return queryset.filter(order=self.request.user)
with the above i am testing on two different restaurants, the restaurant and its not working out as it should. its returning the wrong orders for a given restaurant.
What am i not doing right with get_queryset().
There's something confusing going on here:
return queryset.filter(order=self.request.user)
You're telling it to build a query that filters Order objects against User objects.
Is there something missing in your sample code that ties orders back to users such that a proper join can be constructed?
If you want to have a user (what you refer to as a manager) only able to view their own orders, you need to change things... Restaurant will need to have a field that points to a User (let's call it user and assume it's a ForeignKey) Then you can do something like
if self.request.user.is_superuser:
return queryset
return queryset.filter(order__restaurant__user=self.request.user)
As pointed out by #Joe Holloway, you should not be trying to filter on the order field with a user object...
The other odd thing I wanted to point out is
fields = ('order_email','order_mobile','order_billing_city','item.name','item.price','quantity','order_id','order_restaurant')
You appear to be using a mixture of ways to attempt to access things...
You should be using __ (that's 2 underscores) to access relations, not _ or .
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