How do I build a queryset in django retrieving threads in which a user has posted? - django

I'm making a threaded forum app using django-mptt. Everything is up and running, but I have trouble building one specific queryset.
I want to retrieve posts which:
are root nodes
are posted by current_user or have a descendant posted by current_user.
What I have so far is this:
Post.objects.filter(Q(user = current_user) | Q( )).exclude(parent__gt = 0)
in my second Q I need something to tell whether the current_user has posted one of its descendants. Anyone know if it's even possible?

I don't think you can do this in one query. Here's how to do it in two:
thread_ids = Post.objects.filter(user=current_user).values_list('tree_id', flat=True)
posts = Post.objects.filter(tree_id__in=thread_ids, level=0)
This gets the MPTT tree id of every thread which the user has posted in. Then it gets the root node of each of these threads.

Related

How to mix multiple querysets into one and re order them by time created?

I am learning Django and still a beginner. For practising, i am trying to make a demo social media website. In my project, users can create groups, then they can post and comment there. In the home page, i am trying to add a section like 'recent activities' where a user can see recent activities in that website like "John created a group 'Javascript', Tim posted a comment in 'Python', Sarah posted in 'CSS'" Now i have made some queries like:
groups = Group.objects.all().order_by('-created')[0:5]
posts = Post.objects.all().order_by('-created')[0:5]
comments = Comment.objects.all().order_by('-created')[0:5]
I want to mix them all in a single queryset. Then order them all by the time they were created. I know it's a silly question and i have been stuck here since morning. Can you help me and show me the process please?
You can chain these together and order by the created field with:
from operator import attrgetter
groups = Group.objects.order_by('-created')[:5]
posts = Post.objects.order_by('-created')[:5]
comments = Comment.objects.order_by('-created')[:5]
all_items = sorted(
[*groups, *posts, *comments],
key=attrgetter('created'),
reversed=True
)
Now all_items is a hetrogenous list with different types of objects. This will thus make the rendering process a bit more complicated since a comment probably has different fields than a Post for example.
You can also use chain function from itertools module to combine the querysets and then sort them in reverse order using the created field as key.
from itertools import chain
groups = Group.objects.all()[0:5]
posts = Post.objects.all()[0:5]
comments = Comment.objects.all()[0:5]
queryset = sorted(
chain(groups, posts, comments),
key=lambda instance: instance.created,
reverse=True
)

Is it possible for a queryset filter to not work properly? Django 1.11.12

I ran the code below... and somehow... I got a couple of campaigns that were not active and were passed into the update_existing_campaigns. I am a little mindblown as to how this happened... it was also only a couple of inactive campaigns that were passed in, not all of them. How is this possible?
all_campaigns = AdCampaign.objects.all()
active_campaigns = AdCampaign.objects.filter(active=True)
update_existing_campaigns(active_campaigns)
def update_existing_campaigns(active_campaigns):
# only update active campaigns that haven't already been run today. used to handle failures in middle of job
active_campaigns_to_update = active_campaigns.filter(last_auto_update__lt=datetime.date.today())
for active_campaign in active_campaigns_to_update:
# do something

Getting information from Django custom signal receiver

This is my second question today actually but what I want to know...Is it possible to retrieve information from a signal handler.
I have a list of items, call it list and each item is in AppA. Each item has a couple of characteristics which are saved in a different app, AppB.
So, I figured that I could maybe create a dictionary, dict and iterate over the items in list. In each iteration, I was hoping to send a signal to AppB and retrieve the information, i.e. have something like
def blob(request):
dict = {}
for item in list:
signal.send(sender=None, id=item.id)
dict[item] = (char1, char2)
...some html request
My signal handler looks something like this:
def handler(sender, id, **kwargs):
model2 = Model2.objects.get(id=id)
a = model2.char1
b = model2.char2
return (a, b)
Then I was hoping to be able to just produce a list of the items and their characteristics in the webpage...THe problem is that obviously the signal sender has to send the signal, and get the information back which I want....is that even possible :S?
Currently, I get an error saying "global name 'char1' is not defined....and I have imported the handlers and signals into the view.py where blob resides....so is my problem just unsolvable? / Should it clearly be solved in another way? Or have I almost certainly made a stupid error with importing stuff?
This wasn't actually so tricky. Thought I should perhaps post how it was solved. In my views, I actually wrote
response_list=signal.send(sender=None, list=list_of_items)
I then iterated over my response_list, adding the items to a fresh list like so:
snippets = []
for response in response_list:
logger.error(response)
snippets.append(response[1])
And could then call the responses in snippets like a dictionary in my template. When I asked the question, I didn't appreciate that I could equate something with the signal sending...

How do i get (if possible) a queryset order by a parent entry and all child entries and so on?

I don't know if i was describing things the right way in the headline, so i will try to do it better here,
Lets say that i am building a forum system and that i have a Post model that has, among other fields, a Foreign key to the Thread model and a foreign key to self so with the name of parent_post, so people will be able to post replies to other posts or start new posts for each thread.
Every thing is working great. The thing i don't know and can't find is how to show the posts in order when i want to show all posts for a thread....
For example:
Thread x:
post a .....
response to post a .....
response number 2 to post a .....
post b ....
post c ....
response to post c .....
response 2 to post c .....
And so on......
I know how to do it in pure SQL and i also know there i can return all thread posts and set them up in order with JS but there must be a way to do it the django way :-)
Thank you,
Erez
I guess your model looks like:
class Post(Model):
....
thread = ForeignKey(Thread)
post = ForeignKey('self')
posttime = DateTimeField(auto_now_add=True)
You will get all mother-posts belong to a thread...
mothers = Post.objects.filter(thread=x, post__isnull=True)
post__isnull=True will filter posts that have no referance to self, which means they are posts that starts the topic...
Then Get posts belong to a single topic and order them...
mother-post = mothers[0]
childs = Post.objects.filter(post=mother-post).order_by('posttime')
But probably, ordering by id (which is default) also solves your problem so, you may not need order_by .
UPDATE:
Yes you can do it in one query Such as for the post with id=12323,
Posts.objects.filter(Q(pk=12323) | Q(post__id=12323))
Link for documentation... That will do what you need.
You have to setup ordering = ['id',] or ordering = ['timestamp',] in your Post model.
When you will do request posts = Post.models.filter(thread=x) all post will be order by 'id' or by 'timestamp' fields. And when you will do posts[a].response_set.all() you will got all responses that ordered according your settings in model Meta class.
PS: sorry for my English
why not have a look at http://www.djangopackages.com/grids/g/forums/

Adding a view counter to objects using Django Celery

Not that it matters, but this is a follow-up to this question.
I want to keep a count of how many times each object in my database has been viewed. Let's say we have a Person model, with several instances. We want to keep a counter of how many times each instance has been viewed in the Person model, using Django Celery to avoid waiting for the database writes.
At the moment I'm doing this:
from celery.decorators import task
class Person(models.Model):
name = models.CharField(max_length=50)
class Stats(models.Model):
person = models.ForeignKey('Person', unique=True)
#task
def addView(self):
se = StatEvent()
se.save()
self.views.add(se)
class StatEvent(models.Model):
date = models.DateTimeField(auto_now_add=True)
Then, every time the view is called which lists a page of persons, I get all persons, update the statistics like this:
person.get_stats().addView.delay(person.get_stats())
where after I then return the list of persons to be displayed in the browser. I thought that the updating of the statistics would happen asynchronously, but there's a clear and long delay before the page is displayed, which is confirmed by having a print statement shown for each addition in the Celery command window. The page is only rendered once the last statistic has been updated.
How do I ensure that the user doesn't wait for the database update to finish?
Update
I thought it might have something to do with there not being enough worker processes to process each person separately, so I instead made a function that accepts a list of persons as parameter, and used this as the task to be executed. So, only one task in the queue:
#task(ignore_result=True)
def addViews(persons):
for person in persons:
stats = listing.get_stats()
se = StatEvent()
se.save()
stats.views.add(se)
However, when print to the console, like this:
print "adding"
print tasks.addClicks(persons)
print "done"
Then there's a clear delay between the "adding" and "done" step, and the returned value of the function is None.
Turns out my original suspicion about there not being enough workers was correct. My new function that put everything in one task solved the problem - I was just missing the .delay in that last tasks.addClicks(persons) call.