This is part two in the KidsTasks series where we’re designing and implementing a django app to manage daily task lists for my kids. See part 1 for details on requirements and goals.
Model Design Revisited
As I started coding up the models and the corresponding admin pages for the design I presented in the last section it became clear that there were several bad assumptions and mistakes in that design. (I plan to write up a post about designs and their mutability in the coming weeks.)
The biggest conceptual problem I had was the difference between “python objects” and “django models”. Django models correspond to database tables and thus do not map easily to things like “I want a list of Tasks in my DayOfWeekSchedule”.
After building up a subset of the models described in part 1, I found that the CountedTask model wasn’t going to work the way I had envisioned. Creating it as a direct subclass of Task caused unexpected (initially, at least) behavior in that all CountedTasks were also Tasks and thus showed up in all lists where Tasks could be added. While this behavior makes sense, it doesn’t fit the model I was working toward. After blundering with a couple of other ideas, it finally occurred to me that the main problem was the fundamental design. If something seems really cumbersome to implement it might be pointing to a design error.
Stepping back, it occurred to me that the idea of a “Counted” task was putting information at the wrong level. An individual task shouldn’t care if it’s one of many similar tasks in a Schedule, nor should it know how many there are. That information should be part of the Schedule models instead.
Changing this took more experimenting than I wanted, largely due to a mismatch in my thinking and how django models work. The key for working through this level of confusion was by trying to figure out how to add multiple Tasks of the same type to a Schedule. That led me to this Stack Overflow question which describes using an intermediate model to relate the two items. This does exactly what I’m looking for, allowing me to say that Kid1 needs to Practice Piano twice on Tuesdays without the need for a CountedTask model.
Changing this created problems for our current admin.py, however. I found ideas for how to clean that up here, which describes how to use inlines as part of the admin pages.
Using inlines and intermediate models, I was able to build up a schedule for a kid in a manner similar to my initial vision. The next steps will be to work on views for this model and see where the design breaks!
Wrap Up
I’m going to stop this session here but I want to add a few interesting points and tidbits I’ve discovered on the way:
- If you make big changes to the model and you don’t yet have any significant data, you can wipe out the database easily and start over with the following steps:
$rm db.sqlite3 tasks/migrations/ -rf$./manage.py makemigrations tasks$./manage.py migrate$./manage.py createsuperuser$./manage.py runserver
- For models, it’s definitely worthwhile to add a __str__ (note: maybe __unicode__?) method and a Meta class to each one. The __str__ method controls how the class is described, at least in the admin pages. The Meta class allows you to control the ordering when items of this model are listed. Cool!
- I found (and forgot to note where) in the official docs an example of using a single char to store the name of the week while displaying the full day name. This looks like this:
day_of_week_choices = ( ('M', 'Monday'), ('T', 'Tuesday'), ('W', 'Wednesday'), ('R', 'Thursday'), ('F', 'Friday'), ('S', 'Saturday'), ('N', 'Sunday'), ) ... day_name = models.CharField(max_length=1, choices=day_of_week_choices)
- NOTE that we’re going to have to tie the “name” fields in many of these models to the kid to which it’s associated. I’m considering if the kid can be combined into the schedule, but I don’t think that’s quite right. Certainly changes are coming to that part of the design.
That’s it! The state of the code at the point I’m writing this can be found here:
git@github.com:jima80525/KidTasks.git git checkout blog/02-Models-first-steps
Thanks for reading!