I am currently working on a site where there are several models which do not have immediate views, but rather are attached to other models via foreign keys. I need to prepare a view in which the data of these models (or rather, their underlying tables) are summed and presented in several columns. I have partially written the views so as to gather the data into a nested set of dictionaries, but since templates do not have any support for dictionaries (to the best that I know, anyway), this is obviously only part of the solution. Can anyone offer an approach that would allow me to populate a dynamically generated Model subclass object with the computed sums and pass it to the template?

asked 13 May '13, 13:08

Schol-R-LEA's gravatar image

accept rate: 0%

can you help us by presenting your code here ?


answered 13 May '13, 15:18

DjangoForum's gravatar image

DjangoForum ♦♦
accept rate: 8%

Yes, what there is of it at least.


from django.db import models

class Advertiser(models.Model):
    name = models.CharField(max_length=127)
    contact_name = models.CharField(max_length=63)
    contact_email = models.EmailField()

    def __unicode__(self):
        return self.name

    class Meta:
        ordering = ['name']

class Ad(models.Model):
    STATUS_CHOICES = (('pending', 'Pending Review'),
                      ('denied', 'Denied'),
                      ('approved', 'Approved'),
                      ('paused', 'Paused'))

    advertiser = models.ForeignKey(Advertiser)
    status = models.CharField(choices=STATUS_CHOICES, default='pending',
    image = models.FileField()
    text = models.CharField(max_length=127)
    bid_per_click = models.DecimalField(decimal_places=2)
    cost = models.DecimalField(decimal_places=2)

    def __unicode__(self):
        return self.text

    class Meta:
        ordering = ['advertiser', 'status', 'impressions']

class AdZone(models.Model):
    name = models.CharField(63)
    ads = models.ManyToManyField(Ad)

    def __unicode__(self):
        return self.name

    class Meta:
        ordering = ['name']

class Site(models.Model):
    name = models.CharField(max_length=255)
    uri = models.URLField()
    zones = models.ManyToManyField(AdZone)

    def __unicode__(self):
        return self.name

    class Meta:
        ordering = ['name']

class Impression(models.Model):
    Ad = models.ForeignKey(Ad)
    timestamp = models.DateTimeField()
    url = models.URLField()

    def __unicode__(self):
        return 'Ad {0} presented at {1} on page {2}'.format(self.ad.name, self.timestamp, self.url)

class Click(models.Model):
    impression = models.ForeignKey(Impression)
    timestamp = models.DateTimeField()
    viewer = models.IPAddressField()

    def __unicode__(self):
        return 'Ad {0} on page {1} followed at {2} by {3}'.format(self.impression.ad.name, 
                                                                  self.timestamp, self.viewer)


from django.template import loader, Context
from django.http import HttpResponse
from models import *

def ads(request, Advertiser=None, Status=None):
    """ Generate the context for the ads page and render the template.

    :param request: HttpRequest
    :param Advertiser: str
    :param Status: str
    :return :HttpResponse
    company = Advertiser
    status = Status

    ad_objs = Ad.objects.all()
    if status is None:
        status = 'all'
        ad_objs = ad_objs.filter(status=status)
    if company is None:
        company = 'All Advertisers'
        ad_objs = ad_objs.filter(advertiser=company)

    ads = list()
    # we need to unroll the ad objects into a dict so we can compute the CTR
    for ad_obj in ad_objs:
        ad = dict()
        ad['image'] = ad_obj.image
        ad['text'] = ad_obj.text
        ad['id'] = ad_obj.id
        ad['advertiser'] = ad_obj.advertiser.name
        ad['status'] = ad_obj.status
        ad['impressions'] = ad_obj.impressions
        ad['clicks'] = ad_obj.clicks
        ad['ctr'] = (ad_obj.clicks / ad_obj.impressions) * 100
        ad['bid_per_click'] = ad_obj.bid_per_click
        ad['cost'] = ad_obj.cost

    tmplt = loader.get_template('ads/ads.html')
    ctxt = Context({'ads': ads, 'status': status, 'advertiser': company})
    return HttpResponse(tmplt.render(ctxt))

def ads_summary(request, Advertiser, Status):

    :param request:HttpRequest
    :param Advertiser: str
    :param Status: str
    :return :HttpResponse
    company = Advertiser
    status = Status

    zones = AdZone.objects.all()
    if status is None:
        status = 'all'
        zones = zones.filter(status=status)
    if company is None:
        company = 'All Advertisers'
        zones = zones.filter(advertiser=company)

    zone_summaries = dict()
    # first we need to get all the zones and create a dictionary of them keyed on the zone ID
    for zone in zones:
        zone_summaries[zone.id] = dict()
        zone_summaries[zone.id]['name'] = zone.name
        zone_summaries[zone.id]['impressions'] = 0
        zone_summaries[zone.id]['clicks'] = 0
        zone_summaries[zone.id]['ctr'] = 0
        zone_summaries[zone.id]['bid_per_click'] = 0
        zone_summaries[zone.id]['cost'] = 0

        for ad in zone.ads:
            impressions = Impression.object.filter(ad=ad.id)
            for impression in impressions:
                zone_summaries[zone.id]['impressions'] += 1
                clicks = Click.objects.filter(impression=impression.id)
                for click in clicks:
                    zone_summaries[zone.id]['clicks'] += 1
            zone_summaries[zone.id]['bid_per_click'] += ad.bid_per_click
            zone_summaries[zone.id]['cost'] += ad.cost

        zone_summaries[zone.id]['ctr'] = (zone_summaries[zone.id]['clicks'] / zone_summaries[zone.id]['impressions']) \
                                         * 100
        zone_summaries[zone.id]['size'] = len(zone)
        zone_summaries[zone.id]['bid_average']= zone_summaries[zone.id]['bid_per_click']/zone_summaries[zone.id]['size']
        zone_summaries[zone.id]['cost_average'] = zone_summaries[zone.id]['cost'] / zone_summaries[zone.id]['size']

    tmplt = loader.get_template('ads/ads_summary.html')
    ctxt = Context({'summary': zone_summaries, 'status': status, 'advertiser': company})
    return HttpResponse(tmplt.render(ctxt))

Needless to say, this won't work as it is; the template would have no way of working with a dict object, as far as I am aware. I was hoping that there was some way to either take what I've got and wrap it in a Model object, or else find some more elegant solution that obviates the need for the this sort of kludge.

As you can see, this was interrupted partway in the process of making changes to the Models. While this was rather pressing earlier, I was taken off of the project earlier today, so I now am mostly inquiring to improve my Django development for the future.


answered 13 May '13, 20:21

Schol-R-LEA's gravatar image

accept rate: 0%

edited 13 May '13, 20:24

Your answer
toggle preview

Follow this question

By Email:

Once you sign in you will be able to subscribe for any updates here



Answers and Comments

Markdown Basics

  • *italic* or _italic_
  • **bold** or __bold__
  • link:[text](http://url.com/ "Title")
  • image?![alt text](/path/img.jpg "Title")
  • numbered list: 1. Foo 2. Bar
  • to add a line break simply add two spaces to where you would like the new line to be.
  • basic HTML tags are also supported



Asked: 13 May '13, 13:08

Seen: 469 times

Last updated: 13 May '13, 20:24

powered by OSQA