pythonplonezopez3c.form

How can I create a z3c.form that has multiple schemas?


I am using the cms Plone to build a form that contains two other schemas.

With the Group Forms, I have been able to include both of the fields of the two schemas. However, they lose all of their properties such as hidden or when I use datagridfield to build the table. What I want to be able to do is have both of these forms with their fields and on a save be able to save them in the object which the link was clicked as parent -> object 1 [top of the form] -> object 2 [bottom of the form]

Here is my python code:

class QuestionPart(group.Group):
    label = u'Question Part'
    fields = field.Fields(IQuestionPart)
    template = ViewPageTemplateFile('questionpart_templates/view.pt')

 class Question(group.Group):
     label = u'Question'
     fields = field.Fields(IQuestion)
     template = ViewPageTemplateFile('question_templates/view.pt')

class QuestionSinglePart(group.GroupForm, form.AddForm):
    grok.name('register')
    grok.require('zope2.View')
    grok.context(ISiteRoot)
    label = u"Question with Single Part"

    ignoreContext = True
    enable_form_tabbing  = False

    groups = (Question,QuestionPart)

def update(self):
    super(QuestionSinglePart, self).update()

This code displays both the fields of IQuestion, IQuestionPart without the regard to things like: form.mode(contype='hidden') or DataGridField widget. I found a way that displays the correct form with field hints.

class QuestionSinglePart(AutoExtensibleForm, form.AddForm):
    grok.require('zope2.View')
    grok.context(ISiteRoot)

    label = u"Question"
    schema = IQuestion
    additionalSchemata = (IQuestionPart,)                             

I feel I am still a long way off. I have talked to some people. I am now trying to use a separate form and view.

So far, I am at this point with my code:

class QuestionSinglePartForm(AutoExtensibleForm, form.Form):

    ignoreContext = True

    autoGroups = True
    template = ViewPageTemplateFile('questionsinglepart_templates/questionsinglepartform.pt')

    @property
    def additionalSchemata(self):
        return self._additionalSchemata

    def __init__(self, context, request, schema, additional=()):
        self.context = context
        self.request = request
        if not IInterface.providedBy(schema):
            raise ValueError('Schema is not interface object')
        self._schema = schema
        if not all(IInterface.providedBy(s) for s in additional):
            raise ValueError('Additional schema is not interface')
        self._additionalSchemata = additional

class QuestionSinglePartView(object):

    schema = IQuestion
    additional = (IQuestionPart,)

    def __init__(self, context, request):
        self.context = context
        self.request = request
        self.form = QuestionSinglePartForm(context, request, self.schema, self.additional)

    def magic(self, data, errors):
        pass
        """
        question = Question()
        question.number = data['number']
        question.questionContent = data['questionContent']

        questionPart = QuestionPart()
        questionPart.typeOfQuestion = data['IQuestionPart.typeOfQuestion']
        questionPart.explanation = data['IQuestionPart.explanation'] 
        questionPart.fileSize = data['IQuestionPart.fileSize']
        questionPart.fileType = data['IQuestionPart.fileType']
        questionPart.hints = data['IQuestionPart.hints']
        questionPart.table = data['IQuestionPart.table']
        questionPart.contype = data['IQuestionPart.contype']
        questionPart.content = data['IQuestionPart.content']
        """

    def update(self, *args, **kwargs):
        if self.request.get('REQUEST_METHOD') == 'POST':
            data, errors = self.form.extractData()
            self.magic(data, errors)
        self.formdisplay = self.form.render()

    def __call__(self, *args, **kwargs):
        self.update(*args, **kwargs)
        return self.index(*args, **kwargs)

I am struggling with the rendering of the form and that the QuestionSinglePart object does not have an index attribute.

After a couple of hours of working with some plone devs, we have figured out what was going on.

I had left out:

    @property
    def schema(self):
        return self._schema

I needed to define an index in the view like so:

index = ViewPageTemplateFile('questionsinglepart_templates/questionsinglepart.pt')

I needed to add this to the views init:

alsoProvides(self.form, IWrappedForm)

In the update method for view I needed to call this before the formdisplay. I could also remove the data extraction and move that to the form.

def update(self, *args, **kwargs):
    self.form.update(*args, **kwargs)
    self.formdisplay = self.form.render()

I am still currently working to get the data to save into objects.


Solution

  • Here is my final code with the changes made above. There were issues with the index for the object. I needed to create a simple custom view. I forgot the property for schema on the form. I need to changed my update method for the view as well.

    class QuestionSinglePartForm(AutoExtensibleForm, form.Form):
    
        ignoreContext = True
    
        autoGroups = False
    
        @property
        def schema(self):
            return self._schema
    
        @property
        def additionalSchemata(self):
            return self._additionalSchemata
    
        def __init__(self, context, request, schema, additional=()):
            self.context = context
            self.request = request
            if not IInterface.providedBy(schema):
                raise ValueError('Schema is not interface object')
            self._schema = schema
            if not all(IInterface.providedBy(s) for s in additional):
                raise ValueError('Additional schema is not interface')
            self._additionalSchemata = additional
    
        @button.buttonAndHandler(u'Save')
        def handleSave(self, action):
            data, errors = self.extractData()
            if errors:
                return False
            obj = self.createAndAdd(data)
            if obj is not None:
                # mark only as finished if we get the new object
                self._finishedAdd = True
                IStatusMessage(self.request).addStatusMessage(_(u"Changes saved"), "info")
            print data
    
        @button.buttonAndHandler(u'Cancel')
        def handleCancel(self, action):
            print 'cancel'
    
    
    
    class QuestionSinglePartView(object):
    
        schema = IQuestion
        additional = (IQuestionPart,)
        index = ViewPageTemplateFile('questionsinglepart_templates/questionsinglepart.pt')
    
        def __init__(self, context, request):
            self.context = context
            self.request = request
            self.form = QuestionSinglePartForm(context, request, self.schema, self.additional)
            alsoProvides(self.form, IWrappedForm)
    
        def magic(self, data, errors):
            pass
            """
            question = Question()
            question.number = data['number']
            question.questionContent = data['questionContent']
    
            questionPart = QuestionPart()
            questionPart.typeOfQuestion = data['IQuestionPart.typeOfQuestion']
            questionPart.explanation = data['IQuestionPart.explanation'] 
            questionPart.fileSize = data['IQuestionPart.fileSize']
            questionPart.fileType = data['IQuestionPart.fileType']
            questionPart.hints = data['IQuestionPart.hints']
            questionPart.table = data['IQuestionPart.table']
            questionPart.contype = data['IQuestionPart.contype']
            questionPart.content = data['IQuestionPart.content']
            """
    
        def update(self, *args, **kwargs):
            self.form.update(*args, **kwargs)
            self.formdisplay = self.form.render()
    
        def __call__(self, *args, **kwargs):
            self.update(*args, **kwargs)
            return self.index(*args, **kwargs)