Django formset equivalent in angular.js

2019-05-28 01:04发布

问题:

Django has formsets, where multiple forms can be used in one big form. So let's say one can add in a e.g. library formset mulitple books (providing the author and title) using repetitions of the same book form.

How to achieve the same functionality with Angular.js and Django Rest Framework? I'm new to Angular.js and Django Rest Framework and need some guidance how to be able to dynamically add more forms(e.g. for a book) for a given model in one big form (e.g. my library) and save them in Django Backend.

回答1:

You can achieve this in 2 steps:

On Frontend

Create a <form> on your page that will structure the data entered by the user as you need. Inside that <form> element, you'll need to use the ngForm for multiple forms' validation to behave correctly (here is a nice explanation of how ngForm works). A hypothetical code snippet would look like:

<form name="libraryForm">
  <div ng-repeat="book in vm.newBooksToAdd">

    <!-- ngForm directive allows to create forms within the parent form -->
    <ng-form name="bookForm">
      <div>
        <label>Book title</label>
        <input ng-model="book.title" type="text" name="title" required>
      </div>
      <div>
        <label>Author</label>
        <input ng-model="book.author" type="text" name="author" required>
      </div>
    </ng-form>
  </div>
</form>

In your controller, you can initialize the list of books to add as vm.newBooksToAdd = []; and whenever you want to add a new form to your list of forms for new books, just vm.newBooksToAdd.push({}) an empty object. Thus, you will send to the backend an array of objects representing books you want to create.

On Backend

Now here you'll need to overwrite the .create() method of your view to allow creating many instances at once, because by default it expects a single object. Your view might look like this:

class LibraryViewSet(views.ModelViewSet):
    ...

    def create(self, request):
        serializer = self.get_serializer(data=request.data, many=True)  # notice the `many` keywork argument here
        serializer.is_valid(raise_exception=True)
        self.perform_create(serializer)
        return Response(serializer.data, status=status.HTTP_201_CREATED)

Note: If you would like to allow both a single instance creation and creation in bulk, you'll need to adjust your .create() method to check for the data type of request.data.

Note 2: There is a django-rest-framework-bulk library that achieves what you want on the backend, but I didn't try it, so cannot say anything bad or good about it.

Good luck!