Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django create report

class Beverage(models.Model):
    name=models.CharField(max_length=255)

    def __unicode__(self):
        return self.name

class Location(models.Model):
    name=models.CharField(max_length=255)
    beverages = models.ManyToManyField(Beverage, through='LocationStandard')
    location_number=models.CharField(max_length=255)
    organization=models.CharField(max_length=255)

    def __unicode__(self):
        return self.name

class LocationStandard(models.Model):
    beverage=models.ForeignKey(Beverage)
    location=models.ForeignKey(Location) #elim this or m2m
    start_units=models.IntegerField()
    fill_to_standard=models.IntegerField(max_length=10)
    order_when_below=models.IntegerField(max_length=10)

class Order(models.Model):
    location=models.ForeignKey(Location) #elim this or m2m
    beverage=models.ForeignKey(Beverage)
    units_ordered=models.IntegerField(max_length=10, default=0)
    order_delivered=models.BooleanField(default=False)
    timestamp=models.DateTimeField(auto_now_add=True)
    user=models.ForeignKey(User)

How can I generate a report that will get me an HTML table with all locations on the x-axis and all beverages on the y-axis. The main thing I am struggling with is just what to query that I can pass the template that I can loop over. Thoughts?

like image 716
jasongonzales Avatar asked Nov 04 '22 23:11

jasongonzales


1 Answers

You can't get them in one query, but you can make something like that (don't want to setup a whole env to test, so use it as a clue, not a working solution):

# you can't do order_by in a template, either do them in the view, or 
# make methods in the model, or make it the Meta default ordering

# print the header, and make sure we got a list of all beverage cached
beverages = Beverage.objects.order_by('name') 
for beverage in beverages:
   print each cell of your header

# print a row for each location
locations = Location.objects.all()
for location in locations:
   print the location name table cell
   location_beverages = iter(location.beverages.order_by('name'))
   # for each beverage, we print a cell. If the beverage is in the 
   # location beverage list, we print a checked cell
   # we use the fact that queryset are iterable to move the cursor
   # only when there is a match
   cur_bev = location_beverages.next()
   for beverage in beverages:
        if beverage == cur_bev:
            print checked table cell
            cur_bev = location_beverages.next()
        else:
            print empty table cell

The intermediary variables to store querysets are very important, as they allow you to benefit from Django queryset cache.

With Django 1.4 or more, you can replace:

locations = Location.objects.all()

By:

locations = Location.objects.prefetch_related('beverages')

To get a serious perf boost.

like image 116
e-satis Avatar answered Nov 15 '22 05:11

e-satis