Developer’s Guide

There are two things a Zadig developer is expected to do: (1) create new object types; and (2) create applets. We explain those in separate chapters below. It is essential to first read the Concepts document.

Creating Zadig applications

A Zadig application is a Django application, and, as such, is added in the INSTALLED_APPS setting. The application can reside anywhere in the Python path. The Zadig applications (e.g. zadig.zstandard) included in the Zadig distribution are under the zadig directory.

Such applications should have an __init__.py file and a __models__.py. If they have any extra templates, they should also have a templates directory. If they have applets, they should also have a templatetags directory. If they have any additional general actions, these should be in views.py (general actions will be examined below).

Creating new object types

New object types are declared in models.py. You need to subclass Entry and VObject, and create a form for editing the object.

The Entry subclass must define the vobject_class class attribute, whose value must be the VObject subclass. The Entry subclass should also define typename. Finally, when necessary, it should also override edit_template_name, edit_subform(), and process_edit_subform().

The VObject subclass should have Django fields for storing the vobject content, and it should also define the action_view() and action_info() methods. If the subclass has related models (e.g. other models that have foreign keys to the subclass), you may also need to override the duplicate() method.

If you use the existing applications’ object types implementation as an example, you should not have any problem understanding things better.

The action dispatcher

When the URL of a GET request is of the form /path_to_entry/__actionname__/remainder, or the action parameter of a POST request is set, and the action is not known to the Zadig core code, then Zadig searches for such an action in three places:

  1. It checks whether the VObject pointed by path_to_entry has a method called action_actionname.
  2. Failing that, it searches for such a method in the Entry class.
  3. Failing that, if actionname contains a dot, i.e. it is of the form app.func, it searches for a callable func in zadig.app.views.

If no appropriate callable is found, Http404 is raised. If it is found, it is called, passing the vobject as the first argument. In GET requests, vobject.request.parms is set to the URL remainder.

An example of such a view is the “resized” action of an image. If you append /__resized__/400 to the URL of an image, then you will see the image resized so that its largest dimension is 400 pixels. This is accomplished because the zadig.zstandard.VImage class has a action_resized() method.

Creating applets

To create an applet, create a custom template tag (read the Django documentation for that). If you want your applet to store information in the database, add models in models.py.

Incomplete

I’ve not yet gotten to write about entry option sets.

If the applet is a portlet, you need to do two more things. First, make sure that the tag output conforms to the portlet specification:

<dl class="portlet">
  <dt>Portlet title</dt>
  <dd>First item</dd>
  <dd>Second item</dd>
  ...
  <dd class="lastItem">Last item</dd>
</dl>

Second, in the top level __init__.py of your application, add the following:

from zadig.core import portlets
portlets.append({ 'name': _(u"My portlet"), 'tag': "myportlettag", },
                # Add more items to this list if your
                # application defines more than one portlets.
               )

The request object

Low level Zadig code needs to be aware of the request object all the time. It uses the request object for two purposes: First, it uses request.user to check whether the user has permissions to do various operations; for example, when you call the get_by_path() method of the default Entry manager, it only returns an Entry if the user has permission to view it; and the default manager’s querysets only include entries which the user has permission to search. Second, some additional information is stored for later usage in the request object, such as the preferred and effective languages.

In order to avoid passing the request object all the time and treat this at a low level, transparently for the high level developer, which is important for security, the low level code gets the request object by calling zadig.core.utils.get_object() (the Zadig middleware saves it at the start of execution by calling zadig.core.utils.set_object()). You should, however, avoid to use that at a high level; consider it a Zadig internal. Use the request object as it is normally being used in Django; just be aware that the Zadig core objects have access to it even if you don’t provide it. In addition, Entry and VObject instances have a request attribute which you can use, particularly when you are subclassing them.

If you are not using the API in the context of a web server (for example if you are creating a command-line utility), and therefore you don’t have a request object, low level code will sometimes fail and sometimes automatically consider that it is running with the permissions of the anonymous user. If this is insufficient, do something like the following:

from django.http import HttpRequest
from django.contrib.auth.models import User
from zadig.core.utils import set_request
request = HttpRequest()
request.user = User.objects.get(username=MY_USERNAME)
set_request(request)

# Do what you need at this point

set_request(None) # This is for cleanup and it is important in case you
                  # attempt to set it to a not None value again further
                  # below.