Search code examples
djangodatesortingmodels

Django: How do I sort on date from two models?


1.) I have the following models.py definition:

    from django.db import models
    from datetime import date

    class Author(models.Model):
        author  = models.CharField(max_length=20)
        def __unicode__(self):
            return '%s' % (self.author)

    class SystemA(models.Model):
        author      = models.ForeignKey(Author)
        date        = models.DateField()
        system      = models.CharField(max_length=20, blank=False, default="System A")
        description = models.CharField(max_length=300)
        status = models.CharField(max_length=6)
        def __unicode__(self):
            return '%s, %s, %s, %s, %s' % (self.date, self.author, self.system, self.description, self.status)

    class SystemB(models.Model):
        author      = models.ForeignKey(Author)
        date        = models.DateField()
        system      = models.CharField(max_length=20, blank=False, default="System B")
        description = models.CharField(max_length=300)
        status = models.CharField(max_length=6)
        def __unicode__(self):
            return '%s, %s, %s, %s, %s' % (self.date, self.author, self.system, self.description, self.status)

2.) This admin.py definition:

    from acc.models import SystemA, SystemB, Author
    from django.contrib import admin

    admin.site.register(SystemA)
    admin.site.register(SystemB)

3.) And this is my views.py definition:

    from django.http import HttpResponse
    from acc.models import SystemA, SystemB
    from django.template import Context, loader
    from itertools import chain
    from operator import attrgetter

    def index(request):
      a_list = SystemA.objects.all().order_by('-date')
      b_list = SystemB.objects.all().order_by('-date')
      result_list = sorted(
        chain(a_list, b_list),
        key=attrgetter('date'))
      t = loader.get_template('index.html')
      #c = Context({'result_list': result_list,})
      c = Context({'a_list': a_list,'b_list': b_list,})
      return HttpResponse(t.render(c))

4.) Finally, the template presenting the static HTML page (index.html) is defined as:

    {% if a_list %}
    <ul>
    {% for a in a_list %}
    <li>{{a.date}} | {{a.author}} | {{a.system}} | {{a.description}} | {{a.status}}</li>
    {% endfor %}
    </ul>
    {% endif %}

    {% if b_list %}
    <ul>
    {% for b in b_list %}
    <li>{{b.date}} | {{b.author}} | {{b.system}} | {{b.description}} | {{b.status}}</li>
    {% endfor %}
    </ul>
    {% endif %}

The code is working and I've entered some data from the admin interface. The result:

April 18, 2013 | owta | System A | All jobs went bananas! | FAILED
April 17, 2013 | rash | System A | All Well | OK

April 18, 2013 | owta | System B | All jobs went bananas! | FAILED
April 17, 2013 | rash | System B | All well | OK

My aim is to get a result sorted on date, independently from the models (SystemA/SystemB) in below sort order:

April 17, 2013 | rash | System A | All Well | OK
April 17, 2013 | rash | System B | All well | OK
April 18, 2013 | owta | System A | All jobs went bananas! | FAILED
April 18, 2013 | owta | System B | All jobs went bananas! | FAILED

I've spent a haft week trying to sort this out without success, and I'm a noob into Django. Some help would be much appreciated! Thanks.


Solution

  • "I was into a one-model solution before, but somehow felt that I had to have different classes/models for my systems in order to fetch data nicely into a static page sorted on date from each system"

    Well rash, this is how you would do it with one model. Remember, always try to reduce duplication in your system.

    models.py

    from django.db import models
    
    class Author(models.Model):
        author  = models.CharField(max_length=20)
        def __unicode__(self):
            return '%s' % (self.author)
    
    class System(models.Model):
        SYSTEM_CHOICES = (('A','System A'),('B','System B'))
        author      = models.ForeignKey(Author)
        date        = models.DateField()
        system      = models.CharField(max_length=1, choices=SYSTEM_CHOICES) # see [1]
        description = models.CharField(max_length=300)
        status      = models.CharField(max_length=6)
    

    admin.py

    from django.contrib import admin
    
    class SystemAdmin(admin.ModelAdmin):
        list_filter = ['system'] # See [2]
    
    admin.site.register(System, SystemAdmin)
    

    urls.py

    url(r'^/system/(?P<system>A|B)/list/$', views.SystemListView.as_view(), name='system-list' )
    

    views.py

    from django.views.generic.list import ListView
    from .models import System
    
    class SystemListView(ListView):
        model = System
        context_object_name = "Systems"
    
        def get_queryset(self):
            return super(SystemListView, self) \
              .filter(system = self.kwargs['system']) \
              .order_by(self.request.GET.get('sort') or '-date')
    

    {template_folder}/yourapp/system/list.html

    <h1> System {{ system }}{# See [3] #} </h1>
    <ul>
    {% for sys in Systems %}
      <li>{{sys.date}} | {{sys.author}} | {{sys.description}} | {{sys.status}}</li>
    {% endfor %}
    </ul>
    

    Appendix

    [1] https://docs.djangoproject.com/en/stable/ref/models/fields/#choices
    [2] https://docs.djangoproject.com/en/stable/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_filter
    [3] https://github.com/django/django/blob/master/django/views/generic/detail.py#L99