diff --git a/opentech/apply/funds/models/submissions.py b/opentech/apply/funds/models/submissions.py
index 811ee371bb330642fd2b52d926375fca35917198..866c57428b034800c956fd6298005f00ab566769 100644
--- a/opentech/apply/funds/models/submissions.py
+++ b/opentech/apply/funds/models/submissions.py
@@ -20,7 +20,7 @@ from wagtail.core.fields import StreamField
 from wagtail.contrib.forms.models import AbstractFormSubmission
 
 from opentech.apply.activity.messaging import messenger, MESSAGES
-from opentech.apply.stream_forms.blocks import UploadableMediaBlock
+from opentech.apply.stream_forms.blocks import FormFieldBlock, UploadableMediaBlock
 from opentech.apply.stream_forms.models import BaseStreamForm
 from opentech.apply.utils.blocks import MustIncludeFieldBlock
 
@@ -192,7 +192,12 @@ class AddTransitions(models.base.ModelBase):
         return super().__new__(cls, name, bases, attrs, **kwargs)
 
 
-class ApplicationSubmission(WorkflowHelpers, BaseStreamForm, AbstractFormSubmission, metaclass=AddTransitions):
+class ApplicationSubmission(
+        WorkflowHelpers,
+        BaseStreamForm,
+        AbstractFormSubmission,
+        metaclass=ApplicationSubmissionMetaclass,
+):
     field_template = 'funds/includes/submission_field.html'
 
     form_data = JSONField(encoder=DjangoJSONEncoder)
@@ -386,14 +391,6 @@ class ApplicationSubmission(WorkflowHelpers, BaseStreamForm, AbstractFormSubmiss
         self.ensure_user_has_account()
         self.process_file_data()
 
-    @property
-    def must_include(self):
-        return {
-            field.block.name: field.id
-            for field in self.form_fields
-            if isinstance(field.block, MustIncludeFieldBlock)
-        }
-
     def process_form_data(self):
         for field_name, field_id in self.must_include.items():
             response = self.form_data.pop(field_id, None)
@@ -479,36 +476,11 @@ class ApplicationSubmission(WorkflowHelpers, BaseStreamForm, AbstractFormSubmiss
     def can_have_determination(self):
         return self.in_determination_phase and not self.has_determination
 
-    @property
-    def raw_data(self):
-        data = self.form_data.copy()
-        for field_name, field_id in self.must_include.items():
-            response = data.pop(field_name)
-            data[field_id] = response
-        return data
-
-    def data_and_fields(self):
-        for stream_value in self.form_fields:
-            try:
-                data = self.form_data[stream_value.id]
-            except KeyError:
-                pass  # It was a named field or a paragraph
-            else:
-                yield data, stream_value
-
-    @property
-    def fields(self):
-        return [
-            field.render(context={'data': data})
-            for data, field in self.data_and_fields()
-        ]
-
-    def render_answers(self):
-        return mark_safe(''.join(self.fields))
-
     def prepare_search_values(self):
-        for data, stream in self.data_and_fields():
-            value = stream.block.get_searchable_content(stream.value, data)
+        for field_id in self.question_field_ids:
+            field = self.field(field_id)
+            data = self.data(field_id)
+            value = field.block.get_searchable_content(field.value, data)
             if value:
                 if isinstance(value, list):
                     yield ', '.join(value)
@@ -519,15 +491,6 @@ class ApplicationSubmission(WorkflowHelpers, BaseStreamForm, AbstractFormSubmiss
         for field in ['email', 'title']:
             yield getattr(self, field)
 
-    def get_data(self):
-        # Updated for JSONField
-        form_data = self.form_data.copy()
-        form_data.update({
-            'submit_time': self.submit_time,
-        })
-
-        return form_data
-
     def get_absolute_url(self):
         return reverse('funds:submissions:detail', args=(self.id,))
 
@@ -535,7 +498,7 @@ class ApplicationSubmission(WorkflowHelpers, BaseStreamForm, AbstractFormSubmiss
         # __getattribute__ allows correct error handling from django compared to __getattr__
         # fall back to values defined on the data
         if item in REQUIRED_BLOCK_NAMES:
-            return self.get_data()[item]
+            return self.form_data[item]
         return super().__getattribute__(item)
 
     def __str__(self):
@@ -544,6 +507,95 @@ class ApplicationSubmission(WorkflowHelpers, BaseStreamForm, AbstractFormSubmiss
     def __repr__(self):
         return f'<{self.__class__.__name__}: {self.user}, {self.round}, {self.page}>'
 
+    # Methods for accessing data on the submission
+
+    def get_data(self):
+        # Updated for JSONField
+        form_data = self.form_data.copy()
+        form_data.update({
+            'submit_time': self.submit_time,
+        })
+
+        return form_data
+
+    @property
+    def raw_data(self):
+        # Returns the data mapped by field id instead of the data stored using the must include
+        # values
+        data = self.form_data.copy()
+        for field_name, field_id in self.must_include.items():
+            response = data.pop(field_name)
+            data[field_id] = response
+        return data
+
+    def field(self, id):
+        try:
+            return self.fields[id]
+        except KeyError as e:
+            try:
+                actual_id = self.must_include[id]
+            except KeyError:
+                raise e
+            else:
+                return self.fields[actual_id]
+
+    def data(self, id):
+        try:
+            return self.form_data[id]
+        except KeyError as e:
+            try:
+                transposed_must_include = {v:k for k,v in self.must_include.items()}
+                actual_id = transposed_must_include[id]
+            except KeyError:
+                # We have most likely progressed application forms so the data isnt in form_data
+                return None
+            else:
+                return self.form_data[actual_id]
+
+    @property
+    def question_field_ids(self):
+        for field_id, field in self.fields.items():
+            if isinstance(field.block, FormFieldBlock):
+                yield field_id
+
+    @property
+    def raw_fields(self):
+        # Field ids to field class mapping - similar to raw_data
+        return {
+            field.id: field
+            for field in self.form_fields
+        }
+
+    @property
+    def fields(self):
+        # ALl fields on the application
+        fields = self.raw_fields.copy()
+        for field_name, field_id in self.must_include.items():
+            response = fields.pop(field_id)
+            fields[field_name] = response
+        return fields
+
+    @property
+    def must_include(self):
+        return {
+            field.block.name: field.id
+            for field in self.form_fields
+            if isinstance(field.block, MustIncludeFieldBlock)
+        }
+
+    def render_answer(self, field_id):
+        field = self.field(field_id)
+        data = self.data(field_id)
+        return field.render(context={'data': data})
+
+    def render_answers(self):
+        answers = [
+            self.render_answer(field_id)
+            for field_id in self.question_field_ids
+            if field_id not in self.must_include
+        ]
+        return mark_safe(''.join(answers))
+
 
 @receiver(post_transition, sender=ApplicationSubmission)
 def log_status_update(sender, **kwargs):
diff --git a/opentech/apply/funds/tests/factories/blocks.py b/opentech/apply/funds/tests/factories/blocks.py
index 8d378e36123893fe29af73ade86a4f2c346fc4d8..77cc38d4c0f70518bdb3cb58e07eacdf48835dbc 100644
--- a/opentech/apply/funds/tests/factories/blocks.py
+++ b/opentech/apply/funds/tests/factories/blocks.py
@@ -2,9 +2,17 @@ import random
 import factory
 
 from opentech.apply.funds import blocks
-from opentech.apply.stream_forms.testing.factories import FormFieldBlockFactory, CharFieldBlockFactory, \
-    NumberFieldBlockFactory, RadioFieldBlockFactory, ImageFieldBlockFactory, FileFieldBlockFactory, \
-    MultiFileFieldBlockFactory, StreamFieldUUIDFactory
+from opentech.apply.stream_forms.testing.factories import (
+    CharFieldBlockFactory,
+    FileFieldBlockFactory,
+    FormFieldBlockFactory,
+    ImageFieldBlockFactory,
+    MultiFileFieldBlockFactory,
+    NumberFieldBlockFactory,
+    RadioFieldBlockFactory,
+    ParagraphBlockFactory,
+    StreamFieldUUIDFactory,
+)
 from opentech.apply.utils.testing.factories import RichTextFieldBlockFactory
 
 __all__ = ['CustomFormFieldsFactory', 'TitleBlockFactory', 'EmailBlockFactory', 'FullNameBlockFactory', 'ValueFieldBlockFactory']
@@ -31,6 +39,16 @@ class FullNameBlockFactory(FormFieldBlockFactory):
         model = blocks.FullNameBlock
 
 
+class DurationBlockFactory(FormFieldBlockFactory):
+    class Meta:
+        model = blocks.DurationBlock
+
+    @classmethod
+    def make_answer(cls, params=dict()):
+        choices = list(blocks.DurationBlock.DURATION_OPTIONS.keys())
+        return random.choice(choices)
+
+
 class ValueFieldBlockFactory(FormFieldBlockFactory):
     class Meta:
         model = blocks.ValueBlock
@@ -41,6 +59,7 @@ class ValueFieldBlockFactory(FormFieldBlockFactory):
 
 
 CustomFormFieldsFactory = StreamFieldUUIDFactory({
+    'duration': DurationBlockFactory,
     'title': TitleBlockFactory,
     'value': ValueFieldBlockFactory,
     'email': EmailBlockFactory,
@@ -52,4 +71,5 @@ CustomFormFieldsFactory = StreamFieldUUIDFactory({
     'image': ImageFieldBlockFactory,
     'file': FileFieldBlockFactory,
     'multi_file': MultiFileFieldBlockFactory,
+    'text_markup': ParagraphBlockFactory,
 })
diff --git a/opentech/apply/funds/tests/factories/models.py b/opentech/apply/funds/tests/factories/models.py
index 286c340cd1fd4a05721107d15625c0a5aa5ec4cc..9dc63483098b9159a5544404e650756f51c3dd64 100644
--- a/opentech/apply/funds/tests/factories/models.py
+++ b/opentech/apply/funds/tests/factories/models.py
@@ -42,25 +42,6 @@ __all__ = [
 ]
 
 
-def build_form(data, prefix=''):
-    if prefix:
-        prefix += '__'
-
-    extras = defaultdict(dict)
-    for key, value in data.items():
-        if 'form_fields' in key:
-            _, field, attr = key.split('__')
-            extras[field][attr] = value
-
-    form_fields = {}
-    for i, field in enumerate(blocks.CustomFormFieldsFactory.factories):
-        form_fields[f'{prefix}form_fields__{i}__{field}__'] = ''
-        for attr, value in extras[field].items():
-            form_fields[f'{prefix}form_fields__{i}__{field}__{attr}'] = value
-
-    return form_fields
-
-
 class FundTypeFactory(wagtail_factories.PageFactory):
     class Meta:
         model = FundType
@@ -89,16 +70,14 @@ class FundTypeFactory(wagtail_factories.PageFactory):
     @factory.post_generation
     def forms(self, create, extracted, **kwargs):
         if create:
-            from opentech.apply.review.tests.factories.models import build_form as review_build_form, ReviewFormFactory
-            fields = build_form(kwargs, prefix='form')
-            review_fields = review_build_form(kwargs)
+            from opentech.apply.review.tests.factories.models import ReviewFormFactory
             for _ in self.workflow.stages:
                 # Generate a form based on all defined fields on the model
                 ApplicationBaseFormFactory(
                     application=self,
-                    **fields,
+                    **kwargs,
                 )
-                ReviewFormFactory(**review_fields)
+                ReviewFormFactory(**kwargs)
 
 
 class RequestForPartnersFactory(FundTypeFactory):
@@ -144,12 +123,11 @@ class RoundFactory(wagtail_factories.PageFactory):
     @factory.post_generation
     def forms(self, create, extracted, **kwargs):
         if create:
-            fields = build_form(kwargs, prefix='form')
             for _ in self.workflow.stages:
                 # Generate a form based on all defined fields on the model
                 RoundBaseFormFactory(
                     round=self,
-                    **fields,
+                    **kwargs,
                 )
 
 
@@ -184,12 +162,11 @@ class LabFactory(wagtail_factories.PageFactory):
     @factory.post_generation
     def forms(self, create, extracted, **kwargs):
         if create:
-            fields = build_form(kwargs, prefix='form')
             for _ in self.workflow.stages:
                 # Generate a form based on all defined fields on the model
                 LabBaseFormFactory(
                     lab=self,
-                    **fields,
+                    **kwargs,
                 )
 
 
@@ -236,11 +213,6 @@ class ApplicationSubmissionFactory(factory.DjangoModelFactory):
         if create and reviewers:
             self.reviewers.set(reviewers)
 
-    @classmethod
-    def _generate(cls, strat, params):
-        params.update(**build_form(params))
-        return super()._generate(strat, params)
-
 
 class SealedSubmissionFactory(ApplicationSubmissionFactory):
     page = factory.SubFactory(RequestForPartnersFactory)
diff --git a/opentech/apply/funds/tests/test_models.py b/opentech/apply/funds/tests/test_models.py
index 44b07e3891733bd7d965a3a58d94d785edb59433..9b21854c42f8127783fd6889788ba0b09b6a4293 100644
--- a/opentech/apply/funds/tests/test_models.py
+++ b/opentech/apply/funds/tests/test_models.py
@@ -172,7 +172,7 @@ class TestRoundModelWorkflowAndForms(TestCase):
         del self.round.parent_page
         form = self.round.forms.first().form
         # Not ideal, would prefer better way to create the stream values
-        new_field = CustomFormFieldsFactory.generate(None, {'0__email__': ''})
+        new_field = CustomFormFieldsFactory.generate(None, {})
         form.form_fields = new_field
         form.save()
         for round_form, fund_form in itertools.zip_longest(self.round.forms.all(), self.fund.forms.all()):
@@ -204,7 +204,8 @@ class TestFormSubmission(TestCase):
 
         page = page or self.round_page
         fields = page.get_form_fields()
-        data = {k: v for k, v in zip(fields, ['project', 0, email, name])}
+        # This needs to match the order of the fields defined on the form factory
+        data = {k: v for k, v in zip(fields, [1, 'project', 0, email, name])}
         request = make_request(user, data, method='post', site=self.site)
 
         try:
@@ -419,3 +420,28 @@ class TestApplicationSubmission(TestCase):
         submission.form_data = {'title': title}
         submission.create_revision(draft=True)
         self.assertEqual(submission.revisions.count(), 2)
+
+
+class TestSubmissionRenderMethods(TestCase):
+    def test_must_include_not_included_in_answers(self):
+        submission = ApplicationSubmissionFactory()
+        answers = submission.render_answers()
+        for name in submission.must_include:
+            field = submission.field(name)
+            self.assertNotIn(field.value['field_label'], answers)
+
+    def test_normal_answers_included_in_answers(self):
+        submission = ApplicationSubmissionFactory()
+        answers = submission.render_answers()
+        for field_name in submission.question_field_ids:
+            if field_name not in submission.must_include:
+                field = submission.field(field_name)
+                self.assertIn(field.value['field_label'], answers)
+
+    def test_paragraph_not_rendered_in_answers(self):
+        rich_text_label = 'My rich text label!'
+        submission = ApplicationSubmissionFactory(
+            form_fields__text_markup__value=rich_text_label
+        )
+        answers = submission.render_answers()
+        self.assertNotIn(rich_text_label, answers)
diff --git a/opentech/apply/review/tests/factories/models.py b/opentech/apply/review/tests/factories/models.py
index 2be83c8a6bcd513a694b4cc9bec23f03c7f4711a..83ee6ce79beb240cc57884cc72f15d3e42119d2c 100644
--- a/opentech/apply/review/tests/factories/models.py
+++ b/opentech/apply/review/tests/factories/models.py
@@ -17,24 +17,6 @@ __all__ = ['ReviewFactory', 'ReviewFormFactory', 'ApplicationBaseReviewFormFacto
            'ReviewFundTypeFactory', 'ReviewApplicationSubmissionFactory']
 
 
-def build_form(data, prefix=''):
-    if prefix:
-        prefix += '__'
-
-    extras = defaultdict(dict)
-    for key, value in data.items():
-        if 'form_fields' in key:
-            _, field, attr = key.split('__')
-            extras[field][attr] = value
-
-    form_fields = {}
-    for i, field in enumerate(blocks.ReviewFormFieldsFactory.factories):
-        form_fields[f'{prefix}form_fields__{i}__{field}__'] = ''
-        for attr, value in extras[field].items():
-            form_fields[f'{prefix}form_fields__{i}__{field}__{attr}'] = value
-
-    return form_fields
-
 
 class ReviewFormDataFactory(factory.DictFactory, metaclass=AddFormFieldsMetaclass):
     field_factory = blocks.ReviewFormFieldsFactory
@@ -89,12 +71,11 @@ class ReviewFundTypeFactory(FundTypeFactory):
     @factory.post_generation
     def review_forms(self, create, extracted, **kwargs):
         if create:
-            fields = build_form(kwargs, prefix='form')
             for _ in self.workflow.stages:
                 # Generate a form based on all defined fields on the model
                 ApplicationBaseReviewFormFactory(
                     application=self,
-                    **fields
+                    **kwargs
                 )
 
 
diff --git a/opentech/apply/stream_forms/testing/factories.py b/opentech/apply/stream_forms/testing/factories.py
index 1d03a5670b7a3c7978245cb81a10ae1a8698949b..f1bdf4479318a462b333010c7dffe6e9c23ada6d 100644
--- a/opentech/apply/stream_forms/testing/factories.py
+++ b/opentech/apply/stream_forms/testing/factories.py
@@ -5,7 +5,8 @@ import uuid
 from django.core.files.uploadedfile import InMemoryUploadedFile
 
 import factory
-from wagtail.core.blocks import CharBlock
+from wagtail.core.blocks import RichTextBlock
+from wagtail.core.rich_text import RichText
 import wagtail_factories
 
 from opentech.apply.stream_forms import blocks as stream_blocks
@@ -28,6 +29,7 @@ class AddFormFieldsMetaclass(factory.base.FactoryMetaClass):
             wrapped_factories = {
                 k: factory.SubFactory(AnswerFactory, sub_factory=v)
                 for k, v in field_factory.factories.items()
+                if issubclass(v, FormFieldBlockFactory)
             }
             attrs.update(wrapped_factories)
         return super().__new__(mcs, class_name, bases, attrs)
@@ -63,13 +65,21 @@ class FormDataFactory(factory.Factory, metaclass=AddFormFieldsMetaclass):
         return form_data
 
 
-class CharBlockFactory(wagtail_factories.blocks.BlockFactory):
+class ParagraphBlockFactory(wagtail_factories.blocks.BlockFactory):
     class Meta:
-        model = CharBlock
+        model = RichTextBlock
+
+    @classmethod
+    def _create(cls, model_class, value):
+        value = RichText(value)
+        return super()._create(model_class, value)
 
 
 class FormFieldBlockFactory(wagtail_factories.StructBlockFactory):
-    default_value = factory.Faker('word')
+    default_value = factory.Faker('sentence')
+    field_label = factory.Faker('sentence')
+    help_text = factory.LazyAttribute(lambda o: str(o._Resolver__step.builder.factory_meta.model))
+
 
     class Meta:
         model = stream_blocks.FormFieldBlock
@@ -138,8 +148,7 @@ class MultiFileFieldBlockFactory(UploadableMediaFactory):
 
 class StreamFieldUUIDFactory(wagtail_factories.StreamFieldFactory):
     def generate(self, step, params):
-        if not params:
-            params = self.build_form(params)
+        params = self.build_form(params)
         blocks = super().generate(step, params)
         ret_val = list()
         # Convert to JSON so we can add id before create
@@ -151,10 +160,17 @@ class StreamFieldUUIDFactory(wagtail_factories.StreamFieldFactory):
 
     def build_form(self, data):
         extras = defaultdict(dict)
+        for field, value in data.items():
+            # we dont care about position
+            name, attr = field.split('__')
+            extras[name] = {attr: value}
 
         form_fields = {}
         for i, field in enumerate(self.factories):
-            form_fields[f'{i}__{field}__'] = ''
+            if field == 'text_markup':
+                pass
+            else:
+                form_fields[f'{i}__{field}__'] = ''
             for attr, value in extras[field].items():
                 form_fields[f'{i}__{field}__{attr}'] = value
 
diff --git a/opentech/apply/utils/blocks.py b/opentech/apply/utils/blocks.py
index 3df0908995fc3a92ed3460762bafac95f9f6d24d..ee5aac70634505e766b063a2678858db0c5421ba 100644
--- a/opentech/apply/utils/blocks.py
+++ b/opentech/apply/utils/blocks.py
@@ -36,7 +36,7 @@ class RichTextFieldBlock(TextFieldBlock):
         icon = 'form'
 
     def get_searchable_content(self, value, data):
-        return bleach.clean(data, tags=[], strip=True)
+        return bleach.clean(data or '', tags=[], strip=True)
 
 
 class CustomFormFieldsBlock(StreamBlock):