Django Models

Unicorn provides tight integration with Django Models and QuerySets to handle typical workflows.

Model

A Django Model can be used as a field on a component just like basic Python primitive types. Use unicorn:model to bind to a field of a Django Model like you would in a normal Django template.

Warning

Using this functionality will serialize your entire model by default and expose all of the values in the HTML source code. Do not use this particular functionality if there are properties that need to be kept private.

One option is to customize the serialization of the model into a dictionary to only expose the data that should be publicly available.

<!-- model.html -->
<div>
  <input unicorn:model.defer="book.title" type="text" id="book" />
  {{ book.title }}
  <button unicorn:click="save({{ book.pk }})">Save</button>
</div>
# model.py
from django_unicorn.components import UnicornView
from books.models import Book

class ModelView(UnicornView):
    book: Book = None

    def mount(self):
      self.book = Book.objects.all().first()

    def save(self, book_to_save: Book):
        book_to_save.save()

Note

The model’s pk will be used to look up the correct model if there is only one argument for an action method and it has a type annotation for a Django Model. To lookup by a different model field, pass a dictionary into the front-end.

<button unicorn:click="delete({ 'uuid': '{{ book.uuid }}'})">Delete by uuid</button>
def delete(self, book_to_delete: Book):
    book_to_delete.delete()

QuerySet

A Django QuerySet can be set to a property on a component just like a regular list.

<!-- queryset.html -->
<div>
    {% for book in books %}
    <div>
      <div>
        <input unicorn:model.defer="books.{{ forloop.counter0 }}.title" type="text" id="title" />
        {{ book.title }}
      </div>
      <div>
        <input unicorn:model.defer="books.{{ forloop.counter0 }}.description" type="text" id="description" />
        {{ book.description }}
      </div>
    </div>
    {% endfor %}

  </div>
  <button unicorn:click="save({{ forloop.counter0 }})">Save</button>
</div>
# queryset.py
from django_unicorn.components import UnicornView
from books.models import Book

class QuerysetView(UnicornView):
    books = Book.objects.none()

    def mount(self):
        self.books = Book.objects.all().order_by("-id")[:5]

    def save(self, book_idx: int):
        self.books[book_idx].save()

Warning

This will expose all of the model values for the QuerySet in the HTML source. One way to avoid leaking all model information is to pass the fields that are publicly viewable into values() on your QuerySet.

def mount(self):
  self.books = Book.objects.all().order_by("-id").values("pk", "title")[:5]

A QuerySetType type hint can also be used for QuerySet to ensure the correct type is used for the component field.

# queryset.py
from django_unicorn.components import QuerySetType, UnicornView
from books.models import Book

class QuerysetView(UnicornView):
    books: QuerySetType[Book] = None

    def mount(self):
        self.books = Book.objects.all().order_by("-id")[:5]

    def save(self, book_idx: int):
        self.books[book_idx].save()