annotate gpp/downloads/models.py @ 208:2022c0409296

Fix #76; use POST to get downloads to avoid having side-effects (updating hit count) on GETs.
author Brian Neal <bgneal@gmail.com>
date Wed, 05 May 2010 03:12:15 +0000
parents 272d3a8c98e8
children 77b606e0ad5f
rev   line source
gremmie@1 1 """
gremmie@1 2 Models for the downloads application.
gremmie@1 3 """
gremmie@1 4 import os
gremmie@1 5
gremmie@1 6 import datetime
gremmie@1 7 from django.db import models
gremmie@1 8 from django.contrib.auth.models import User
gremmie@1 9 from django.template.defaultfilters import filesizeformat
gremmie@1 10
bgneal@128 11 from core.markup import site_markup
bgneal@124 12
gremmie@1 13
gremmie@1 14 class Category(models.Model):
gremmie@1 15 """Downloads belong to categories."""
gremmie@1 16 title = models.CharField(max_length=64)
gremmie@1 17 description = models.TextField(blank=True)
bgneal@192 18 count = models.IntegerField(default=0, blank=True)
gremmie@1 19
gremmie@1 20 class Meta:
gremmie@1 21 verbose_name_plural = 'Categories'
gremmie@1 22 ordering = ('title', )
gremmie@1 23
gremmie@1 24 def __unicode__(self):
gremmie@1 25 return self.title
gremmie@1 26
gremmie@1 27
gremmie@1 28 def download_path(instance, filename):
gremmie@1 29 """
gremmie@1 30 Creates a path for a download. Uses the current date to avoid filename
gremmie@1 31 clashes. Uses the current microsecond also to make the directory name
gremmie@1 32 harder to guess.
gremmie@1 33 """
gremmie@1 34 now = datetime.datetime.now()
gremmie@1 35 parts = ['downloads']
gremmie@1 36 parts.extend([str(p) for p in (now.year, now.month, now.day, now.microsecond)])
gremmie@1 37 parts.append(filename)
gremmie@1 38 return os.path.join(*parts)
gremmie@1 39
gremmie@1 40
gremmie@1 41 class PublicDownloadManager(models.Manager):
gremmie@1 42 """The manager for all public downloads."""
gremmie@1 43 def get_query_set(self):
bgneal@190 44 return super(PublicDownloadManager, self).get_query_set().filter(
bgneal@190 45 is_public=True).select_related()
gremmie@1 46
gremmie@1 47
bgneal@204 48 class DownloadBase(models.Model):
bgneal@204 49 """Abstract model to collect common download fields."""
gremmie@1 50 title = models.CharField(max_length=128)
gremmie@1 51 category = models.ForeignKey(Category)
gremmie@1 52 description = models.TextField()
gremmie@1 53 html = models.TextField(blank=True)
gremmie@1 54 file = models.FileField(upload_to=download_path)
gremmie@1 55 user = models.ForeignKey(User)
bgneal@204 56 date_added = models.DateTimeField()
gremmie@1 57 ip_address = models.IPAddressField('IP Address')
bgneal@204 58
bgneal@204 59 class Meta:
bgneal@204 60 abstract = True
bgneal@204 61
bgneal@204 62 def size(self):
bgneal@204 63 return filesizeformat(self.file.size)
bgneal@204 64
bgneal@204 65
bgneal@204 66 class PendingDownload(DownloadBase):
bgneal@204 67 """This model represents pending downloads created by users. These pending
bgneal@204 68 downloads must be approved by an admin before they turn into "real"
bgneal@204 69 Downloads and are visible on site.
bgneal@204 70 """
bgneal@204 71 class Meta:
bgneal@204 72 ordering = ('date_added', )
bgneal@204 73
bgneal@204 74 def __unicode__(self):
bgneal@204 75 return self.title
bgneal@204 76
bgneal@204 77 def save(self, *args, **kwargs):
bgneal@204 78 if not self.pk:
bgneal@204 79 self.date_added = datetime.datetime.now()
bgneal@204 80 self.html = site_markup(self.description)
bgneal@204 81 super(PendingDownload, self).save(*args, **kwargs)
bgneal@204 82
bgneal@204 83
bgneal@204 84 class Download(DownloadBase):
bgneal@204 85 """Model to represent a download."""
gremmie@1 86 hits = models.IntegerField(default=0)
gremmie@1 87 average_score = models.FloatField(default=0.0)
gremmie@1 88 total_votes = models.IntegerField(default=0)
gremmie@1 89 is_public = models.BooleanField(default=False, db_index=True)
gremmie@1 90
gremmie@1 91 # Managers:
gremmie@1 92 objects = models.Manager()
gremmie@1 93 public_objects = PublicDownloadManager()
gremmie@1 94
gremmie@1 95 def __unicode__(self):
gremmie@1 96 return self.title
gremmie@1 97
bgneal@14 98 @models.permalink
bgneal@14 99 def get_absolute_url(self):
bgneal@23 100 return ('downloads-details', [str(self.id)])
bgneal@14 101
bgneal@182 102 def save(self, *args, **kwargs):
bgneal@128 103 self.html = site_markup(self.description)
bgneal@182 104 super(Download, self).save(*args, **kwargs)
gremmie@1 105
gremmie@1 106 def vote(self, vote_value):
gremmie@1 107 """receives a vote_value and updates internal score accordingly"""
gremmie@1 108 total_score = self.average_score * self.total_votes
gremmie@1 109 total_score += vote_value
gremmie@1 110 self.total_votes += 1
gremmie@1 111 self.average_score = total_score / self.total_votes
gremmie@1 112 return self.average_score
gremmie@1 113
gremmie@1 114
gremmie@1 115 class AllowedExtensionManager(models.Manager):
gremmie@1 116 def get_extension_list(self):
gremmie@1 117 return self.values_list('extension', flat=True)
gremmie@1 118
gremmie@1 119
gremmie@1 120 class AllowedExtension(models.Model):
gremmie@1 121 """Model to represent the list of allowed file extensions."""
bgneal@206 122 extension = models.CharField(max_length=8, help_text="e.g. .txt")
gremmie@1 123
gremmie@1 124 objects = AllowedExtensionManager()
gremmie@1 125
gremmie@1 126 def __unicode__(self):
gremmie@1 127 return self.extension
gremmie@1 128
gremmie@1 129 class Meta:
gremmie@1 130 ordering = ('extension', )
gremmie@1 131
gremmie@1 132
gremmie@1 133 class VoteRecord(models.Model):
gremmie@1 134 """Model to record the date that a user voted on a download."""
gremmie@1 135 download = models.ForeignKey(Download)
gremmie@1 136 user = models.ForeignKey(User)
gremmie@1 137 vote_date = models.DateTimeField(auto_now_add=True)
gremmie@1 138
gremmie@1 139 def __unicode__(self):
bgneal@192 140 return u"%s voted on '%s' on %s" % (
gremmie@1 141 self.user.username,
gremmie@1 142 self.download.title,
gremmie@1 143 self.vote_date.strftime('%b %d, %Y %H:%M:%S'))
gremmie@1 144
gremmie@1 145 class Meta:
gremmie@1 146 ordering = ('-vote_date', )