devilry.apps.core.models — Devilry core datastructure

../_images/devilry.core.models.1.png ../_images/devilry.core.models.2.png

(edit the images umldiagram1 and umldiagram2 using yuml.me)

Functions and attributes

devilry.apps.core.models.model_utils.pathsep

Path separator used by node-paths. The value is '.', and it must not be changed.

devilry.apps.core.models.model_utils.splitpath(path, expected_len=0)

Split the path on pathsep and return the resulting list. Example:

>>> splitpath('uio.ifi.matnat')
['uio', 'ifi', 'matnat']
>>> splitpath('uio.ifi.matnat', expected_len=2)
Traceback (most recent call last):
...
ValueError: Path must have exactly 2 parts
Parameters:expected_len – Expected length of the resulting list. If the resulting list is not exactly the given length, ValueError is raised. If expected_len is 0 (default), no checking is done.

BaseNode

class devilry.apps.core.models.BaseNode

Bases: devilry.apps.core.models.abstract_is_admin.AbstractIsAdmin, devilry.apps.core.models.save_interface.SaveInterface

The base class of the Devilry hierarchy. Implements basic functionality used by the other Node classes. This is an abstract datamodel, so it is never used directly.

short_name

A django.db.models.SlugField with max 20 characters. Only numbers, letters, ‘_’ and ‘-‘.

long_name

A django.db.models.CharField with max 100 characters. Gives a longer description than short_name.

AbstractIsAdmin

class devilry.apps.core.models.AbstractIsAdmin

Bases: object

Abstract class implemented by all classes where it is natural to need to check if a user has admin rights.

classmethod q_is_admin(user_obj)

Get a django.db.models.Q object matching all objects of this type where the given user is admin. The matched result is not guaranteed to contain unique items, so you should use distinct() on the queryset if this is required.

This must be implemented in all subclassed.

classmethod where_is_admin(user_obj, *related_fields)

Get all objects of this type where the given user is admin.

classmethod where_is_admin_or_superadmin(user_obj, *related_fields)

Get all objects of this type where the given user is admin, or all objects if the user is superadmin.

AbstractIsExaminer

class devilry.apps.core.models.AbstractIsExaminer

Bases: object

Abstract class implemented by all classes where it is natural to need to check if a user is examiner.

classmethod q_published(old=True, active=True)

Return a django.models.Q object which matches all items of this type where Assignment.publishing_time is in the past.

Parameters:
classmethod q_is_examiner(user_obj)

Return a django.models.Q object which matches items where the given user is examiner.

classmethod where_is_examiner(user_obj)

Get all items of this type where the given user_obj is examiner on one of the assignment groups.

Parameters:user_obj – A django.contrib.auth.models.User object.
Return type:QuerySet
classmethod published_where_is_examiner(user_obj, old=True, active=True)

Get all published items of this type where the given user_obj is examiner on one of the assignment groups. Combines q_is_examiner() and q_published().

Parameters:
  • user_objq_is_examiner().
  • oldq_published().
  • activeq_published().
Returns:

A django.db.models.query.QuerySet with duplicate assignments eliminated.

classmethod active_where_is_examiner(user_obj)

Shortcut for published_where_is_examiner() with old=False.

classmethod old_where_is_examiner(user_obj)

Shortcut for published_where_is_examiner() with active=False.

Node

A node at the top of the navigation tree. It is a generic element used to organize administrators. A Node can be organized below another Node, and it can only have one parent.

Let us say you use Devilry within two departments at Fantasy University; informatics and mathematics. The university has an administration, and each department have their own administration. You would end up with this node-hierarchy:

  • Fantasy University
    • Department of informatics
    • Department of mathematics
class devilry.apps.core.models.Node(*args, **kwargs)

Bases: django.db.models.base.Model, devilry.apps.core.models.basenode.BaseNode, devilry.apps.core.models.model_utils.Etag

This class is typically used to represent a hierarchy of institutions, faculties and departments.

parentnode

A django.db.models.ForeignKey that points to the parent node, which is always a Node.

admins

A django.db.models.ManyToManyField that holds all the admins of the Node.

child_nodes

A set of child_nodes of type Node for this node

subjects

A set of subjects for this node

etag

A DateTimeField containing the etag for this object.

iter_childnodes()

Recursively iterates over all child nodes, and their child nodes. For a list of direct child nodes, use atribute child_nodes instead.

clean(*args, **kwargs)

Validate the node, making sure it does not do something stupid.

Always call this before save()! Read about validation here: http://docs.djangoproject.com/en/dev/ref/models/instances/#id1

Raises ValidationError if:

  • The node is it’s own parent.
  • The node is the child of itself or one of its childnodes.
is_empty()

Returns True if this Node does not contain any childnodes or subjects.

Subject

A subject is a course, seminar, class or something else being given regularly. A subject is further divided into periods.

class devilry.apps.core.models.Subject(*args, **kwargs)

Bases: django.db.models.base.Model, devilry.apps.core.models.basenode.BaseNode, devilry.apps.core.models.abstract_is_examiner.AbstractIsExaminer, devilry.apps.core.models.abstract_is_candidate.AbstractIsCandidate, devilry.apps.core.models.model_utils.Etag

parentnode

A django.db.models.ForeignKey that points to the parent node, which is always a Node.

admins

A django.db.models.ManyToManyField that holds all the admins of the Node.

short_name

A django.db.models.SlugField with max 20 characters. Only numbers, letters, ‘_’ and ‘-‘. Unlike all other children of BaseNode, Subject.short_name is unique. This is mainly to avoid the overhead of having to recurse all the way to the top of the node hierarchy for every unique path.

periods

A set of periods for this subject.

etag

A DateTimeField containing the etag for this object.

get_path()

Only returns short_name for subject since it is guaranteed to be unique.

is_empty()

Returns True if this Subject does not contain any periods.

Period

A Period is a limited period of time, like spring 2009, week 34 2010 or even a single day.

class devilry.apps.core.models.Period(*args, **kwargs)

Bases: django.db.models.base.Model, devilry.apps.core.models.basenode.BaseNode, devilry.apps.core.models.abstract_is_examiner.AbstractIsExaminer, devilry.apps.core.models.abstract_is_candidate.AbstractIsCandidate, devilry.apps.core.models.model_utils.Etag

A Period represents a period of time, for example a half-year term at a university.

parentnode

A django.db.models.ForeignKey that points to the parent node, which is always a Subject.

start_time

A django.db.models.DateTimeField representing the starting time of the period.

end_time

A django.db.models.DateTimeField representing the ending time of the period.

admins

A django.db.models.ManyToManyField that holds all the admins of the node.

assignments

A Django RelatedManager of assignments for this period.

relatedexaminer_set

A Django RelatedManager of RelatedExaminers for this period.

relatedstudent_set

A Django RelatedManager of RelatedStudents for this period.

etag

A DateTimeField containing the etag for this object.

clean(*args, **kwargs)

Validate the period.

Always call this before save()! Read about validation here: http://docs.djangoproject.com/en/dev/ref/models/instances/#id1

Raises ValidationError if start_time is after end_time.

is_active()

Returns true if the period is active

classmethod q_is_active()

Get a django.db.models.Q object that matches all active periods (periods where start_time is in the past, and end_time is in the future).

Example:

activeperiods = Period.objects.filter(Period.q_is_active())
is_empty()

Returns True if this Period does not contain any assignments.

subject

More readable alternative to self.parentnode.

RelatedUserBase

Base class for devilry.apps.core.models.RelatedStudent and devilry.apps.core.models.RelatedExaminer.

class devilry.apps.core.models.relateduser.RelatedUserBase(*args, **kwargs)

Bases: django.db.models.base.Model, devilry.apps.core.models.abstract_is_admin.AbstractIsAdmin

Common fields for examiners and students related to a period.

period

The period that the user is related to.

user

A django.contrib.auth.models.User object. Must be unique within this period.

tags

Comma-separated list of tags. Each tag is a word with the following letters allowed: a-z and 0-9. Each word is separated by a comma, and no whitespace.

RelatedStudent — Student on a period

A RelatedStudent is a student related to a devilry.apps.core.models.Period.

class devilry.apps.core.models.RelatedStudent(*args, **kwargs)

Bases: devilry.apps.core.models.relateduser.RelatedUserBase

Related student.

candidate_id

If a candidate has the same Candidate ID for all or many assignments in a semester, this field can be set to simplify setting candidate IDs on each assignment.

RelatedExaminer — Examiner on a period

A RelatedExaminer is an examiner related to a devilry.apps.core.models.Period.

class devilry.apps.core.models.RelatedExaminer(*args, **kwargs)

Bases: devilry.apps.core.models.relateduser.RelatedUserBase

Related examiner.

Adds no fields to RelatedUserBase.

Assignment

Represents one assignment within a given Period in a given Subject. Each assignment contains one AssignmentGroup for each student or group of students permitted to submit deliveries.

We have three main classifications of assignments:

  1. A old assignment is a assignment where Period.end_time is in the past.
  2. A published assignment is a assignment where publishing_time is in the past.
  3. A active assignment is a assignment where publishing_time is in the past and current time is before Period.end_time.
class devilry.apps.core.models.Assignment(*args, **kwargs)

Bases: django.db.models.base.Model, devilry.apps.core.models.basenode.BaseNode, devilry.apps.core.models.abstract_is_examiner.AbstractIsExaminer, devilry.apps.core.models.abstract_is_candidate.AbstractIsCandidate

parentnode

A django.db.models.ForeignKey that points to the parent node, which is always a Period.

publishing_time

A django.db.models.DateTimeField representing the publishing time of the assignment.

anonymous

A models.BooleanField specifying if the assignment should be anonymously for correcters.

admins

A django.db.models.ManyToManyField that holds all the admins of the Node.

assignmentgroups

A set of assignmentgroups for this assignment

examiners_publish_feedbacks_directly

Should feedbacks published by examiners be made avalable to the students immediately? If not, an administrator have to publish feedbacks. See also Deadline.feedbacks_published.

scale_points_percent

Percent to scale points on this assignment by for period overviews. The default is 100, which means no change to the points.

delivery_types

An integer identifying the type of deliveries allowed. Possible values:

0
Electronic deliveries using Devilry
1
Non-electronic deliveries, or deliveries made through another electronic system.
2
An alias/link to a delivery made in another Period.
deadline_handling

An integer identifying how deadlines are handled.

0
Soft deadlines. Deliveries can be added until groups are closed.
1
Hard deadlines. Deliveries can not be added after the deadline has expired.
first_deadline

A DateTimeField containing an optional first deadline for this assignment. This is metadata that the UI can use where it is natural.

max_points

An IntegerField that contains the maximum number of points possible to achieve on this assignment. This field may be None, and it is normally set by the grading system plugin.

DO NOT UPDATE MANUALLY. You can safely set an initial value for this manually when you create a new assignment, but when you update this field, do so using set_max_points().

passing_grade_min_points

An IntegerField that contains the minimum number of points required to achive a passing grade on this assignment. This means that any feedback with more this number of points or more is considered a passing grade.

WARNING: Changing this does not have any effect on existing feedback. To actually change existing feedback, you would have to update all feedback on the assignment, effectively creating new StaticFeedbacks from the latest published FeedbackDrafts for each AssignmentGroup.

points_to_grade_mapper

Configures how points should be mapped to a grade. Valid choices:

  • passed-failed - Points is mapped directly to passed/failed. Zero points results in a failing grade, other points results in a passing grade.
  • raw-points - The grade is <points>/<max-points>.
  • table-lookup - Points is mapped to a grade via a table lookup. This means that someone configures a mapping from point thresholds to grades using devilry.apps.core.models.PointRangeToGrade.
grading_system_plugin_id

A CharField containing the ID of the grading system plugin this assignment uses.

students_can_create_groups

BooleanField specifying if students can join/leave groups on their own.

If this is True students should be allowed to join/leave groups. If students_can_not_create_groups_after is specified, this students can not create groups after students_can_not_create_groups_after even if this is True.

This does not in any way affect an admins ability to organize students in groups manually.

students_can_not_create_groups_after

Students can not create project groups after this time. Ignored if students_can_create_groups is False.

DateTimeField that defaults to None (null).

students_can_create_groups_now

Return True if students_can_create_groups is True, and students_can_not_create_groups_after is in the future or None.

is_electronic()

Returns True if deliverytypes is 0 (electric).

New in version 1.4.0.

is_nonelectronic()

Returns True if deliverytypes is 1 (non-electric).

New in version 1.4.0.

set_max_points(max_points)

Sets max_points, and invalidates any PointToGradeMap configured for this assignment if the new value for max_points differs from the old one.

Invalidating the PointToGradeMap ensures that the course admin has to re-evaluate the grade to point mapping when they change max_points.

NOTE: This saves the PointToGradeMap, but not the assignment.

get_gradingsystem_plugin_api()

Shortcut for:

devilry.devilry_gradingsystem.pluginregistry.gradingsystempluginregistry.get(
    self.grading_system_plugin_id)(self)

See: devilry.devilry_gradingsystem.pluginregistry.GradingSystemPluginRegistry.get().

has_valid_grading_setup()

Checks if this assignment is configured correctly for grading.

setup_grading(grading_system_plugin_id, points_to_grade_mapper, passing_grade_min_points=None, max_points=None)

Setup all of the simple parts of the grading system:

Does not setup:

  • Grading system plugin specific configuration.
  • A PointToGradeMap.
get_point_to_grade_map()

Get the PointToGradeMap for this assinment, creating if first if it does not exist.

points_is_passing_grade(points)

Checks if the given points represents a passing grade.

WARNING: This will only work if passing_grade_min_points is set. The best way to check that is with has_valid_grading_setup().

points_to_grade(points)

Convert the given points into a grade.

WARNING: This will not work if has_valid_grading_setup() is not True.

clean(*args, **kwargs)

Validate the assignment.

Always call this before save()! Read about validation here: http://docs.djangoproject.com/en/dev/ref/models/instances/#id1

Raises ValidationError if publishing_time is not between Period.start_time and Period.end_time.

is_empty()

Returns True if this Assignment does not contain any deliveries.

is_active()

Returns True if this assignment is published, and the period has not ended yet.

Examiner

class devilry.apps.core.models.Examiner(*args, **kwargs)

Bases: django.db.models.base.Model, devilry.apps.core.models.abstract_is_admin.AbstractIsAdmin

assignmentgroup

The AssignmentGroup where this groups belongs.

user

A foreign key to a User.

Candidate

class devilry.apps.core.models.Candidate(*args, **kwargs)

Bases: django.db.models.base.Model

assignment_group

The AssignmentGroup where this groups belongs.

student

A student (a foreign key to a User).

candidate_id

A optional candidate id. This can be anything as long as it is not more than 30 characters. When the assignment is anonymous, this is the “name” shown to examiners instead of the username of the student.

AssignmentGroup

class devilry.apps.core.models.AssignmentGroup(*args, **kwargs)

Bases: django.db.models.base.Model, devilry.apps.core.models.abstract_is_admin.AbstractIsAdmin, devilry.apps.core.models.abstract_is_examiner.AbstractIsExaminer, devilry.apps.core.models.model_utils.Etag

Represents a student or a group of students.

parentnode

A django.db.models.ForeignKey that points to the parent node, which is always an Assignment.

name

An optional name for the group.

candidates

A django RelatedManager that holds the candidates on this group.

examiners

A django.db.models.ManyToManyField that holds the examiner(s) that are to correct and grade the assignment.

is_open

A django.db.models.BooleanField that tells you if the group can add deliveries or not.

deadlines

A django RelatedManager that holds the deadlines on this group.

tags

A django RelatedManager that holds the tags on this group.

feedback

The last StaticFeedback (by save timestamp) on this assignmentgroup.

last_deadline

The last devilry.apps.core.models.Deadline for this assignmentgroup.

etag

A DateTimeField containing the etag for this object.

delivery_status

A CharField containing the status of the group. Valid status values:

  • “no-deadlines”
  • “corrected”
  • “closed-without-feedback”
  • “waiting-for-something”
save(*args, **kwargs)
Parameters:
  • update_delivery_status – Update the delivery_status? This is a somewhat expensive operation, so we provide the option to avoid it if needed. Defaults to True.
  • autocreate_first_deadline_for_nonelectronic – Autocreate the first deadline if non-electronic assignment? Defaults to True.
classmethod q_is_candidate(user_obj)

Returns a django.models.Q object matching AssignmentGroups where the given student is candidate.

classmethod where_is_candidate(user_obj)

Returns a QuerySet matching all AssignmentGroups where the given user is student.

Parameters:user_obj – A django.contrib.auth.models.User object.
Return type:QuerySet
classmethod published_where_is_candidate(user_obj, old=True, active=True)

Returns a QuerySet matching all published assignment groups where the given user is student.

Parameters:user_obj – A django.contrib.auth.models.User object.
Return type:QuerySet
classmethod active_where_is_candidate(user_obj)

Returns a QuerySet matching all active assignment groups where the given user is student.

Parameters:user_obj – A django.contrib.auth.models.User object.
Return type:QuerySet
classmethod old_where_is_candidate(user_obj)

Returns a QuerySet matching all old assignment groups where the given user is student.

Parameters:user_obj – A django.contrib.auth.models.User object.
Return type:QuerySet
should_ask_if_examiner_want_to_give_another_chance

True if the current state of the group is such that the examiner should be asked if they want to give them another chance.

True if corrected with failing grade or closed without feedback.

missing_expected_delivery

Return True if the group has no deliveries, and we are expecting them to have made at least one delivery on the last deadline.

subject

Shortcut for parentnode.parentnode.parentnode.

period

Shortcut for parentnode.parentnode.

assignment

Alias for parentnode.

short_displayname

A short displayname for the group. If the assignment is anonymous, we list the candidate IDs. If the group has a name, the name is used, else we fall back to a comma separated list of usernames. If the group has no name and no students, we use the ID.

long_displayname

A long displayname for the group. If the assignment is anonymous, we list the candidate IDs.

If the assignment is not anonymous, we use a comma separated list of the displaynames (full names with fallback to username) of the students. If the group has a name, we use the groupname with the names of the students in parenthesis.

get_students()

Get a string containing all students in the group separated by comma and a space, like: superman, spiderman, batman.

WARNING: You should never use this method when the user is not an administrator.

get_examiners(separator=u', ')

Get a string contaning the username of all examiners in the group separated by comma (',').

Parameters:separator – The unicode string used to separate candidates. Defaults to u', '.
is_examiner(user_obj)

Return True if user is examiner on this assignment group

can_delete(user_obj)

Check if the given user is permitted to delete this AssignmentGroup. A user is permitted to delete an object if the user is superadmin, or if the user is admin on the assignment (uses is_admin()). Only superusers are allowed to delete AssignmentGroups where AssignmentGroup.is_empty() returns False.

Note

This method can also be used to check if candidates can be removed from the group.

Returns:True if the user is permitted to delete this object.
is_empty()

Returns True if this AssignmentGroup does not contain any deliveries.

get_active_deadline()

Get the active Deadline.

This is always the last deadline on this group.

Returns:The latest deadline or None.
can_save(user_obj)

Check if the user has permission to save this AssignmentGroup.

can_add_deliveries()

Returns true if a student can add deliveries on this assignmentgroup

Both the assignmentgroups is_open attribute, and the periods start and end time is checked.

copy_all_except_candidates()

Note

Always run this is a transaction.

pop_candidate(candidate)

Make a copy of this group using copy_all_except_candidates, and add given candidate to the copied group and remove the candidate from this group.

Parameters:candidate – A devilry.apps.core.models.Candidate object. The candidate must be among the candidates on this group.

Note

Always run this is a transaction.

recalculate_delivery_numbers()

Query all successful deliveries on this AssignmentGroup, ordered by time_of_delivery ascending, and number them with the oldest delivery as number 1.

merge_into(target)

Merge this AssignmentGroup into the target AssignmentGroup. Algorithm:

  • Copy in all candidates and examiners not already on the AssignmentGroup.

  • Delete all copies where the original is in self or target:
    • Delete all deliveries from target that are copy_of a delivery self.
    • Delete all deliveries from self that are copy_of a delivery in target.
  • Loop through all deadlines in this AssignmentGroup, and for each deadline:

    If the datetime and text of the deadline matches one already in target, move the remaining deliveries into the target deadline.

    If the deadline and text does NOT match a deadline already in target, change assignmentgroup of the deadline to the master group.

  • Recalculate delivery numbers of target using recalculate_delivery_numbers().

  • Run self.delete().

  • Set the latest feedback on target as the active feedback.

Note

The target.name or target.is_open is not changed.

Note

Everything except setting the latest feedback runs in a transaction. Setting the latest feedback does not run in transaction because we need to save the with feedback=None, and then set the new latest feedback to avoid IntegrityError.

classmethod merge_many_groups(sources, target)

Loop through the sources-iterable, and for each source in the iterator, run source.merge_into(target).

get_status()

Get the status of the group. Calculated with this algorithm:

if ``delivery_status == 'waiting-for-something'``
    if assignment.delivery_types==NON_ELECTRONIC:
        "waiting-for-feedback"
    else
        if before deadline
            "waiting-for-deliveries"
        if after deadline:
            "waiting-for-feedback"
else
    delivery_status

AssignmentGroupTag

class devilry.apps.core.models.AssignmentGroupTag(*args, **kwargs)

Bases: django.db.models.base.Model

An AssignmentGroup can be tagged with zero or more tags using this class.

assignment_group

The AssignmentGroup where this groups belongs.

tag

The tag. Max 20 characters. Can only contain a-z, A-Z, 0-9 and “_”.

Deadline

Each AssignmentGroup have zero or more deadlines.

class devilry.apps.core.models.Deadline(*args, **kwargs)

Bases: django.db.models.base.Model, devilry.apps.core.models.abstract_is_admin.AbstractIsAdmin, devilry.apps.core.models.abstract_is_examiner.AbstractIsExaminer, devilry.apps.core.models.abstract_is_candidate.AbstractIsCandidate

A deadline on an AssignmentGroup. A deadline contains zero or more deliveries, the time of the deadline and an optional text.

assignment_group

The AssignmentGroup where the deadline is registered.

deadline

The deadline a DateTimeField.

text

A optional deadline text.

deliveries

A django RelatedManager that holds the deliveries on this group. NOTE: You should normally not use this directly, but rather use meth:.query_successful_deliveries.

deliveries_available_before_deadline

Should deliveries on this deadline be available to examiners before the deadline expires? This is set by students.

feedbacks_published

If this boolean field is True, the student can see all StaticFeedback objects associated with this Deadline through a Delivery. See also Assignment.examiners_publish_feedbacks_directly.

added_by

The User that added this deadline. Can be None, and all deadlines created before Devilry version 1.4.0 has this set to None.

New in version 1.4.0.

why_created

Why was this deadline created? Valid choices:

  • None: Why the deadline was created is unknown.
  • "examiner-gave-another-chance": Created because the examiner elected to give the student another chance to pass the assignment.

Can be None, and all deadlines created before Devilry version 1.4.0 has this set to None.

New in version 1.4.0.

classmethod reduce_datetime_precision(datetimeobj)

Reduce the precition of the datetimeobj to make it easier to compare and harder to make distinct deadlines that is basically the same time. We:

  • Set seconds and microseconds to 0. This makes “Friday 14:59”, “Friday 14:59:00” and “Friday 14:59:59” equal. We do not allow specifying seconds in the UI, and handling this right in the core makes this easier to handle across the board.
  • Set tzinfo to None. We do not support timezones in Devilry, so including it makes no sense.
Returns:A copy of datetimeobj with second and microsecond set to 0, and tzinfo set to None.
clean(*args, **kwargs)

Validate the deadline.

Always call this before save()! Read about validation here: http://docs.djangoproject.com/en/dev/ref/models/instances/#id1

Raises ValidationError if:

  • deadline is before Assignment.publishing_time.
  • deadline is not before Period.end_time.
save(*args, **kwargs)
Parameters:autocreate_delivery_if_nonelectronic – Autocreate a delivery if this save creates the deadline, and the assignment is non-electronic. Defaults to True.
query_successful_deliveries()

Returns a django QuerySet that filters all the successful deliveries on this group.

is_empty()

Returns True if this Deadline does not contain any deliveries.

can_delete(user_obj)

Check if the given user is permitted to delete this object. A user is permitted to delete an Deadline if the user is superadmin, or if the user is admin on the assignment. Only superusers are allowed to delete deadlines with any deliveries.

Returns:True if the user is permitted to delete this object.
copy(newgroup)

Copy this deadline into newgroup, including all deliveries and filemetas, with the actual file data.

Note

Always run this is a transaction.

Warning

This does not autoset the latest feedback as active on the group. You need to handle that yourself after the copy.

is_in_the_future()

Return True if this deadline is in the future.

is_in_the_past()

Return True if this deadline is in the past.

has_text()

Checks that the text is not None or an empty string.

Delivery

Examples

Simple example:

assignmentgroup = AssignmentGroup.objects.get(id=1)
assignmentgroup.deliveries.create(delivered_by=student1,
                                  successful=True)

More advanced example:

assignmentgroup = AssignmentGroup.objects.get(id=1)
delivery = assignmentgroup.deliveries.create(delivered_by=student1,
                                             successful=False)
delivery.add_file('test.py', ['print', 'hello world'])
delivery.add_file('test2.py', ['print "hi"'])
delivery.successful = True
delivery.save()

The input to add_file() will normally be a file-like object, but as shown above it can be anything you want.

Delivery API

class devilry.apps.core.models.Delivery(*args, **kwargs)

Bases: django.db.models.base.Model, devilry.apps.core.models.abstract_is_admin.AbstractIsAdmin, devilry.apps.core.models.abstract_is_candidate.AbstractIsCandidate, devilry.apps.core.models.abstract_is_examiner.AbstractIsExaminer

A class representing a given delivery from an AssignmentGroup.

How to create a delivery:

deadline = Deadline.objects.get(....)
candidate = Candidate.objects.get(....)
delivery = Delivery(
    deadline=deadline,
    delivered_by=candidate)
delivery.set_number()
delivery.full_clean()
delivery.save()
time_of_delivery

A django.db.models.DateTimeField that holds the date and time the Delivery was uploaded.

deadline

A django.db.models.ForeignKey pointing to the Deadline for this Delivery.

number

A django.db.models.fields.PositiveIntegerField with the delivery-number within this assignment-group. This number is automatically incremented within each assignmentgroup, starting from 1. Must be unique within the assignment-group. Automatic incrementation is used if number is None when calling save().

delivered_by

A django.db.models.ForeignKey pointing to the user that uploaded the Delivery

successful

A django.db.models.BooleanField telling whether or not the Delivery was successfully uploaded.

after_deadline

A django.db.models.BooleanField telling whether or not the Delivery was delived after deadline..

filemetas

A set of filemetas for this delivery.

feedbacks

A set of feedbacks on this delivery.

etag

A DateTimeField containing the etag for this object.

copy_of

Link to a delivery that this delivery is a copy of. This is set by Delivery.copy().

last_feedback

The last StaticFeedback on this delivery. This is updated each time a feedback is added.

copy_of

If this delivery is a copy of another delivery, this ForeignKey points to that other delivery.

copies

The reverse of copy_of - a queryset that returns all copies of this delivery.

after_deadline

Compares the deadline and time of delivery. If time_of_delivery is greater than the deadline, return True.

classmethod q_is_candidate(user_obj)

Returns a django.models.Q object matching Deliveries where the given student is candidate.

is_last_delivery

Returns True if this is the last delivery for this AssignmentGroup.

assignment_group

Shortcut for self.deadline.assignment_group.assignment.

assignment

Shortcut for self.deadline.assignment_group.assignment.

add_file(filename, iterable_data)

Add a file to the delivery.

Parameters:
  • filename – A filename as defined in FileMeta.
  • iterable_data – A iterable yielding data that can be written to file using the write() method of a storage backend (byte strings).
clean(*args, **kwargs)

Validate the delivery.

copy(newdeadline)

Copy this delivery, including all FileMeta’s and their files, and all feedbacks into newdeadline. Sets the copy_of attribute of the created delivery.

Note

Always run this in a transaction.

Warning

This does not autoset the latest feedback as feedback or the last_delivery on the group. You need to handle that yourself after the copy.

Returns:The newly created, cleaned and saved delivery.
is_electronic()

Returns True if Delivery.delivery_type is 0 (electric).

is_nonelectronic()

Returns True if Delivery.delivery_type is 1 (non-electric).

StaticFeedback

class devilry.apps.core.models.StaticFeedback(*args, **kwargs)

Bases: django.db.models.base.Model, devilry.apps.core.models.abstract_is_admin.AbstractIsAdmin, devilry.apps.core.models.abstract_is_examiner.AbstractIsExaminer, devilry.apps.core.models.abstract_is_candidate.AbstractIsCandidate

Represents a feedback for a Delivery.

Each delivery can have zero or more feedbacks. Each StaticFeedback object stores static data that an examiner has published on a delivery. StaticFeedback is created and edited in a grade+feedback editor in a grade plugin, and when an examiner choose to publish feedback, a static copy of the data he/she created in the grade+feedback editor is stored in a StaticFeedback.

Feedbacks are only visible to students when Deadline.feedbacks_published on the related deadline is True. Feedbacks are related to Deadlines through its delivery.

Students are presented with the last feedback on a delivery, however they can browse every StaticFeedback on their deliveries. This history is to protect the student from administrators or examiners that change published feedback to avoid that a student can make an issue out of a bad feedback.

NOTE: When a StaticFeedback is saved, the corresponding AssignmentGroup.feedback is updated to the newly created StaticFeedback.

rendered_view

The rendered HTML view.

saved_by

The django.contrib.auth.models.User that created the StaticFeedback.

save_timestamp

Date/time when this feedback was created.

delivery

A django.db.models.ForeignKey that points to the Delivery where this feedback belongs.

grade

The grade as a short string (max 12 chars).

points

The number of points (integer).

is_passing_grade

Boolean is passing grade?

classmethod q_is_candidate(user_obj)

Returns a django.models.Q object matching Deliveries where the given student is candidate.

classmethod q_is_examiner(user_obj)

Returns a django.models.Q object matching Feedbacks where the given student is candidate.

classmethod from_points(points, assignment=None, **kwargs)

Shortcut method to initialize the StaticFeedback object from points.

Initializes a StaticFeedback with the given points, with grade and is_passing_grade inferred from the points with the help of devilry.apps.core.models.Assignment.points_to_grade() and devilry.apps.core.models.Assignment.points_is_passing_grade().

Example:

feedback = StaticFeedback.from_points(
    assignment=myassignment,
    points=10,
    delivery=mydelivery,
    saved_by=someuser)
assert(feedback.id == None)
assert(feedback.grade != None)
Parameters:
  • points – The number of points for the feedback.
  • assignment

    An Assignment object. Should be the assignment where delivery this feedback is for belongs, but that is not checked.

    Defaults to self.delivery.deadline.assignment_group.assignment.

    We provide the ability to take the assignment as argument instead of looking it up via self.delivery.deadline.assignment_group because we want to to be efficient when creating feedback in bulk.

  • kwargs – Extra kwargs for the StaticFeedback constructor.
Returns:

An (unsaved) StaticFeedback.

save(*args, **kwargs)
Parameters:
  • autoset_timestamp_to_now – Automatically set the timestamp-attribute of this model to now? Defaults to True.
  • autoupdate_related_models

    Automatically update related models:

    • Sets the last_feedback-attribute of self.delivery and saved the delivery.
    • Sets the feedback and is_open attributes of self.delivery.deadline.assignment_group to this feedback, and False. Saves the AssignmentGroup.

    Defaults to True.

copy(newdelivery)

Copy this StaticFeedback into newdeadline.

Note

This only copies the StaticFeedback, not any data related to it via any grade editors.

Warning

This does not autoset the feedback as active on the group or as latest on the delivery. You need to handle that yourself after the copy.

FileMeta

class devilry.apps.core.models.FileMeta(*args, **kwargs)

Bases: django.db.models.base.Model, devilry.apps.core.models.abstract_is_admin.AbstractIsAdmin, devilry.apps.core.models.abstract_is_examiner.AbstractIsExaminer, devilry.apps.core.models.abstract_is_candidate.AbstractIsCandidate

Represents the metadata for a file belonging to a Delivery.

A file meta is just information about a single file, which is stored in a deliverystore. Use the deliverystore to manage the file stored in its physical location. Example:

filemeta = FileMeta.objects.get(pk=0)
if filemeta.deliverystore.exists(filemeta):
    filemeta.deliverystore.remove(filemeta)

# Write or read just as with the builtin open()
fobj = filemeta.deliverystore.write_open(filemeta)
fobj.write('Hello')
fobj.write('World')
fobj.close()
fobj = filemeta.deliverystore.read_open(filemeta)
print fobj.read()

See DeliveryStore for more details on deliverystores.

delivery

A django.db.models.ForeignKey that points to the Delivery of the given feedback.

filename

Name of the file.

size

Size of the file in bytes.

deliverystore

The current DeliveryStore. Class variable.

get_all_data_as_string()

Get all data store in the deliverystore for this FileMeta as a string. THIS IS ONLY FOR TESTING, and should NEVER be used for production code, since it will eat all memory on the server for huge files.

copy(newdelivery)

Copy this filemeta into newdelivery. Copies the database object and the data in the deliverystore.

DevilryUserProfile

See also: The Devilry User object.

class devilry.apps.core.models.DevilryUserProfile(*args, **kwargs)

Bases: django.db.models.base.Model

User profile with a one-to-one relation to django.contrib.auth.models.User.

Ment to be used as a Django user profile (AUTH_PROFILE_MODULE).

full_name

Django splits names into first_name and last_name. They are only 30 chars each. Read about why this is not a good idea here:

Since we require support for any name, we use our own full_name field, and ignore the one in Django. Max length 300.

languagecode

Used to store the preferred language for a user. Not required (The UI defaults to the default language)

get_displayname()

Get a name for this user, preferrably the full name, but falls back to username of that is unavailable.