3 # Copyright (C) 2012 FinalsClub Foundation
6 Models for the courses django app.
7 Handles courses, and their related models
8 Courses are the first class object, they contain notes.
9 Courses have a manytoone relation to schools.
13 from django.db import models
14 from django.template import defaultfilters
15 from karmaworld.settings.manual_unique_together import auto_add_check_unique_together
18 class School(models.Model):
19 """ A grouping that contains many courses """
20 name = models.CharField(max_length=255)
21 slug = models.SlugField(max_length=150, null=True)
22 location = models.CharField(max_length=255, blank=True, null=True)
23 url = models.URLField(max_length=511, blank=True)
24 # Facebook keeps a unique identifier for all schools
25 facebook_id = models.BigIntegerField(blank=True, null=True)
26 # United States Department of Education institution_id
27 usde_id = models.BigIntegerField(blank=True, null=True)
28 file_count = models.IntegerField(default=0)
29 priority = models.BooleanField(default=0)
30 alias = models.CharField(max_length=255, null=True, blank=True)
31 hashtag = models.CharField(max_length=16, null=True, blank=True, unique=True, help_text='School abbreviation without #')
34 """ Sort School by file_count descending, name abc=> """
35 ordering = ['-file_count','-priority', 'name']
37 def __unicode__(self):
40 def save(self, *args, **kwargs):
41 """ Save school and generate a slug if one doesn't exist """
43 self.slug = defaultfilters.slugify(self.name)
44 super(School, self).save(*args, **kwargs)
47 def autocomplete_search_fields():
48 return ("name__icontains",)
50 def update_note_count(self):
51 """ Update the School.file_count by summing the
52 contained course.file_count
54 self.file_count = sum([course.file_count for course in self.course_set.all()])
58 class Department(models.Model):
59 """ Department within a School. """
60 name = models.CharField(max_length=255)
61 school = models.ForeignKey(School) # Should this be optional ever?
62 slug = models.SlugField(max_length=150, null=True)
63 url = models.URLField(max_length=511, blank=True, null=True)
65 def __unicode__(self):
68 def save(self, *args, **kwargs):
69 """ Save department and generate a slug if one doesn't exist """
71 self.slug = defaultfilters.slugify(self.name)
72 super(Department, self).save(*args, **kwargs)
75 class Professor(models.Model):
77 Track professors for courses.
79 name = models.CharField(max_length=255)
80 email = models.EmailField(blank=True, null=True)
82 def __unicode__(self):
83 return u'Professor: {0}'.format(self.name)
86 class ProfessorAffiliation(models.Model):
88 Track professors for departments. (many-to-many)
90 professor = models.ForeignKey(Professor)
91 department = models.ForeignKey(Department)
93 def __unicode__(self):
94 return u'Professor {0} working for {1}'.format(self.professor.name, self.department.name)
97 # many-to-many across both fields,
98 # but (prof, dept) as a tuple should only appear once.
99 unique_together = ('professor', 'department',)
102 class Course(models.Model):
103 """ First class object that contains many notes.Note objects """
105 name = models.CharField(max_length=255)
106 slug = models.SlugField(max_length=150, null=True)
107 # department should remove nullable when school gets yoinked
108 department = models.ForeignKey(Department, blank=True, null=True)
109 # school is an appendix: the kind that gets swollen and should be removed
111 school = models.ForeignKey(School)
112 file_count = models.IntegerField(default=0)
114 desc = models.TextField(max_length=511, blank=True, null=True)
115 url = models.URLField(max_length=511, blank=True, null=True)
117 # instructor_* is vestigial, replaced by Professor+ProfessorTaught models.
118 instructor_name = models.CharField(max_length=255, blank=True, null=True)
119 instructor_email = models.EmailField(blank=True, null=True)
121 updated_at = models.DateTimeField(default=datetime.datetime.utcnow)
123 created_at = models.DateTimeField(auto_now_add=True)
125 # Number of times this course has been flagged as abusive/spam.
126 flags = models.IntegerField(default=0,null=False)
130 ordering = ['-file_count', 'school', 'name']
131 unique_together = ('school', 'name', 'instructor_name')
132 verbose_name = 'course'
133 verbose_name_plural = 'courses'
135 def __unicode__(self):
136 return u"{0}: {1}".format(self.name, self.school)
138 def get_absolute_url(self):
139 """ return url based on school slug and self slug """
140 return u"/{0}/{1}".format(self.school.slug, self.slug)
142 def save(self, *args, **kwargs):
143 """ Save school and generate a slug if one doesn't exist """
144 super(Course, self).save(*args, **kwargs) # generate a self.id
146 self.slug = defaultfilters.slugify("%s %s" % (self.name, self.id))
147 self.save() # Save the slug
149 def get_updated_at_string(self):
150 """ return the formatted style for datetime strings """
151 return self.updated_at.strftime("%I%p // %a %b %d %Y")
154 def autocomplete_search_fields():
155 return ("name__icontains",)
157 def update_note_count(self):
158 """ Update self.file_count by summing the note_set """
159 self.file_count = self.note_set.count()
163 class ProfessorTaught(models.Model):
165 Track professors teaching courses. (many-to-many)
167 professor = models.ForeignKey(Professor)
168 course = models.ForeignKey(Course)
170 def __unicode__(self):
171 return u'Professor {0} taught {1}'.format(self.professor.name, self.course.name)
174 # many-to-many across both fields,
175 # but (prof, course) as a tuple should only appear once.
176 unique_together = ('professor', 'course',)
179 # Enforce unique constraints even when we're using a database like
180 # SQLite that doesn't understand them
181 auto_add_check_unique_together(Course)
182 auto_add_check_unique_together(ProfessorAffiliation)
183 auto_add_check_unique_together(ProfessorTaught)