Commit d6a663553957fa87b9715b4f75f5bfb4afb551ba
1 parent
86fde4fa00
Exists in
master
Fixed up some model errors, added docstrings to some
Showing 2 changed files with 195 additions and 36 deletions Side-by-side Diff
flashcards/migrations/0003_auto_20150429_0344.py
View file @
d6a6635
1 | +# -*- coding: utf-8 -*- | |
2 | +from __future__ import unicode_literals | |
3 | + | |
4 | +from django.db import models, migrations | |
5 | + | |
6 | + | |
7 | +class Migration(migrations.Migration): | |
8 | + | |
9 | + dependencies = [ | |
10 | + ('flashcards', '0002_auto_20150429_0248'), | |
11 | + ] | |
12 | + | |
13 | + operations = [ | |
14 | + migrations.AlterModelOptions( | |
15 | + name='class', | |
16 | + options={'ordering': ['-quarter']}, | |
17 | + ), | |
18 | + migrations.AlterModelOptions( | |
19 | + name='flashcard', | |
20 | + options={'ordering': ['-pushed']}, | |
21 | + ), | |
22 | + migrations.RenameField( | |
23 | + model_name='class', | |
24 | + old_name='professor', | |
25 | + new_name='instructor', | |
26 | + ), | |
27 | + migrations.RemoveField( | |
28 | + model_name='flashcard', | |
29 | + name='hidden', | |
30 | + ), | |
31 | + migrations.AddField( | |
32 | + model_name='flashcard', | |
33 | + name='hide_reason', | |
34 | + field=models.CharField(help_text=b'Reason for hiding this card', max_length=255, blank=True), | |
35 | + ), | |
36 | + migrations.AddField( | |
37 | + model_name='flashcard', | |
38 | + name='is_hidden', | |
39 | + field=models.BooleanField(default=False), | |
40 | + ), | |
41 | + migrations.AlterField( | |
42 | + model_name='flashcard', | |
43 | + name='associated_class', | |
44 | + field=models.ForeignKey(help_text=b'The class with which the card is associated', to='flashcards.Class'), | |
45 | + ), | |
46 | + migrations.AlterField( | |
47 | + model_name='flashcard', | |
48 | + name='mask', | |
49 | + field=models.ForeignKey(blank=True, to='flashcards.FlashcardMask', help_text=b'The default mask for this card', null=True), | |
50 | + ), | |
51 | + migrations.AlterField( | |
52 | + model_name='flashcard', | |
53 | + name='material_date', | |
54 | + field=models.DateTimeField(help_text=b'The date with which the card is associated'), | |
55 | + ), | |
56 | + migrations.AlterField( | |
57 | + model_name='flashcard', | |
58 | + name='previous', | |
59 | + field=models.ForeignKey(blank=True, to='flashcards.Flashcard', help_text=b'The previous version of this card, if one exists', null=True), | |
60 | + ), | |
61 | + migrations.AlterField( | |
62 | + model_name='flashcard', | |
63 | + name='pushed', | |
64 | + field=models.DateTimeField(help_text=b'When the card was first pushed', auto_now_add=True), | |
65 | + ), | |
66 | + migrations.AlterField( | |
67 | + model_name='flashcard', | |
68 | + name='text', | |
69 | + field=models.CharField(help_text=b'The text on the card', max_length=255), | |
70 | + ), | |
71 | + migrations.AlterField( | |
72 | + model_name='userflashcard', | |
73 | + name='mask', | |
74 | + field=models.ForeignKey(help_text=b"A mask which overrides the card's mask", to='flashcards.FlashcardMask'), | |
75 | + ), | |
76 | + migrations.AlterField( | |
77 | + model_name='userflashcard', | |
78 | + name='pulled', | |
79 | + field=models.DateTimeField(help_text=b'When the user pulled the card', null=True, blank=True), | |
80 | + ), | |
81 | + migrations.AlterField( | |
82 | + model_name='userflashcard', | |
83 | + name='unpulled', | |
84 | + field=models.DateTimeField(help_text=b'When the user unpulled this card', null=True, blank=True), | |
85 | + ), | |
86 | + migrations.AlterField( | |
87 | + model_name='userflashcardreview', | |
88 | + name='blanked_word', | |
89 | + field=models.CharField(help_text=b'The character range which was blanked', max_length=8, blank=True), | |
90 | + ), | |
91 | + migrations.AlterField( | |
92 | + model_name='userflashcardreview', | |
93 | + name='correct', | |
94 | + field=models.NullBooleanField(help_text=b"The user's self-evaluation of their response"), | |
95 | + ), | |
96 | + migrations.AlterField( | |
97 | + model_name='userflashcardreview', | |
98 | + name='response', | |
99 | + field=models.CharField(help_text=b"The user's response", max_length=255, null=True, blank=True), | |
100 | + ), | |
101 | + migrations.AlterUniqueTogether( | |
102 | + name='class', | |
103 | + unique_together=set([('department', 'course_num', 'quarter', 'instructor')]), | |
104 | + ), | |
105 | + ] |
flashcards/models.py
View file @
d6a6635
1 | 1 | from django.contrib.auth.models import User |
2 | -from django.db import models | |
2 | +from django.db.models import * | |
3 | 3 | |
4 | 4 | |
5 | -class UserFlashcard(models.Model): | |
5 | +class UserFlashcard(Model): | |
6 | 6 | """ |
7 | 7 | Represents the relationship between a user and a flashcard by: |
8 | 8 | 1. A user has a flashcard in their deck |
9 | 9 | 2. A user used to have a flashcard in their deck |
10 | 10 | 3. A user has a flashcard hidden from them |
11 | 11 | """ |
12 | - user = models.ForeignKey(User) | |
13 | - mask = models.ForeignKey('FlashcardMask') | |
14 | - pulled = models.DateTimeField(null=True) | |
15 | - flashcard = models.ForeignKey('Flashcard') | |
16 | - unpulled = models.DateTimeField(null=True) | |
12 | + user = ForeignKey(User) | |
13 | + mask = ForeignKey('FlashcardMask', help_text="A mask which overrides the card's mask") | |
14 | + pulled = DateTimeField(blank=True, null=True, help_text="When the user pulled the card") | |
15 | + flashcard = ForeignKey('Flashcard') | |
16 | + unpulled = DateTimeField(blank=True, null=True, help_text="When the user unpulled this card") | |
17 | 17 | |
18 | 18 | class Meta: |
19 | + # There can be at most one UserFlashcard for each User and Flashcard | |
19 | 20 | unique_together = (('user', 'flashcard'),) |
20 | 21 | index_together = ["user", "flashcard"] |
22 | + # By default, order by most recently pulled | |
21 | 23 | ordering = ['-pulled'] |
22 | 24 | |
23 | 25 | def is_hidden(self): |
26 | + """ | |
27 | + A card is hidden only if a user has not ever added it to their deck. | |
28 | + :return: Whether the flashcard is hidden from the user | |
29 | + """ | |
24 | 30 | return not self.pulled |
25 | 31 | |
26 | - def is_active(self): | |
32 | + def is_in_deck(self): | |
33 | + """ | |
34 | + :return:Whether the flashcard is in the user's deck | |
35 | + """ | |
27 | 36 | return self.pulled and not self.unpulled |
28 | 37 | |
29 | 38 | |
30 | -class FlashcardMask(models.Model): | |
31 | - ranges = models.CharField(max_length=255) | |
39 | +class FlashcardMask(Model): | |
40 | + """ | |
41 | + A serialized list of character ranges that can be blanked out during review. | |
42 | + This is encoded as '13-145,150-195' | |
43 | + """ | |
44 | + ranges = CharField(max_length=255) | |
32 | 45 | |
33 | 46 | |
34 | -class Flashcard(models.Model): | |
35 | - text = models.CharField(max_length=255) | |
36 | - associated_class = models.ForeignKey('Class') | |
37 | - pushed = models.DateTimeField() | |
38 | - material_date = models.DateTimeField() | |
39 | - previous = models.ForeignKey('Flashcard', null=True) | |
40 | - author = models.ForeignKey(User) | |
41 | - hidden = models.CharField(null=True, blank=True, max_length=255) | |
42 | - mask = models.ForeignKey(FlashcardMask, null=True) | |
47 | +class Flashcard(Model): | |
48 | + text = CharField(max_length=255, help_text='The text on the card') | |
49 | + associated_class = ForeignKey('Class', help_text='The class with which the card is associated') | |
50 | + pushed = DateTimeField(auto_now_add=True, help_text="When the card was first pushed") | |
51 | + material_date = DateTimeField(help_text="The date with which the card is associated") | |
52 | + previous = ForeignKey('Flashcard', null=True, blank=True, | |
53 | + help_text="The previous version of this card, if one exists") | |
54 | + author = ForeignKey(User) | |
55 | + is_hidden = BooleanField(default=False) | |
56 | + hide_reason = CharField(blank=True, max_length=255, help_text="Reason for hiding this card") | |
57 | + mask = ForeignKey(FlashcardMask, blank=True, null=True, help_text="The default mask for this card") | |
43 | 58 | |
44 | - def is_visible_to(self, user): | |
45 | - result = self.userflashcard_set.filter(user=user) | |
59 | + class Meta: | |
60 | + # By default, order by most recently pushed | |
61 | + ordering = ['-pushed'] | |
46 | 62 | |
63 | + def is_hidden_from(self, user): | |
64 | + """ | |
65 | + A card can be hidden globally, but if a user has the card in their deck, | |
66 | + this visibility overrides a global hide. | |
67 | + :param user: | |
68 | + :return: Whether the card is hidden from the user. | |
69 | + """ | |
70 | + result = user.userflashcard_set.filter(flashcard=self) | |
71 | + if not result.exists(): return self.is_hidden | |
72 | + return result[0].is_hidden() | |
73 | + | |
74 | + | |
47 | 75 | @classmethod |
48 | 76 | def cards_visible_to(cls, user): |
49 | - return cls.objects.filter(hidden=False).exclude(userflashcard=user, | |
50 | - userflashcard__pulled=None) | |
77 | + """ | |
78 | + :param user: | |
79 | + :return: A queryset with all cards that should be visible to a user. | |
80 | + """ | |
81 | + return cls.objects.filter(hidden=False).exclude(userflashcard=user, userflashcard__pulled=None) | |
51 | 82 | |
52 | 83 | |
53 | -class UserFlashcardReview(models.Model): | |
54 | - user_flashcard = models.ForeignKey(UserFlashcard) | |
55 | - when = models.DateTimeField() | |
56 | - blanked_word = models.CharField(max_length=8) | |
57 | - response = models.CharField(max_length=255, blank=True, null=True) | |
58 | - correct = models.NullBooleanField() | |
84 | +class UserFlashcardReview(Model): | |
85 | + """ | |
86 | + An event of a user reviewing a flashcard. | |
87 | + """ | |
88 | + user_flashcard = ForeignKey(UserFlashcard) | |
89 | + when = DateTimeField() | |
90 | + blanked_word = CharField(max_length=8, blank=True, help_text="The character range which was blanked") | |
91 | + response = CharField(max_length=255, blank=True, null=True, help_text="The user's response") | |
92 | + correct = NullBooleanField(help_text="The user's self-evaluation of their response") | |
59 | 93 | |
94 | + def status(self): | |
95 | + """ | |
96 | + There are three stages of a review object: | |
97 | + 1. the user has been shown the card | |
98 | + 2. the user has answered the card | |
99 | + 3. the user has self-evaluated their responses's correctness | |
100 | + :return: string (evaluated, answered, viewed) | |
101 | + """ | |
102 | + if self.correct != None: return "evaluated" | |
103 | + if self.response: return "answered" | |
104 | + return "viewed" | |
60 | 105 | |
61 | -class Class(models.Model): | |
62 | - department = models.CharField(max_length=50) | |
63 | - course_num = models.IntegerField() | |
64 | - name = models.CharField(max_length=50) | |
65 | - professor = models.CharField(max_length=50) | |
66 | - quarter = models.CharField(max_length=4) | |
67 | - members = models.ManyToManyField(User) | |
106 | + | |
107 | +class Class(Model): | |
108 | + """ | |
109 | + A UCSD course taught by an instructor during a quarter. | |
110 | + Different sections taught by the same instructor in the same quarter are considered identical.s | |
111 | + """ | |
112 | + department = CharField(max_length=50) | |
113 | + course_num = IntegerField() | |
114 | + name = CharField(max_length=50) | |
115 | + instructor = CharField(max_length=50) | |
116 | + quarter = CharField(max_length=4) | |
117 | + members = ManyToManyField(User) | |
118 | + | |
119 | + class Meta: | |
120 | + unique_together = (('department', 'course_num', 'quarter', 'instructor'),) | |
121 | + ordering = ['-quarter'] |