Mojtaba
Mojtaba

Reputation: 593

Is there a way to merge 2 querysets in Django and order them by a their repecting field?

I'm trying to create a twitter clone and this is my user and tweet Model(some irrelevant fields have been removed).

class TwitterUser(models.Model):
    user = models.OneToOneField(to=User, on_delete=models.CASCADE,primary_key=True)
    Bio = models.CharField(max_length=200, blank=True)
    Location = models.CharField(max_length=200, blank=True)
    Website = models.URLField(blank=True)
    ProfilePicture = models.ImageField(upload_to="Twitter", default="../static/twitter/images/default_profile.png")
    CreateDate = models.DateField(default=timezone.now)
class Tweet(models.Model):
    TweetBody = models.CharField(max_length=140, blank=False)
    TweetDate = models.DateTimeField(default=timezone.now)
    Owner= models.ForeignKey(to=TwitterUser,on_delete=models.CASCADE,related_name="Owner")
    RetweetedBy= models.ManyToManyField(to=TwitterUser,related_name="Retweeted",blank=True,through="RetweetIntermediate")

and this the table that my many to many relationship for retweet is using.

class RetweetIntermediate(models.Model):
    twitteruser=models.ForeignKey(TwitterUser,on_delete=models.CASCADE)
    tweet=models.ForeignKey(Tweet,on_delete=models.CASCADE)
    retweetDate=models.DateTimeField(default=timezone.now)

In profile view all the tweets and retweets should be shown ordered by date what I'm doing right now (and it is working fine) is this:

def keymaker(a):
    return a.TweetDate
def ProfileView(request):
    tweets= list(Tweet.objects.filter(Owner=user.user_id,IsReplyToTweet__isnull=True).order_by("-TweetDate"))
    retweets = list(user.Retweeted.all().order_by("-id"))
    retweetInter=RetweetIntermediate.objects.all().order_by("-tweet_id")
    for i , j in zip(retweets,retweetInter):
        i.TweetDate=j.retweetDate
    tweets=(tweets+retweets)
    tweets.sort(key=keymaker,reverse=True)

I retrieve all the tweets ordered by date. then I retrieve all of retweets and make a list out of them and change the data of tweet to the date saved in intermediate table and merge both lists and sort them by date. I want to know is there a better way or more standard way to do this?

Thanks in advance.

Upvotes: 0

Views: 99

Answers (1)

Martí
Martí

Reputation: 2861

You can do it using union together with annotate.

from django.db.models import F

tweets_qs = Tweet.objects\
  .filter(Owner=user, IsReplyToTweet__isnull=True)\
  .annotate(date=F('TweetDate'))

retweets_qs = Tweet.objects\
  .filter(retweetintermediate__twitteruser=user)\
  .annotate(date=F('retweetintermediate__retweetDate'))

timeline_qs = tweets_qs.union(retweets_qs).order_by('-date')

Notice that both querysets have Tweet objects.

Edit: Sorry for not understanding the question correctly the first time.

Upvotes: 1

Related Questions