Stefan Stefan - 1 month ago 40
React JSX Question

ReactJS & django-forms

I have a modelform in django backend with validators, choicefields and etc. I would like to pass it to react and display it. First of all is that even possible? I would like to get it completly with validators, but just html is still great. The reason for that is:


  1. Avoiding double constant declarations on the front and back. For example select options: "male", "female", "???" would need to be on the backend for validation and frontend for display and validation.

  2. Constructing the whole html on the frontend for the form again, despite that all of it can also be easily created by django. Main concern again select options with many different custom values.



There is a package called drf-braces that has a FormSerializer but it does seem to have a problem, I constantly get a 500 error "is not JSON serializable error", like in:

name_or_event = CharFormSerializerField(error_messages={u'required':
<django.utils.functional.__proxy__ object>}, help_text='', initial=None,
label='Name', required=True, validators=[]) is not JSON serializable


This is the drf-braces based serializer as seen in drf-braces form serialization example:

from drf_braces.serializers.form_serializer import FormSerializer

from myapp.forms import SignupDataForm

class MySerializer(FormSerializer):
class Meta(object):
form = SignupDataForm


and the API view based on rest-auth RegisterView:

from myapp.serializers import MySerializer

class TestView(RegisterView):

permission_classes = (AllowAny,)
allowed_methods = ('GET', )
serializer_class = MySerializer

def get(self, *args, **kwargs):
serializer = self.serializer_class()
return Response({'serializer': serializer}, status=status.HTTP_200_OK)


If I open the url assigned to TestView in browser I can see the form fields. But when loading with ajax from react I get a 500 with "is not JSON serializable error" above. The call is made from React.component constructor like bellow. I don't say it would display the field correctly, so far mostly I tried to print the response in to console and see what error that throws, but it dosn't get that far:

loadUserDetail() {
this.serverRequest = $.get("myUrl", function (result) {
console.log(result);
this.setState({
username: result.name_or_event,
email: result.email
});
}.bind(this));
}


Any other ideas how to do this? I am completely wrong with my approach, right? :-)

Answer

In my opinion mixing the django-generated forms and React is going to be a mess. A much cleaner approach would be to let React handle the frontend side and use Django to just expose a JSON api. There is no way to render the form server side and then let React "pick up" from there, unless you use Nodejs and React on the server too (React supports server side rendering).

The problem you have with your Python code is that DRF serialisers are supposed to read input sent to the server and to serialise data you want to send as a response. The ModelSerializer knows how to json-encode Django models, in your code you're trying to JSON-encode a serializer object, which doesn't work as there's no magic way to turn that object into json.

I understand you don't want to duplicate your form definitions and options, but you can just easily tell React the options/choices you need to use in the form. Normally you can achieve that by rendering a script tag in the template where you pass any initial data as JSON and you read that from the Js side.

class TestView(RegisterView):

    permission_classes = (AllowAny,)
    allowed_methods = ('GET', )


    def get(self, *args, **kwargs):
        initial_data = {'gender_options': [...]}  # anything you need to render the form, must be json-serialisable.
        return Response({'initial_data': json.dumps(initial_data)}, status=status.HTTP_200_OK)

Then in the Django template you render (before you actually loads the js app files):

<script>var INITIAL_DATA = {{ initial_data|escapejs }};</script>

Be careful about escapejs, that can be a security issue if you are not absolutely sure initial_data contains only trusted data.

Then at this point you have INITIAL_DATA that is globally available to your js code, so you can base your React components on that.

You can still use the Django form definitions to perform server-side validation.

Comments