Skip to content
thraxil edited this page Jun 22, 2012 · 2 revisions

If you are implementing a new pageblock type, these attributes and methods are required.

attributes

pageblocks

This is the magic required to create the generic relations.

pageblocks = generic.GenericRelation(PageBlock)

template_file

template_file = "pageblocks/textblock.html"

js_template_file

js_template_file = "myblock/myblock_js.html"

css_template_file

css_template_file = "myblock/myblock_css.html"

display_name

How this block will be referred to in the interface.

display_name = "My Block"

basic methods

pageblock()

Convenience function to hide some of the generic relations mess. Just use this exact implementation unless you know what you're doing:

def pageblock(self):
    return self.pageblocks.all()[0]

add_form()

Returns a django form for creating the block. These always do not include the label field, which pagetree itself handles. These forms should only deal with the fields specific to the block type.

@classmethod
def add_form(self):
    class AddForm(forms.Form):
        body = forms.CharField(widget=forms.widgets.Textarea())
    return AddForm()

create()

Do the actual creation of the block. Should create it and return the new block. Gets a request object that should have POST data from the form.

@classmethod
def create(self, request):
    return TextBlock.objects.create(body=request.POST.get('body', ''))

edit_form()

Returns a django form object for editing this block. Should set the initial values on the fields based on the current data.

def edit_form(self):
    class EditForm(forms.Form):
        body = forms.CharField(widget=forms.widgets.Textarea(),
                               initial=self.body)
    return EditForm()

edit()

This is called when the user has edited the block in the web interface. Gets a dict of vals (basically, request.POST) and files.

def edit(self, vals, files):
    self.body = vals.get('body', '')
    self.save()

methods for serialization

as_dict()

Should return data for the block as a play Python dict suitable for immediate JSON serialization via simplejson.

def as_dict(self):
    return dict(foo=self.foo,
                bar=self.bar)

list_resources()

If the block stores anything on the filesystem in the uploads directory, it should return a list of relative paths to those uploaded files. These get collected from all the blocks on the site during an import so the client can then individually download the resources (to avoid trying to serialize them into a massive zip file or something).

def list_resources(self):
    return ['path/to/file.jpg']

create_from_dict()

Used for importing from a serialized format. Gets a python dict and should create a new block (and any ancillary objects).

@classmethod
def from_dict(cls, d):
    return MyBlock.objects.create(
        foo=d.get('foo', 'default foo value'),
        bar=d.get('bar', 'default bar value'))

exportable

These flags just mark the block as being capable of exporting/importing itself as JSON (via as_dict() and import_from_dict() below). This is for the web interface where a user can get an individual block's serialized form to copy around. The original use-case for this was the quizblock when users wanted to create a couple copies of the same quiz and didn't want to have to re-enter the questions/answers each time. This is just for the web interface, it doesn't have anything to do with the pull_from_prod stuff where the entire site gets exported/imported.

exportable = True

importable

importable = True

import_from_dict()

similar to create_from_dict(), but updates the existing one instead of making a new one. Used for the import/export individual blocks web interface. (Yeah, there's some messy overlap with the global stuff that should probably get sorted out)

def import_from_dict(self, d):
    self.foo = d.get('foo', 'default foo value')
    self.bar = d.get('bar', 'default bar value')
    self.save()

optional methods for pageblocks

needs_submit()

If a pageblock should be wrapped in a form, give it a needs_submit() method that returns true. If the method returns False or doesn't exist, pagetree will not make a form for it.

def needs_submit(self):
    return True

This is done as a method rather than an attribute because there are cases where you want the content editor to be able to specify whether the block collects data or not on a block by block basis. Eg, the quizblock has the "rhetorical" flag which, if it is set means that the quiz just shows the user the answer right on the page and they never actually submit anything to the back-end.

submit()

When the user has submitted data, pagetree collects it from all the blocks on the page, figures out which fields need to go to which blocks and then calls this method on each block with the user who submitted, and the data that's relevant to that block.

def submit(self, user, data):
    s = Submission.objects.create(quiz=self, user=user)
    for k in data.keys():
        # ... do something with the data

redirect_to_self_on_submit()

After the user has submitted, should it redirect back to this page (eg, to show feedback immediately), or just redirect them on to the next page on the site.

def redirect_to_self_on_submit(self):
    return True

unlocked()

meaning that the user can proceed past this one, not that they can access this one. careful.

def unlocked(self, user):
    return Submission.objects.filter(quiz=self, user=user).count() > 0