class StudentProfile(models.Model): FRESHMAN = 0 SOPHOMORE = 1 JUNIOR = 2 SENIOR = 3 GRADE_LEVEL_CHOICES = ( (FRESHMAN, 'Freshman'), (SOPHOMORE, 'Sophomore'), (JUNIOR, 'Junior'), (SENIOR, 'Senior'), ) user_profile = models.OneToOneField(UserProfile, related_name='student_profile', null=True) # TODO: set student_id to unique = True in production student_id = models.CharField("Student ID", max_length=10, validators=[student_id_validator]) grade_level = models.IntegerField("Grade Level", default=FRESHMAN, choices=GRADE_LEVEL_CHOICES) objects = GetOrNoneManager() def __str__(self): return '%s - student profile' % self.user_profile def save(self, *args, **kwargs): if not self.pk: self.pk = self.user_profile.user.pk super(StudentProfile, self).save(*args, **kwargs) @classmethod def generate_random_objects(cls, count): rand_1 = random.randint(140, size=count) rand_2 = random.randint(140, size=count) rand_3 = random.randint(1100000000, 1100999999, size=count) rand_4 = random.randint(3, size=count) user_pk = User.objects.latest('pk').pk + 1 generated_count = 0 for i in range(0, count): first_name = first_names[rand_1.item(i)] last_name = last_names[rand_2.item(i)] student_id = rand_3.item(i) grade_level = rand_4.item(i) user = User.objects.create_user( username=user_pk, password=user_pk, first_name=first_name, last_name=last_name, ) user_profile = UserProfile.objects.create( user=user, mobile='6787901506', is_student=True, ) student_profile= StudentProfile.objects.create( user_profile=user_profile, student_id = student_id, grade_level=grade_level, ) user_pk += 1 generated_count += 1 print('Generated StudentProfile %d (UserProfile %d User %d)' %(student_profile.pk, user_profile.pk, user.pk)) return generated_count
class Category(models.Model): COLOR_CHOICES = [ '#f2f3f4', '#f3c300', '#875692', '#f38400', '#a1caf1', '#be0032', '#c2b280', '#848482', '#008856', '#e68fac', '#0067a5', '#f99379', '#604e97', '#f6a600', '#b3446c', '#dcd300', '#882d17', '#8db600', '#654522', '#e25822', '#2b3d26', ] name = models.CharField(max_length=30) color = RGBColorField(unique=True, colors=COLOR_CHOICES) objects = GetOrNoneManager() class Meta: ordering = ('name', ) verbose_name_plural = "categories" def __str__(self): return self.name @classmethod def merge(cls, categories, new_name=None, new_color=None): count = len(categories) if count > 0: first = categories[0] for i in range(1, count): categories[i].announcements.all().update(category=first) categories[i].events.all().update(category=first) categories[i].polls.all().update(category=first) categories[i].delete() # Keep first category's name and color by default if new_name: first.name = new_name if new_color: first.color = new_color first.save() return True
class TeacherProfile(models.Model): user_profile = models.OneToOneField(UserProfile, related_name='teacher_profile', null=True) room = models.CharField("Room Number", unique=True, max_length=6) objects = GetOrNoneManager() def __str__(self): return '%s - teacher profile' % self.user_profile def save(self, *args, **kwargs): if not self.pk: self.pk = self.user_profile.user.pk super(TeacherProfile, self).save(*args, **kwargs)
class ImageLink(models.Model): # NOTE: set on_delete=models.CASCADE and remove null=True for production announcement = models.ForeignKey(Announcement, related_name='image_links', blank=True, null=True, on_delete=models.SET_NULL) image_link = models.URLField() image_file = ProcessedImageField( upload_to='announcements/images/', blank=True, null=True, processors=[ResizeToFit(settings.IMAGE_WIDTH, settings.IMAGE_HEIGHT)], format='JPEG', options={'quality': settings.IMAGE_QUALITY}, ) image_file_thumbnail = ImageSpecField( source='image_file', processors=[ResizeToFill(settings.THUMBNAIL_WIDTH, settings.THUMBNAIL_HEIGHT)], format='JPEG', options={'quality': settings.THUMBNAIL_QUALITY}, ) objects = GetOrNoneManager() def __str__(self): return os.path.basename(self.image_file.path) def save(self, *args, **kwargs): content = self.download_image() if content: name = os.path.basename(self.image_link) self.image_file.save(name, content, save=False) super(ImageLink, self).save(*args, **kwargs) def download_image(self): r = requests.get(self.image_link) if r.status_code == 200: img = Image.open(BytesIO(r.content)) if img: img_io = BytesIO() img.save(img_io, 'JPEG') return ContentFile(img_io.getvalue()) return None def image_exists(self): try: r = requests.head(self.image_link) except: return False return r.status_code == 200 @classmethod def create_image_set(cls): for i in range(0, len(random_images)): i = ImageLink(image_link=random_images.item(i)) i.save()
class Choice(models.Model): poll = models.ForeignKey(Poll, related_name='choices', on_delete=models.CASCADE) content = models.CharField(max_length=200) vote_count = models.IntegerField(default=0, blank=True) objects = GetOrNoneManager() class Meta: ordering = ('poll', ) def __str__(self): return self.content def update_vote_count(self): self.vote_count = self.votes.count() self.save()
class UserProfile(models.Model): user = models.OneToOneField(User, related_name='profile', null=True) # TODO: set mobile to unique = True in production mobile = models.CharField("Phone Number", max_length=10, validators=[mobile_validator]) # TODO: create a signal (or just update save function of related model) that automatically sets these values when a related student/teacher profile object is saved is_student = models.BooleanField(default=False) is_teacher = models.BooleanField(default=False) categories_hidden_announcements = models.ManyToManyField(Category, related_name="user_profiles_with_category_hidden_for_announcements", blank=True) categories_hidden_events = models.ManyToManyField(Category, related_name="user_profiles_with_category_hidden_for_events", blank=True) categories_hidden_polls = models.ManyToManyField(Category, related_name="user_profiles_with_category_hidden_for_polls", blank=True) objects = GetOrNoneManager() def __str__(self): return self.user.get_full_name() def save(self, *args, **kwargs): if not self.pk: self.pk = self.user.pk super(UserProfile, self).save(*args, **kwargs)
class Vote(models.Model): voter = models.ForeignKey(UserProfile, related_name='votes', on_delete=models.CASCADE) choice = models.ForeignKey(Choice, related_name='votes', on_delete=models.CASCADE) poll = models.ForeignKey(Poll, related_name='votes', on_delete=models.CASCADE) objects = GetOrNoneManager() class Meta: ordering = ('poll', 'choice') def __str__(self): return "%s - %s" % (self.choice, self.voter) def save(self, *args, **kwargs): p = self.choice.poll self.poll = p previous_vote = Vote.objects.get_or_none(voter=self.voter, poll=self.poll) if previous_vote: original_choice = previous_vote.choice original_choice.vote_count -= 1 original_choice.save() previous_vote.delete() new_choice = Choice.objects.get_or_none(pk=self.choice.pk) if new_choice.vote_count % 100 == 0: new_choice.update_vote_count() new_choice.vote_count += 1 new_choice.save() p.update_vote_count() super(Vote, self).save(*args, **kwargs)
class Poll(models.Model): content = models.CharField(max_length=200) author = models.ForeignKey(UserProfile, related_name="polls", blank=True, null=True, on_delete=models.SET_NULL) date_open = models.DateTimeField(auto_now_add=True) date_close = models.DateTimeField(blank=True, null=True) is_open = models.BooleanField(default=True) category = models.ForeignKey(Category, related_name='polls', blank=True, null=True, on_delete=models.SET_NULL) rank = models.IntegerField(default=0, blank=True) total_vote_count = models.IntegerField(default=0, blank=True) # voters = models.ManyToManyField(UserProfile, related_name="polls_submitted", blank=True) #TODO: allow visibility to be set for each poll (students, parents, teachers, etc.) objects = GetOrNoneManager() class Meta: ordering = ('is_open', 'rank', '-date_close', '-date_open') def __str__(self): return "%s (%s)" % (self.content, self.category) def save(self, *args, **kwargs): if not self.is_open and not self.date_close: self.date_close = timezone.now() else: self.date_close = None super(Poll, self).save(*args, **kwargs) def get_absolute_url(self): return reverse('polls:detail', args=[str(self.pk)]) def update_vote_count(self): total_vote_count = 0 for c in self.choices.all(): total_vote_count += c.vote_count self.total_vote_count = total_vote_count self.save() def get_vote(self, user_profile_pk): for c in self.choices.all(): vote = UserProfile.objects.get( pk=user_profile_pk).votes.get_or_none(choice_id=c.pk) if vote: return vote return None def pin(self): self.rank = Poll.get_top_rank() + 1 self.save() def unpin(self): self.rank = 0 self.save() @classmethod def get_top_rank(cls): return cls.objects.all().first().rank @classmethod def clean_ranks(cls): pinned = Announcement.objects.filter(rank__gt=0).reverse() i = 1 for a in pinned: a.rank = i a.save() i += 1 @classmethod def generate_random_objects(cls, count, add_votes): poll_manager = Poll.objects choice_manager = Choice.objects user_profiles = UserProfile.objects.all() user_profile_count = user_profiles.count() if user_profile_count < 100: StudentProfile.generate_random_objects(100) voter_count = 100 # Contents rand_1 = random.randint(100, size=count) # first word rand_2 = random.randint(5, 11, size=count) # length # Authors rand_3 = random.randint(user_profile_count, size=count) # Categories categories = Category.objects.all() categories_count = categories.count() rand_4 = random.randint(categories_count, size=count) # Choices rand_5 = random.randint(2, 6, size=count) # status rand_6 = random.randint(3, size=count) # Generator loop generated_count = 0 for i in range(0, count): # Random Content content = lorem_random[rand_1.item(i)] + ' ' content_length = rand_2.item(i) content_rand = random.randint(200, size=content_length) for c in range(0, content_length): content += lorem_random[content_rand[c]] + ' ' content += '?' # Random Author author = user_profiles[rand_3.item(i)] # Random Category category = categories[rand_4.item(i)] # Random Status is_open = True if rand_6.item(i) == 2: is_open = False # Create Object p = poll_manager.create(content=content, author=author, category=category, is_open=is_open) # Random Choices choice_count = rand_5.item(i) for x in range(0, choice_count): choice_content = lorem_random[rand_1.item(i)] + ' ' choice_length = rand_2.item(i) choice_rand = random.randint(200, size=choice_length) for y in range(0, choice_length): choice_content += lorem_random[choice_rand[y]] + ' ' c = choice_manager.create(poll=p, content=choice_content) # Random Votes vote_count = 0 if add_votes: vote_count = p.generate_random_votes(user_profiles, choice_count, voter_count) generated_count += 1 print('Generated Poll %d (%d choices, %d votes, open: %s)' % (p.pk, choice_count, vote_count, p.is_open)) return generated_count def generate_random_votes(self, user_profiles, choice_count, voter_count): vote_manager = Vote.objects rand_votes = random.randint(choice_count, size=voter_count) choices = self.choices.all() vote_counter = 0 for i in range(0, voter_count): voter = user_profiles[i] choice = choices[rand_votes.item(i)] v = vote_manager.create(poll=self, choice=choice, voter=voter) print('Generated Vote %d (Userprofile %d, Choice %d)' % (v.pk, voter.pk, choice.pk)) vote_counter += 1 return vote_counter