Identify Testcases with a string codename [1/3]

Rather than by an integer index.

Also bind each Evaluation to its Testcase using a foreign key and a
relationship, instead of relying on them having the same codename. This
way Evaluations will be deleted when their Testcase is, and there's no
risk that their names go "out of sync".
Identify Testcases with a string codename [2/3]

Mostly straightforward changes. Job.testcases and Job.evaluations are
now indexed by strings and not by integers (makes it also easier to
convert to and from JSON); the same holds for the public_testcases
argument for ScoreTypes; TaskType.evaluate_testcase also receives a
string. When EvaluationService creates an Evaluation it cannot pass the
codename to the constructor but has to use it to get the Testcase from
the Dataset.

When ScoreTypes need to put an order on Testcase (to group them into
subtasks or to present them in the graphical output) they use the
lexicographical order of the codenames.
Identify Testcases with a string codename [3/3]

Mostly straightforward again. Use the ID of the Testcase instead of its
codename ("namespaced" with the ID of the Dataset) as HTML form input
names (and hence HTTP query argument names) as it doesn't need to be
escaped and pose no risk. Given the new sorting criteria for Evaluations
in ScoreTypes, to preserve the current behavior import Testcases with
their numerical indexed (zero-padded to three digits) as codename.
Use JobGroup

Instead of combining the evaluations for all testcases into a single
EvaluationJob, use one for each testcase and introduce a JobGroup to
"bind" them all together.

We needed to remove the testcases and evaluations attributes from
EvaluationJob and add input, output and all the other fields that
TaskTypes dynamically put in the elements inserted in evaluations:
success, outcome, text, user_output, plus (user_output was called
output before but has been renamed to avoid collision).

JobGroup contains a dict of Jobs and a success attribute, which is
basically the AND of the success of all the Jobs it contains. The
methods to create Jobs from Submissions and UserTests have been moved
here too, with slight modifications (usually just the last two lines of
code, with the exception of from_submission_evaluation which required
some more changes).

The loop that breaks a JobGroup into single Jobs (the one that was in
TaskType.evaluate and called .evaluate_testcase) has been moved into
Worker. Therefore TaskType.evaluate has been removed and
.evaluate_testcase has been renamed to .evaluate. Worker, on the other
hand, doesn't need store the TaskType as class-level attribute just to
set its ignore_job attribute: it's now storing ignore_job itself (the
session attribute has also been removed as it was completely unused).