diff --git a/opentech/apply/review/forms.py b/opentech/apply/review/forms.py
index 9987745338e627a82da14fb1981f4110b1d0c625..67bdeed8282a5b9090498689c1ce25475ab5031c 100644
--- a/opentech/apply/review/forms.py
+++ b/opentech/apply/review/forms.py
@@ -4,7 +4,7 @@ from django.core.exceptions import NON_FIELD_ERRORS
 from opentech.apply.review.options import NA
 from opentech.apply.stream_forms.forms import StreamBaseForm
 
-from .models import Review
+from .models import Review, ReviewOpinion
 
 
 class MixedMetaClass(type(StreamBaseForm), type(forms.ModelForm)):
@@ -84,3 +84,19 @@ class ReviewModelForm(StreamBaseForm, forms.ModelForm, metaclass=MixedMetaClass)
             return sum(scores) / len(scores)
         except ZeroDivisionError:
             return NA
+
+
+class ReviewOpinionForm(forms.ModelForm):
+
+    class Meta:
+        model = ReviewOpinion
+        fields = ('opinion',)
+
+    def __init__(self, *args, **kwargs):
+        if kwargs.get('user'):
+            self.user = kwargs.pop('user')
+        super().__init__(*args, **kwargs)
+
+    def save(self, commit=True):
+        # TODO: save the review here
+        return super().save(False)
diff --git a/opentech/apply/review/templates/review/review_detail.html b/opentech/apply/review/templates/review/review_detail.html
index 4a82a07322bf04ed897c272dc3a90bba5ee25c7a..1684b3a43c0f21c861f3c5ce9cbdc1ec8219016a 100644
--- a/opentech/apply/review/templates/review/review_detail.html
+++ b/opentech/apply/review/templates/review/review_detail.html
@@ -33,4 +33,11 @@
 
     {{ object.output_answers|submission_links }}
 </div>
+
+<form method="post">
+    {% csrf_token %}
+    {{ form }}
+    <button id="submit" name="submit">Submit</button>
+</form>
+
 {% endblock %}
diff --git a/opentech/apply/review/views.py b/opentech/apply/review/views.py
index 0a075b5c11d1b6ed45d76abe6213944378acb7a8..15c3eca7c837be66d182f877203ac051d7960f9d 100644
--- a/opentech/apply/review/views.py
+++ b/opentech/apply/review/views.py
@@ -2,21 +2,22 @@ from django.contrib.auth.decorators import login_required
 from django.core.exceptions import PermissionDenied
 from django.http import HttpResponseRedirect
 from django.shortcuts import get_object_or_404
-from django.urls import reverse_lazy
+from django.urls import reverse_lazy, reverse
 from django.utils.decorators import method_decorator
-from django.views.generic import ListView, DetailView
+from django.views.generic import ListView, DetailView, FormView
+from django.views.generic.detail import SingleObjectMixin
 
 from wagtail.core.blocks import RichTextBlock
 
 from opentech.apply.activity.messaging import messenger, MESSAGES
 from opentech.apply.funds.models import ApplicationSubmission
 from opentech.apply.review.blocks import RecommendationBlock, RecommendationCommentsBlock
-from opentech.apply.review.forms import ReviewModelForm
+from opentech.apply.review.forms import ReviewModelForm, ReviewOpinionForm
 from opentech.apply.stream_forms.models import BaseStreamForm
 from opentech.apply.users.decorators import staff_required
 from opentech.apply.utils.views import CreateOrUpdateView
 
-from .models import Review
+from .models import Review, ReviewOpinion
 
 
 class ReviewContextMixin:
@@ -99,10 +100,14 @@ class ReviewCreateOrUpdateView(BaseStreamForm, CreateOrUpdateView):
         return self.submission.get_absolute_url()
 
 
-@method_decorator(login_required, name='dispatch')
-class ReviewDetailView(DetailView):
+class ReviewDisplay(DetailView):
     model = Review
 
+    def get_context_data(self, **kwargs):
+        context = super().get_context_data(**kwargs)
+        context['form'] = ReviewOpinionForm()
+        return context
+
     def dispatch(self, request, *args, **kwargs):
         review = self.get_object()
         author = review.author
@@ -116,6 +121,40 @@ class ReviewDetailView(DetailView):
         return super().dispatch(request, *args, **kwargs)
 
 
+class ReviewOpinionFormView(SingleObjectMixin, FormView):
+    template_name = 'review/review_detail.html'
+    form_class = ReviewOpinionForm
+    model = Review
+
+    def get_form_kwargs(self):
+        kwargs = super().get_form_kwargs()
+        kwargs['user'] = self.request.user
+        return kwargs
+
+    def post(self, request, *args, **kwargs):
+        self.object = self.get_object()
+
+        form = self.get_form()
+        if form.is_valid():
+            form.save()
+
+        return super().post(request, *args, **kwargs)
+
+    def get_success_url(self):
+        return reverse('apply:submissions:reviews:review', args=(self.object.submission.pk, self.object.id,))
+
+
+@method_decorator(login_required, name='dispatch')
+class ReviewDetailView(DetailView):
+    def get(self, request, *args, **kwargs):
+        view = ReviewDisplay.as_view()
+        return view(request, *args, **kwargs)
+
+    def post(self, request, *args, **kwargs):
+        view = ReviewOpinionFormView.as_view()
+        return view(request, *args, **kwargs)
+
+
 @method_decorator(staff_required, name='dispatch')
 class ReviewListView(ListView):
     model = Review