Add new tables for the database
- Author
- Maarten 'Vngngdn' Vangeneugden
- Date
- Nov. 15, 2017, 7:21 p.m.
- Hash
- 35d48d7399ca4e87c9820a7d256c50b2ede8d4e4
- Parent
- c3f5bcfa37c056eeee3908d148ff037aec95e1fc
- Modified files
- courses/models.py
- joeni/models.py
courses/models.py ¶
298 additions and 0 deletions.
View changes Hide changes
1 |
1 |
|
2 |
2 |
# Create your models here. |
3 |
3 |
|
+ |
4 |
class Course(models.Model): |
+ |
5 |
""" Represents a course that is taught at the university. """ |
+ |
6 |
number = models.PositiveSmallIntegerField( |
+ |
7 |
primary_key=True, |
+ |
8 |
blank=False, |
+ |
9 |
help_text=_("The number associated with this course. A leading "0" will be added if the number is smaller than 1000."), |
+ |
10 |
) |
+ |
11 |
name = models.CharField( |
+ |
12 |
max_length=64, |
+ |
13 |
blank=False, |
+ |
14 |
help_text=_("The name of this course, in the language that it is taught. Translations are for the appropriate template."), |
+ |
15 |
) |
+ |
16 |
contact_person = models.ForeignKey( |
+ |
17 |
"joeni.user", |
+ |
18 |
on_delete=models.PROTECT, # A course must have a contact person |
+ |
19 |
limit_choices_to={'is_staff': True}, |
+ |
20 |
null=False, |
+ |
21 |
help_text=_("The person to contact regarding this course."), |
+ |
22 |
) |
+ |
23 |
coordinator = models.ForeignKey( |
+ |
24 |
"joeni.user", |
+ |
25 |
on_delete=models.PROTECT, # A course must have a coordinator |
+ |
26 |
limit_choices_to={'is_staff': True}, |
+ |
27 |
null=False, |
+ |
28 |
help_text=_("The person whom's the coordinator of this course."), |
+ |
29 |
) |
+ |
30 |
educating_team = models.ManyToManyField( |
+ |
31 |
"joeni.user", |
+ |
32 |
# No on_delete, since M->M cannot be required at database level |
+ |
33 |
limit_choices_to={'is_staff': True}, |
+ |
34 |
null=False, |
+ |
35 |
help_text=_("The team members of this course."), |
+ |
36 |
) |
+ |
37 |
language = models.CharField( |
+ |
38 |
max_length=64, |
+ |
39 |
choices = ( |
+ |
40 |
('NL', _("Dutch")), |
+ |
41 |
('EN', _("English")), |
+ |
42 |
('FR', _("French")), |
+ |
43 |
) |
+ |
44 |
null=False, |
+ |
45 |
help_text=_("The language in which this course is given."), |
+ |
46 |
) |
+ |
47 |
requirements = models.ManyToManyField() |
+ |
48 |
|
+ |
49 |
def __str__(self): |
+ |
50 |
number = str(self.number) |
+ |
51 |
for i in [10,100,1000]: |
+ |
52 |
if self.number < i: |
+ |
53 |
number = "0" + number |
+ |
54 |
return "(" + number + ") " + self.name |
+ |
55 |
|
+ |
56 |
|
+ |
57 |
class Prerequisites(models.Model): |
+ |
58 |
""" Represents a collection of prerequisites a student must have obtained |
+ |
59 |
before being allowed to partake in this course. |
+ |
60 |
It's possible that, if a student has obtained credits in a certain set of |
+ |
61 |
courses, a certain part of the prerequisites do not have to be obtained. |
+ |
62 |
Because of this, make a different record for each different set. In other |
+ |
63 |
words: If one set of prerequisites is obtained, and another one isn't, BUT |
+ |
64 |
they point to the same course, the student is allowed to partake. """ |
+ |
65 |
course = models.ForeignKey( |
+ |
66 |
"Course", |
+ |
67 |
on_delete=models.CASCADE, |
+ |
68 |
null=False, |
+ |
69 |
help_text=_("The course that these prerequisites are for."), |
+ |
70 |
) |
+ |
71 |
name = models.ForeignKey( |
+ |
72 |
blank=True, |
+ |
73 |
help_text=_("To specify a name for this set, if necessary."), |
+ |
74 |
) |
+ |
75 |
sequentialities = models.ManyToManyField( |
+ |
76 |
"Course", |
+ |
77 |
help_text=_("All courses for which a credit must've been received in order to follow the course."), |
+ |
78 |
) |
+ |
79 |
in_curriculum = models.ManyToManyField( |
+ |
80 |
"Course", |
+ |
81 |
help_text=_("All courses that have to be in the curriculum to follow this. If a credit was achieved, that course can be omitted."), |
+ |
82 |
) |
+ |
83 |
required_study = models.ForeignKey( |
+ |
84 |
"Study", |
+ |
85 |
on_delete=models.CASCADE, |
+ |
86 |
null=True, |
+ |
87 |
help_text=_("If one must have a certain amount of obtained ECTS points for a particular course, state that course here."), |
+ |
88 |
) |
+ |
89 |
ECTS_for_required_study = models.PositiveSmallIntegerField( |
+ |
90 |
null=True, |
+ |
91 |
help_text=_("The amount of obtained ECTS points for the required course, if any."), |
+ |
92 |
) |
+ |
93 |
|
+ |
94 |
def __str__(self): |
+ |
95 |
if self.name == "": |
+ |
96 |
return _("Prerequisites for %(course)s") % {'course': str(self.course)} |
+ |
97 |
else: |
+ |
98 |
return self.name + " | " + str(self.course) |
+ |
99 |
|
+ |
100 |
|
+ |
101 |
class ProgrammeInformation(models.Model): |
+ |
102 |
""" It's possible that a course is taught in multiple degree programmes; For |
+ |
103 |
example: Calculus can easily be taught to physics and mathematics students |
+ |
104 |
alike. In this table, these relations are set up, and the related properties |
+ |
105 |
are defined as well. """ |
+ |
106 |
study = models.ForeignKey( |
+ |
107 |
"Study", |
+ |
108 |
on_delete=models.CASCADE, |
+ |
109 |
null=False, |
+ |
110 |
help_text=_("The study in which the course is taught."), |
+ |
111 |
) |
+ |
112 |
course = models.ForeignKey( |
+ |
113 |
"Course", |
+ |
114 |
on_delete=models.CASCADE, |
+ |
115 |
null=False, |
+ |
116 |
help_text=_("The course that this information is for."), |
+ |
117 |
) |
+ |
118 |
programme_type = models.CharField( |
+ |
119 |
max_length=1, |
+ |
120 |
blank=False, |
+ |
121 |
choices = ( |
+ |
122 |
('C', _("Compulsory")), |
+ |
123 |
('O', _("Optional")), |
+ |
124 |
), |
+ |
125 |
help_text=_("Type of this course for this study."), |
+ |
126 |
) |
+ |
127 |
study_hours = models.PositiveSmallIntegerField( |
+ |
128 |
blank=False, |
+ |
129 |
help_text=_("The required amount of hours to study this course."), |
+ |
130 |
) |
+ |
131 |
ECTS = models.PositiveSmallIntegerField( |
+ |
132 |
blank=False, |
+ |
133 |
help_text=_("The amount of ECTS points attached to this course."), |
+ |
134 |
) |
+ |
135 |
semester = models.PositiveSmallIntegerField( |
+ |
136 |
blank=False, |
+ |
137 |
choices = ( |
+ |
138 |
(1, _("First semester")), |
+ |
139 |
(2, _("Second semester")), |
+ |
140 |
(3, _("Full year course")), |
+ |
141 |
(4, _("Taught in first quarter")), |
+ |
142 |
(5, _("Taught in second quarter")), |
+ |
143 |
(6, _("Taught in third quarter")), |
+ |
144 |
(7, _("Taught in fourth quarter")), |
+ |
145 |
) |
+ |
146 |
help_text=_("The period in which this course is being taught in this study."), |
+ |
147 |
) |
+ |
148 |
year = models.PositiveSmallIntegerField( |
+ |
149 |
blank=False, |
+ |
150 |
help_text=_("The year in which this course is taught for this study."), |
+ |
151 |
) |
+ |
152 |
second_chance = models.BooleanField( |
+ |
153 |
default=True, |
+ |
154 |
help_text=_("Defines if a second chance exam is planned for this course."), |
+ |
155 |
) |
+ |
156 |
tolerable = models.BooleanField( |
+ |
157 |
default=True, |
+ |
158 |
help_text=_("Defines if a failed result can be tolerated."), |
+ |
159 |
) |
+ |
160 |
scoring = models.CharField( |
+ |
161 |
max_length=2, |
+ |
162 |
choices = ( |
+ |
163 |
('N', _("Numerical")), |
+ |
164 |
('FP', _("Fail/Pass")), |
+ |
165 |
), |
+ |
166 |
default='N', |
+ |
167 |
blank=False, |
+ |
168 |
help_text=_("How the obtained score for this course is given."), |
+ |
169 |
) |
+ |
170 |
|
+ |
171 |
def __str__(self): |
+ |
172 |
return str(self.study) + " - " + str(self.course) |
+ |
173 |
|
+ |
174 |
class Study(models.Model): |
+ |
175 |
""" Defines a certain study that can be followed at the university. |
+ |
176 |
This also includes abridged study programmes, like transition programmes. |
+ |
177 |
Other information, such as descriptions, are kept in the template file |
+ |
178 |
of this study, which can be manually edited. Joeni searches for a file |
+ |
179 |
with the exact name as the study + ".html". So if the study is called |
+ |
180 |
"Bachelor of Informatics", it will search for "Bachelor of Informatics.html". |
+ |
181 |
""" |
+ |
182 |
# Degree types |
+ |
183 |
BSc = _("Bachelor of Science") |
+ |
184 |
Msc = _("Master of Science") |
+ |
185 |
LLB = _("Bachelor of Laws") |
+ |
186 |
LLM = _("Master of Laws") |
+ |
187 |
ir = _("Engineer") |
+ |
188 |
ing = _("Technological Engineer") |
+ |
189 |
# Faculties |
+ |
190 |
FoMaLS = _("Faculty of Medicine and Life Sciences") |
+ |
191 |
Fos = _("Faculty of Sciences") |
+ |
192 |
FoTS = _("Faculty of Transportation Sciences") |
+ |
193 |
FoAaA = _("Faculty of Architecture and Arts") |
+ |
194 |
FoBE = _("Faculty of Business Economics") |
+ |
195 |
FoET = _("Faculty of Engineering Technology") |
+ |
196 |
FoL = _("Faculty of Law") |
+ |
197 |
|
+ |
198 |
name = models.CharField( |
+ |
199 |
max_length=128, |
+ |
200 |
blank=False, |
+ |
201 |
unique=True, |
+ |
202 |
help_text=_("The full name of this study, in the language it's taught in."), |
+ |
203 |
) |
+ |
204 |
degree_type = models.CharField( |
+ |
205 |
max_length=64, |
+ |
206 |
choices = ( |
+ |
207 |
('BSc', Bsc), |
+ |
208 |
('MSc', Msc), |
+ |
209 |
('LL.B', LLB), |
+ |
210 |
('LL.M', LLM), |
+ |
211 |
('ir.', ir ), |
+ |
212 |
('ing.',ing), |
+ |
213 |
), |
+ |
214 |
blank=False, |
+ |
215 |
help_text=_("The type of degree one obtains upon passing this study."), |
+ |
216 |
) |
+ |
217 |
language = models.CharField( |
+ |
218 |
max_length=64, |
+ |
219 |
choices = ( |
+ |
220 |
('NL', _("Dutch")), |
+ |
221 |
('EN', _("English")), |
+ |
222 |
('FR', _("French")), |
+ |
223 |
) |
+ |
224 |
null=False, |
+ |
225 |
help_text=_("The language in which this study is given."), |
+ |
226 |
) |
+ |
227 |
# Information about exam committee |
+ |
228 |
chairman = models.ForeignKey( |
+ |
229 |
"Joeni.users", |
+ |
230 |
on_delete=models.PROTECT, |
+ |
231 |
null=False, |
+ |
232 |
limit_choices_to={'is_staff': True}, |
+ |
233 |
help_text=_("The chairman of this study."), |
+ |
234 |
) |
+ |
235 |
vice_chairman = models.ForeignKey( |
+ |
236 |
"Joeni.users", |
+ |
237 |
on_delete=models.PROTECT, |
+ |
238 |
null=False, |
+ |
239 |
help_text=_("The vice-chairman of this study."), |
+ |
240 |
limit_choices_to={'is_staff': True}, |
+ |
241 |
) |
+ |
242 |
secretary = models.ForeignKey( |
+ |
243 |
"Joeni.users", |
+ |
244 |
on_delete=models.PROTECT, |
+ |
245 |
null=False, |
+ |
246 |
help_text=_("The secretary of this study."), |
+ |
247 |
limit_choices_to={'is_staff': True}, |
+ |
248 |
) |
+ |
249 |
ombuds = models.ForeignKey( |
+ |
250 |
"Joeni.users", |
+ |
251 |
on_delete=models.PROTECT, |
+ |
252 |
null=False, |
+ |
253 |
help_text=_("The ombuds person of this study."), |
+ |
254 |
limit_choices_to={'is_staff': True}, |
+ |
255 |
) |
+ |
256 |
vice_ombuds = models.ForeignKey( |
+ |
257 |
"Joeni.users", |
+ |
258 |
on_delete=models.PROTECT, |
+ |
259 |
null=False, |
+ |
260 |
help_text=_("The (replacing) ombuds person of this study."), |
+ |
261 |
limit_choices_to={'is_staff': True}, |
+ |
262 |
) |
+ |
263 |
additional_members = models.ManyToManyField( |
+ |
264 |
"Joeni.users", |
+ |
265 |
help_text=_("All the other members of the exam committee."), |
+ |
266 |
limit_choices_to={'is_staff': True}, |
+ |
267 |
) |
+ |
268 |
faculty = models.CharField( |
+ |
269 |
max_length=6, |
+ |
270 |
choices = ( |
+ |
271 |
('FoS', FoS), |
+ |
272 |
('FoTS', FoTS), |
+ |
273 |
('FoAaA', FoAaA), |
+ |
274 |
('FoBE', FoBE), |
+ |
275 |
('FoMaLS', FoMaLS), |
+ |
276 |
('FoET', FoET), |
+ |
277 |
('FoL', FoL), |
+ |
278 |
), |
+ |
279 |
blank=False, |
+ |
280 |
help_text=_("The faculty where this study belongs to."), |
+ |
281 |
) |
+ |
282 |
|
+ |
283 |
def study_points(self): |
+ |
284 |
""" Returns the amount of study points for this year. |
+ |
285 |
This value is inferred based on the study programme information |
+ |
286 |
records that lists this study as their foreign key. """ |
+ |
287 |
total_ECTS = 0 |
+ |
288 |
for course in ProgrammeInformation.objects.filter(study=self): |
+ |
289 |
total_ECTS += course.ECTS |
+ |
290 |
return total_ECTS |
+ |
291 |
def years(self): |
+ |
292 |
""" Returns the amount of years this study takes. |
+ |
293 |
This value is inferred based on the study programme information |
+ |
294 |
records that lists this study as their foreign key. """ |
+ |
295 |
highest_year = 0 |
+ |
296 |
for course in ProgrammeInformation.objects.filter(study=self): |
+ |
297 |
highest_year = max(highest_year, course.year) |
+ |
298 |
return highest_year |
+ |
299 |
def __str__(self): |
+ |
300 |
return self.name |
+ |
301 |
joeni/models.py ¶
10 additions and 0 deletions.
View changes Hide changes
1 |
1 |
from django.core.exceptions import ValidationError # For validating IBAN input |
2 |
2 |
from django.utils.translation import ugettext_lazy as _ |
3 |
3 |
from django.db import models |
4 |
4 |
import datetime |
5 |
5 |
import os |
6 |
6 |
|
7 |
7 |
class room(models.Model): |
8 |
8 |
""" Represents a room in the university. |
9 |
9 |
Rooms can have a number of properties, which are stored in the database. |
10 |
10 |
""" |
11 |
11 |
name = models.TextField() |
12 |
12 |
seats = models.IntegerField() |
13 |
13 |
wheelchair_accessible = models.BooleanField(default=True,blank=False) |
14 |
14 |
exams_equipped = models.BooleanField(blank=False) |
15 |
15 |
|
16 |
16 |
class User(models.Model): |
17 |
17 |
""" Replacement for the standard Django User model. """ |
18 |
18 |
number = models.PositiveIntegerField( |
19 |
19 |
primary_key=True, |
20 |
20 |
help_text=_("The number assigned to this user."), |
21 |
21 |
) |
22 |
22 |
created = models.DateField(auto_now_add=True) |
23 |
23 |
passphrase = models.CharField( |
24 |
24 |
max_length=512, |
25 |
25 |
blank=False, |
26 |
26 |
help_text=_("The passphrase used for this account. This field must only contain hashed information."), |
27 |
27 |
) |
28 |
28 |
first_name = models.CharField(max_length=64, blank=False) |
29 |
29 |
last_name = models.CharField(max_length=64, blank=False) |
30 |
30 |
DOB = models.DateField( |
+ |
31 |
max_length=64, |
+ |
32 |
blank=True, |
+ |
33 |
help_text=_("The academic title of this user, if applicable."), |
+ |
34 |
) |
+ |
35 |
DOB = models.DateField( |
31 |
36 |
blank=False, |
32 |
37 |
editable=False, |
33 |
38 |
help_text=_("The date of birth of this user."), |
34 |
39 |
) |
35 |
40 |
POB = models.CharField( |
36 |
41 |
max_length=64, |
37 |
42 |
blank=False, |
38 |
43 |
editable=False, |
39 |
44 |
help_text=_("The place of birth of this user."), |
40 |
45 |
) |
41 |
46 |
nationality = models.CharField( |
42 |
47 |
max_length=64, |
43 |
48 |
blank=False, |
44 |
49 |
help_text=_("The current nationality of this user."), |
45 |
50 |
) |
46 |
51 |
national_registry_number = models.BigIntegerField( |
47 |
52 |
unique=True, |
48 |
53 |
editable=False, |
49 |
54 |
help_text=_("The assigned national registry number of this user."), |
50 |
55 |
) |
51 |
56 |
civil_status = models.CharField( |
52 |
57 |
choices = ( |
53 |
58 |
("Single", _("Single")), |
54 |
59 |
("Married", _("Married")), |
55 |
60 |
("Divorced", _("Divorced")), |
56 |
61 |
("Widowed", _("Widowed")), |
57 |
62 |
("Partnership", _("Partnership")), |
58 |
63 |
), |
59 |
64 |
blank=False, |
60 |
65 |
# There may be more; consult http://www.aantrekkingskracht.com/trefwoord/burgerlijke-staat |
61 |
66 |
# for more information. |
62 |
67 |
help_text=_("The civil/marital status of the user."), |
63 |
68 |
) |
64 |
69 |
|
65 |
70 |
# Home address |
+ |
71 |
default=False, |
+ |
72 |
help_text=_("Determines if this user is part of the university's staff."), |
+ |
73 |
) |
+ |
74 |
|
+ |
75 |
# Home address |
66 |
76 |
home_street = models.CharField(max_length=64, blank=False) |
67 |
77 |
home_number = models.PositiveSmallIntegerField(blank=False) |
68 |
78 |
home_bus = models.PositiveSmallIntegerField() |
69 |
79 |
home_postal_code = models.PositiveSmallIntegerField(blank=False) |
70 |
80 |
home_country = models.CharField(max_length=64, blank=False) |
71 |
81 |
home_telephone = models.CharField( |
72 |
82 |
max_length=64, |
73 |
83 |
help_text=_("The telephone number for the house address. Prefix 0 can be presented with the national call code in the system."), |
74 |
84 |
) |
75 |
85 |
# Study address |
76 |
86 |
study_street = models.CharField(max_length=64, blank=False) |
77 |
87 |
study_number = models.PositiveSmallIntegerField(blank=False) |
78 |
88 |
study_bus = models.PositiveSmallIntegerField() |
79 |
89 |
study_postal_code = models.PositiveSmallIntegerField(blank=False) |
80 |
90 |
study_country = models.CharField(max_length=64, blank=False) |
81 |
91 |
study_telephone = models.CharField( |
82 |
92 |
max_length=64, |
83 |
93 |
help_text=_("The telephone number for the study address. Prefix 0 can be presented with the national call code in the system."), |
84 |
94 |
) |
85 |
95 |
study_cellphone = models.CharField( |
86 |
96 |
max_length=64, |
87 |
97 |
help_text=_("The cellphone number of the person. Prefix 0 can be presented with then national call code in the system."), |
88 |
98 |
) |
89 |
99 |
# Titularis address |
90 |
100 |
# XXX: These fields are only required if this differs from the user itself. |
91 |
101 |
titularis_street = models.CharField(max_length=64) |
92 |
102 |
titularis_number = models.PositiveSmallIntegerField() |
93 |
103 |
titularis_bus = models.PositiveSmallIntegerField() |
94 |
104 |
titularis_postal_code = models.PositiveSmallIntegerField() |
95 |
105 |
titularis_country = models.CharField(max_length=64) |
96 |
106 |
titularis_telephone = models.CharField( |
97 |
107 |
max_length=64, |
98 |
108 |
help_text=_("The telephone number of the titularis. Prefix 0 can be presented with the national call code in the system."), |
99 |
109 |
) |
100 |
110 |
|
101 |
111 |
# Financial details |
102 |
112 |
bank_account_number = models.CharField( |
103 |
113 |
max_length=34, # Max length of all IBAN account numbers |
104 |
114 |
validators=[validate_IBAN], |
105 |
115 |
help_text=_("The IBAN of this user. No spaces!"), |
106 |
116 |
) |
107 |
117 |
BIC = models.CharField( |
108 |
118 |
max_length=11, |
109 |
119 |
validators=[validate_BIC], |
110 |
120 |
help_text=_("The BIC of this user's bank."), |
111 |
121 |
) |
112 |
122 |
|
113 |
123 |
def validate_IBAN(value): |
114 |
124 |
""" Validates if the given value qualifies as a valid IBAN number. |
115 |
125 |
This validator checks if the structure is valid, and calculates the control |
116 |
126 |
number if the structure is correct. If the control number fails, or the |
117 |
127 |
structure is invalid, a ValidationError will be raised. In that case, |
118 |
128 |
the Error will specify whether the structure is incorrect, or the control |
119 |
129 |
number is not valid. |
120 |
130 |
""" |
121 |
131 |
# FIXME: This function is not complete. When there's time, implement |
122 |
132 |
# as specified at https://nl.wikipedia.org/wiki/International_Bank_Account_Number#Structuur |
123 |
133 |
if False: |
124 |
134 |
raise ValidationError( |
125 |
135 |
_('%(value)s is not a valid IBAN number.'), |
126 |
136 |
params={'value': value},) |
127 |
137 |
def validate_BIC(value): |
128 |
138 |
""" Same functionality as validate_IBAN, but for BIC-codes. """ |
129 |
139 |
# FIXME: This function is not complete. When there's time, implement |
130 |
140 |
# as specified at https://nl.wikipedia.org/wiki/Business_Identifier_Code |
131 |
141 |
pass |
132 |
142 |
|
133 |
143 |
|
134 |
144 |
""" NOTE: What about all the other features that should be in the administration? |
135 |
145 |
While there are a lot of things to cover, as of now, I have no way to know which |
136 |
146 |
ones are still valid, which are deprecated, and so on... |
137 |
147 |
Additionally, every feature may have a different set of requirements, data, |
138 |
148 |
and it's very likely making an abstract class won't do any good. Thus I have |
139 |
149 |
decided to postpone making additional tables and forms for these features until |
140 |
150 |
I have clearance about certain aspects. """ |
141 |
151 |
|
142 |
152 |
def post_title_directory(instance, filename): |
143 |
153 |
""" Files will be uploaded to MEDIA_ROOT/blog/<year of publishing>/<blog |
144 |
154 |
title> |
145 |
155 |
The blog title is determined by the text before the first period (".") in |
146 |
156 |
the filename. So if the file has the name "Trains are bæ.en.md", the file |
147 |
157 |
will be stored in "blog/<this year>/Trains are bæ". Name your files |
148 |
158 |
properly! |
149 |
159 |
It should also be noted that all files are stored in the same folder if they |
150 |
160 |
belong to the same blogpost, regardless of language. The titles that are |
151 |
161 |
displayed to the user however, should be the titles of the files themselves, |
152 |
162 |
which should be in the native language. So if a blog post is titled |
153 |
163 |
"Universities of Belgium", its Dutch counterpart should be titled |
154 |
164 |
"Universiteiten van België", so the correct title can be derived from the |
155 |
165 |
filename. |
156 |
166 |
|
157 |
167 |
Recommended way to name the uploaded file: "<name of blog post in language |
158 |
168 |
it's written>.md". This removes the maximum amount of redundancy (e.g. the |
159 |
169 |
language of the file can be derived from the title, no ".fr.md" or something |
160 |
170 |
like that necessary), and can directly be used for the end user (the title |
161 |
171 |
is what should be displayed). |
162 |
172 |
""" |
163 |
173 |
english_file_name = os.path.basename(instance.english_file.name) # TODO: Test if this returns the file name! |
164 |
174 |
english_title = english_file_name.rpartition(".")[0] |
165 |
175 |
year = datetime.date.today().year |
166 |
176 |
|
167 |
177 |
return "blog/{0}/{1}/{2}".format(year, english_title, filename) |
168 |
178 |
|
169 |
179 |
class Post(models.Model): |
170 |
180 |
""" Represents a blog post. The title of the blog post is determnined by the name |
171 |
181 |
of the files. |
172 |
182 |
A blog post can be in 5 different languages: German, Spanish, English, French, |
173 |
183 |
and Dutch. For all these languages, a seperate field exists. Thus, a |
174 |
184 |
translated blog post has a seperate file for each translation, and is |
175 |
185 |
seperated from Django's internationalization/localization system. |
176 |
186 |
Only the English field is mandatory. The others may contain a value if a |
177 |
187 |
translated version exists, which will be displayed accordingly. |
178 |
188 |
""" |
179 |
189 |
published = models.DateTimeField(auto_now_add=True) |
180 |
190 |
english_file = models.FileField(upload_to=post_title_directory, unique=True, blank=False) |
181 |
191 |
dutch_file = models.FileField(upload_to=post_title_directory, blank=True) |
182 |
192 |
french_file = models.FileField(upload_to=post_title_directory, blank=True) |
183 |
193 |
german_file = models.FileField(upload_to=post_title_directory, blank=True) |
184 |
194 |
spanish_file = models.FileField(upload_to=post_title_directory, blank=True) |
185 |
195 |
# Only the English file can be unique, because apparantly, there can't be |
186 |
196 |
# two blank fields in a unique column. Okay then. |
187 |
197 |
|
188 |
198 |
def __str__(self): |
189 |
199 |
return os.path.basename(self.english_file.name).rpartition(".")[0] |
190 |
200 |
|
191 |
201 |
#class Comment(models.model): |
192 |
202 |
""" Represents a comment on a blog post. |
193 |
203 |
|
194 |
204 |
Comments are not linked to an account or anything, I'm trusting the |
195 |
205 |
commenter that he is honest with his credentials. That being said: |
196 |
206 |
XXX: Remember to put up a notification that comments are not checked for |
197 |
207 |
identity, and, unless verified by a trustworthy source, cannot be seen as |
198 |
208 |
being an actual statement from the commenter. |
199 |
209 |
Comments are linked to a blogpost, and are not filtered by language. (So a |
200 |
210 |
comment made by someone reading the article in Dutch, that's written in |
201 |
211 |
Dutch, will show up (unedited) for somebody whom's reading the Spanish |
202 |
212 |
version. |
203 |
213 |
XXX: Remember to notify (tiny footnote or something) that comments showing |
204 |
214 |
up in a foreign language is by design, and not a bug. |
205 |
215 |
""" |
206 |
216 |
# date = models.DateTimeField(auto_now_add=True) |
207 |
217 |
#name = models.TextField() |
208 |
218 |
#mail = models.EmailField() |
209 |
219 |
#post = models.ForeignKey(Post) # TODO: Finish this class and the shit... |
210 |
220 |