简体   繁体   中英

How do I collect multiple Django models together into a single list?

I have a fairly straightforward blog in Django, with separate models for Article and Link. I want to have a loop in my template that lists them both in date order, which means something like this:

def listview(request):
    return render_to_response('index.dtmpl', {
        'articles' : ArticlesAndLinks.objects.order_by('post_date')[:10]
    }, context_instance = RequestContext(request)

I'm not sure how to do this. Do I have to grab Articles.objects.order_by('post_date') and Links.objects.order_by('post_date') separately, merge them, and reorder? Or is there a nicer Django-ish/Pythonic way to accomplish this?

If it helps, Posts and Links are both subclasses of an abstract class, Post, but as it's an abstract class it appears I can't run collections on it.

事实证明,解决方案是将抽象类变成一个真正的类,然后我可以收集它。

Well, the obvious answer would have been to make Post a concrete class. Else you'll probably have to squeeze the ORM and resort to handcoded SQL or manually merge/order your two querysets. Given the small size of the dataset, I'd go for this last solution.

Refactoring could be the better solution, but here is another one that could do the job:

Create a custom Manager:

class PostManager(models.Manager):
    def mixed(self, first):
        all_dates = []
        articles_dates = Articles.objects.extra(select={'type':'"article"'}).values('id', 'post_date', 'type').order_by('-post_date')[:first]
        links_dates = Links.objects.extra(select={'type':'"link"'}).values('id', 'post_date', 'type').order_by('-post_date')[:first]
        all_dates.extend(articles_dates)
        all_dates.extend(links_dates)
        # Sort the mixed list by post_date, reversed
        all_dates.sort(key=lambda item: item['post_date'], reverse=True)
        # Cut first 'first' items in mixed list
        all_dates = all_dates[:first]
        mixed_objects = []
        mixed_objects.extend(Articles.objects.filter(id__in=[item['id'] for item in all_dates if item['type'] = 'article']))
        mixed_objects.extend(Links.objects.filter(id__in=[item['id'] for item in all_dates if item['type'] = 'link']))
        # Sort again the result list
        mixed_objects.sort(key=lambda post: post.post_date, reverse=True)
        return mixed_objects

And use it in your abstract model:

class Post(models.Model):

    class Meta:
        abstract = True

    objects = PostManager()

Then the call for your mixed objects will be:

Article.objects.mixed(10)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM