diff --git a/biscuit/apps/exlibris/__init__.py b/biscuit/apps/exlibris/__init__.py
index caaacd4267c62fb008c4a399435a697ae212ef2a..d60bef7eb6ce08054d6d404700cad541b9c6fd94 100644
--- a/biscuit/apps/exlibris/__init__.py
+++ b/biscuit/apps/exlibris/__init__.py
@@ -1,11 +1,11 @@
 import pkg_resources
 
 try:
-    __version__ = pkg_resources.get_distribution('BiscuIT-App-Exlibris').version
+    __version__ = pkg_resources.get_distribution("BiscuIT-App-Exlibris").version
 except Exception:
-    __version__ = 'unknown'
+    __version__ = "unknown"
 
-default_app_config = 'biscuit.apps.exlibris.apps.ExlibrisConfig'
+default_app_config = "biscuit.apps.exlibris.apps.ExlibrisConfig"
 
 # Additional apps to add to BiscuIT's INSTALLED_APPS on loading
-INSTALLED_APPS = ['isbn_field']
+INSTALLED_APPS = ["isbn_field"]
diff --git a/biscuit/apps/exlibris/apps.py b/biscuit/apps/exlibris/apps.py
index 2c239bf646f0edc8a2dfe225c44bf7d1833b35a3..0f6da041e9932706cf739da36ea8843eea1c9669 100644
--- a/biscuit/apps/exlibris/apps.py
+++ b/biscuit/apps/exlibris/apps.py
@@ -2,5 +2,5 @@ from biscuit.core.util.apps import AppConfig
 
 
 class ExlibrisConfig(AppConfig):
-    name = 'biscuit.apps.exlibris'
-    verbose_name = 'BiscuIT - Exlibris (School book management)'
+    name = "biscuit.apps.exlibris"
+    verbose_name = "BiscuIT - Exlibris (School book management)"
diff --git a/biscuit/apps/exlibris/forms.py b/biscuit/apps/exlibris/forms.py
index 6665351f7e688ffeb4e1059b9a57ecf3f371e749..626624da0c48f794fe01e9e723b30cf9fb9ff83d 100644
--- a/biscuit/apps/exlibris/forms.py
+++ b/biscuit/apps/exlibris/forms.py
@@ -1,5 +1,6 @@
 from django import forms
 from django.utils.translation import ugettext_lazy as _
+
 from django_select2.forms import Select2Widget
 
 from biscuit.core.models import Person
@@ -10,47 +11,47 @@ from .models import Book, BookCopy
 class BookAddISBNForm(forms.ModelForm):
     class Meta:
         model = Book
-        fields = ['isbn']
+        fields = ["isbn"]
 
     def __init__(self, *args, **kwargs):
         super().__init__(*args, **kwargs)
 
-        self.fields['isbn'].widget.attrs.update({'autofocus': 'autofocus'})
+        self.fields["isbn"].widget.attrs.update({"autofocus": "autofocus"})
 
 
 class BookGetCopyForm(forms.ModelForm):
     class Meta:
         model = BookCopy
-        fields = ['barcode']
+        fields = ["barcode"]
 
     def __init__(self, *args, **kwargs):
         super().__init__(*args, **kwargs)
 
-        self.fields['barcode'].widget.attrs.update({'autofocus': 'autofocus'})
+        self.fields["barcode"].widget.attrs.update({"autofocus": "autofocus"})
 
 
 class BookEditForm(forms.ModelForm):
     class Meta:
         model = Book
-        fields = ['isbn', 'title', 'author',
-                  'publisher', 'year', 'edition', 'cover']
+        fields = ["isbn", "title", "author", "publisher", "year", "edition", "cover"]
 
 
 class BookCopyEditForm(forms.ModelForm):
     class Meta:
         model = BookCopy
-        fields = ['borrower', 'borrow_count',
-                  'condition', 'remarks', 'barcode']
+        fields = ["borrower", "borrow_count", "condition", "remarks", "barcode"]
 
     def __init__(self, *args, **kwargs):
         super().__init__(*args, **kwargs)
-        self.fields['borrower'].disabled = True
+        self.fields["borrower"].disabled = True
 
 
 class BookCopiesBulkAddForm(forms.Form):
-    count = forms.IntegerField(label=_('Number of copies'))
+    count = forms.IntegerField(label=_("Number of copies"))
 
 
 class PersonBorrowForm(forms.Form):
-    borrower = forms.ModelChoiceField(label=_('Person'), queryset=Person.objects.all(), widget=Select2Widget)
-    barcodes = forms.CharField(label=_('Barcodes'), widget=forms.Textarea)
+    borrower = forms.ModelChoiceField(
+        label=_("Person"), queryset=Person.objects.all(), widget=Select2Widget
+    )
+    barcodes = forms.CharField(label=_("Barcodes"), widget=forms.Textarea)
diff --git a/biscuit/apps/exlibris/menus.py b/biscuit/apps/exlibris/menus.py
index 142e3d76a0b48002bbc780ef2efc86679863ca92..568e7aabc2f032ff03abf06cd102457ed530f636 100644
--- a/biscuit/apps/exlibris/menus.py
+++ b/biscuit/apps/exlibris/menus.py
@@ -1,34 +1,37 @@
 from django.utils.translation import ugettext_lazy as _
 
 MENUS = {
-    'NAV_MENU_CORE': [
+    "NAV_MENU_CORE": [
         {
-            'name': _('Books'),
-            'url': '#',
-            'root': True,
-            'validators': ['menu_generator.validators.is_authenticated', 'biscuit.core.util.core_helpers.has_person'],
-            'submenu': [
+            "name": _("Books"),
+            "url": "#",
+            "root": True,
+            "validators": [
+                "menu_generator.validators.is_authenticated",
+                "biscuit.core.util.core_helpers.has_person",
+            ],
+            "submenu": [
                 {
-                    'name': _('List of books'),
-                    'url': 'books',
-                    'validators': ['menu_generator.validators.is_authenticated']
+                    "name": _("List of books"),
+                    "url": "books",
+                    "validators": ["menu_generator.validators.is_authenticated"],
                 },
                 {
-                    'name': _('Add book'),
-                    'url': 'add_book',
-                    'validators': ['menu_generator.validators.is_authenticated']
+                    "name": _("Add book"),
+                    "url": "add_book",
+                    "validators": ["menu_generator.validators.is_authenticated"],
                 },
                 {
-                    'name': _('Open copy'),
-                    'url': 'get_copy',
-                    'validators': ['menu_generator.validators.is_authenticated']
+                    "name": _("Open copy"),
+                    "url": "get_copy",
+                    "validators": ["menu_generator.validators.is_authenticated"],
                 },
                 {
-                    'name': _('Person borrowing'),
-                    'url': 'person_borrow',
-                    'validators': ['menu_generator.validators.is_authenticated']
-                }
-            ]
+                    "name": _("Person borrowing"),
+                    "url": "person_borrow",
+                    "validators": ["menu_generator.validators.is_authenticated"],
+                },
+            ],
         }
     ]
 }
diff --git a/biscuit/apps/exlibris/migrations/0001_initial.py b/biscuit/apps/exlibris/migrations/0001_initial.py
index 0ac8362600c039a823841f33a2d9f31b8e08e184..54ee6920330b38edad15981194b462f1611982fa 100644
--- a/biscuit/apps/exlibris/migrations/0001_initial.py
+++ b/biscuit/apps/exlibris/migrations/0001_initial.py
@@ -1,53 +1,165 @@
 # Generated by Django 2.2.5 on 2019-09-03 18:30
 
-import biscuit.core.util.core_helpers
-from django.db import migrations, models
 import django.db.models.deletion
+from django.db import migrations, models
+
 import isbn_field.fields
 import isbn_field.validators
 
+import biscuit.core.util.core_helpers
+
 
 class Migration(migrations.Migration):
 
     initial = True
 
     dependencies = [
-        ('core', '0001_initial'),
+        ("core", "0001_initial"),
     ]
 
     operations = [
         migrations.CreateModel(
-            name='Book',
+            name="Book",
             fields=[
-                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
-                ('title', models.CharField(max_length=50, verbose_name='Book title')),
-                ('author', models.CharField(blank=True, max_length=50, verbose_name='Author name')),
-                ('publisher', models.CharField(blank=True, max_length=50, verbose_name='Publishing company')),
-                ('edition', models.PositiveSmallIntegerField(blank=True, null=True, verbose_name='Number of edition')),
-                ('year', models.PositiveSmallIntegerField(blank=True, null=True, verbose_name='Publishing year')),
-                ('isbn', isbn_field.fields.ISBNField(max_length=28, unique=True, validators=[isbn_field.validators.ISBNValidator], verbose_name='ISBN number')),
-                ('cover', models.ImageField(blank=True, null=True, upload_to='', verbose_name='Photo of cover')),
-                ('school', models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='core.School')),
+                (
+                    "id",
+                    models.AutoField(
+                        auto_created=True,
+                        primary_key=True,
+                        serialize=False,
+                        verbose_name="ID",
+                    ),
+                ),
+                ("title", models.CharField(max_length=50, verbose_name="Book title")),
+                (
+                    "author",
+                    models.CharField(
+                        blank=True, max_length=50, verbose_name="Author name"
+                    ),
+                ),
+                (
+                    "publisher",
+                    models.CharField(
+                        blank=True, max_length=50, verbose_name="Publishing company"
+                    ),
+                ),
+                (
+                    "edition",
+                    models.PositiveSmallIntegerField(
+                        blank=True, null=True, verbose_name="Number of edition"
+                    ),
+                ),
+                (
+                    "year",
+                    models.PositiveSmallIntegerField(
+                        blank=True, null=True, verbose_name="Publishing year"
+                    ),
+                ),
+                (
+                    "isbn",
+                    isbn_field.fields.ISBNField(
+                        max_length=28,
+                        unique=True,
+                        validators=[isbn_field.validators.ISBNValidator],
+                        verbose_name="ISBN number",
+                    ),
+                ),
+                (
+                    "cover",
+                    models.ImageField(
+                        blank=True,
+                        null=True,
+                        upload_to="",
+                        verbose_name="Photo of cover",
+                    ),
+                ),
+                (
+                    "school",
+                    models.ForeignKey(
+                        default=1,
+                        on_delete=django.db.models.deletion.CASCADE,
+                        to="core.School",
+                    ),
+                ),
             ],
             options={
-                'ordering': ['title', 'year', 'edition'],
-                'unique_together': {('school', 'title', 'author', 'edition', 'year')},
+                "ordering": ["title", "year", "edition"],
+                "unique_together": {("school", "title", "author", "edition", "year")},
             },
         ),
         migrations.CreateModel(
-            name='BookCopy',
+            name="BookCopy",
             fields=[
-                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
-                ('copy_num', models.PositiveSmallIntegerField(blank=True, null=True, verbose_name='Current number of copy')),
-                ('borrow_count', models.PositiveSmallIntegerField(blank=True, null=True, verbose_name='Number of borrowings')),
-                ('condition', models.CharField(blank=True, choices=[('U', 'New, unused'), ('N', 'New, used'), ('S', 'Slightly worn'), ('H', 'Heavily worn')], max_length=1, verbose_name='Condition')),
-                ('remarks', models.CharField(blank=True, max_length=100, verbose_name='Remarks')),
-                ('barcode', models.CharField(max_length=20, unique=True, verbose_name='Barcode')),
-                ('book', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='copies', to='exlibris.Book')),
-                ('borrower', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='books', to='core.Person')),
+                (
+                    "id",
+                    models.AutoField(
+                        auto_created=True,
+                        primary_key=True,
+                        serialize=False,
+                        verbose_name="ID",
+                    ),
+                ),
+                (
+                    "copy_num",
+                    models.PositiveSmallIntegerField(
+                        blank=True, null=True, verbose_name="Current number of copy"
+                    ),
+                ),
+                (
+                    "borrow_count",
+                    models.PositiveSmallIntegerField(
+                        blank=True, null=True, verbose_name="Number of borrowings"
+                    ),
+                ),
+                (
+                    "condition",
+                    models.CharField(
+                        blank=True,
+                        choices=[
+                            ("U", "New, unused"),
+                            ("N", "New, used"),
+                            ("S", "Slightly worn"),
+                            ("H", "Heavily worn"),
+                        ],
+                        max_length=1,
+                        verbose_name="Condition",
+                    ),
+                ),
+                (
+                    "remarks",
+                    models.CharField(
+                        blank=True, max_length=100, verbose_name="Remarks"
+                    ),
+                ),
+                (
+                    "barcode",
+                    models.CharField(
+                        max_length=20, unique=True, verbose_name="Barcode"
+                    ),
+                ),
+                (
+                    "book",
+                    models.ForeignKey(
+                        blank=True,
+                        null=True,
+                        on_delete=django.db.models.deletion.CASCADE,
+                        related_name="copies",
+                        to="exlibris.Book",
+                    ),
+                ),
+                (
+                    "borrower",
+                    models.ForeignKey(
+                        blank=True,
+                        null=True,
+                        on_delete=django.db.models.deletion.CASCADE,
+                        related_name="books",
+                        to="core.Person",
+                    ),
+                ),
             ],
             options={
-                'ordering': ['book__title', 'book__year', 'book__edition', 'copy_num'],
+                "ordering": ["book__title", "book__year", "book__edition", "copy_num"],
             },
         ),
     ]
diff --git a/biscuit/apps/exlibris/migrations/0002_db_indexes.py b/biscuit/apps/exlibris/migrations/0002_db_indexes.py
index 81cac5b81d1092c5f30d76607b0a8b59be8943d1..c5d31ca3c5489ef7a3a4d8e58154172d5f9719fc 100644
--- a/biscuit/apps/exlibris/migrations/0002_db_indexes.py
+++ b/biscuit/apps/exlibris/migrations/0002_db_indexes.py
@@ -6,13 +6,15 @@ from django.db import migrations, models
 class Migration(migrations.Migration):
 
     dependencies = [
-        ('core', '0001_initial'),
-        ('exlibris', '0001_initial'),
+        ("core", "0001_initial"),
+        ("exlibris", "0001_initial"),
     ]
 
     operations = [
         migrations.AddIndex(
-            model_name='bookcopy',
-            index=models.Index(fields=['barcode'], name='exlibris_bo_co_barc_55ac33_idx'),
+            model_name="bookcopy",
+            index=models.Index(
+                fields=["barcode"], name="exlibris_bo_co_barc_55ac33_idx"
+            ),
         ),
     ]
diff --git a/biscuit/apps/exlibris/models.py b/biscuit/apps/exlibris/models.py
index 5ee717c707900da0da3c55a2ca3f5ca76b4f433a..713dd7f47ce93bcebd7c93a0f2153eff3e9631a5 100644
--- a/biscuit/apps/exlibris/models.py
+++ b/biscuit/apps/exlibris/models.py
@@ -7,24 +7,31 @@ from isbn_field import ISBNField
 class Book(models.Model):
     """A book that is available for borrowing by persons."""
 
-    title = models.CharField(verbose_name=_('Book title'), max_length=50)
-    author = models.CharField(verbose_name=_(
-        'Author name'), max_length=50, blank=True)
-    publisher = models.CharField(verbose_name=_(
-        'Publishing company'), max_length=50, blank=True)
+    title = models.CharField(verbose_name=_("Book title"), max_length=50)
+    author = models.CharField(verbose_name=_("Author name"), max_length=50, blank=True)
+    publisher = models.CharField(
+        verbose_name=_("Publishing company"), max_length=50, blank=True
+    )
 
     edition = models.PositiveSmallIntegerField(
-        verbose_name=_('Number of edition'), blank=True, null=True)
+        verbose_name=_("Number of edition"), blank=True, null=True
+    )
     year = models.PositiveSmallIntegerField(
-        verbose_name=_('Publishing year'), blank=True, null=True)
+        verbose_name=_("Publishing year"), blank=True, null=True
+    )
 
-    isbn = ISBNField(verbose_name=_('ISBN number'), unique=True)
+    isbn = ISBNField(verbose_name=_("ISBN number"), unique=True)
 
-    cover = models.ImageField(verbose_name=_(
-        'Photo of cover'), blank=True, null=True)
+    cover = models.ImageField(verbose_name=_("Photo of cover"), blank=True, null=True)
 
     def __str__(self) -> str:
-        return '%s (%s, %d. %d %d)' % (self.title, self.author, self.edition, _('edition'), self.year)
+        return "%s (%s, %d. %d %d)" % (
+            self.title,
+            self.author,
+            self.edition,
+            _("edition"),
+            self.year,
+        )
 
     def is_deleteable(self) -> bool:
         for book_copy in self.copies.all():
@@ -34,8 +41,8 @@ class Book(models.Model):
         return True
 
     class Meta:
-        unique_together = [['title', 'author', 'edition', 'year']]
-        ordering = ['title', 'year', 'edition']
+        unique_together = [["title", "author", "edition", "year"]]
+        ordering = ["title", "year", "edition"]
 
 
 class BookCopy(models.Model):
@@ -44,40 +51,52 @@ class BookCopy(models.Model):
     """
 
     CONDITION_CHOICES = [
-        ('U', _('New, unused')),
-        ('N', _('New, used')),
-        ('S', _('Slightly worn')),
-        ('H', _('Heavily worn'))
+        ("U", _("New, unused")),
+        ("N", _("New, used")),
+        ("S", _("Slightly worn")),
+        ("H", _("Heavily worn")),
     ]
 
     book = models.ForeignKey(
-        'Book', blank=True, null=True, on_delete=models.CASCADE, related_name='copies')
+        "Book", blank=True, null=True, on_delete=models.CASCADE, related_name="copies"
+    )
     borrower = models.ForeignKey(
-        'core.Person', blank=True, null=True, on_delete=models.CASCADE, related_name='books')
+        "core.Person",
+        blank=True,
+        null=True,
+        on_delete=models.CASCADE,
+        related_name="books",
+    )
 
     copy_num = models.PositiveSmallIntegerField(
-        verbose_name=_('Current number of copy'), blank=True, null=True)
+        verbose_name=_("Current number of copy"), blank=True, null=True
+    )
 
     borrow_count = models.PositiveSmallIntegerField(
-        verbose_name=_('Number of borrowings'), blank=True, null=True)
+        verbose_name=_("Number of borrowings"), blank=True, null=True
+    )
     condition = models.CharField(
-        verbose_name=_('Condition'), choices=CONDITION_CHOICES, max_length=1, blank=True)
-    remarks = models.CharField(
-        verbose_name=_('Remarks'), max_length=100, blank=True)
+        verbose_name=_("Condition"), choices=CONDITION_CHOICES, max_length=1, blank=True
+    )
+    remarks = models.CharField(verbose_name=_("Remarks"), max_length=100, blank=True)
 
-    barcode = models.CharField(verbose_name=_(
-        'Barcode'), max_length=20, unique=True)
+    barcode = models.CharField(verbose_name=_("Barcode"), max_length=20, unique=True)
 
     def save(self, *args, **kwargs) -> None:
         if not self.copy_num:
             if self.book.copies.exclude(copy_num__isnull=True).exists():
-                self.copy_num = self.book.copies.exclude(
-                    copy_num__isnull=True).order_by('copy_num').last().copy_num + 1
+                self.copy_num = (
+                    self.book.copies.exclude(copy_num__isnull=True)
+                    .order_by("copy_num")
+                    .last()
+                    .copy_num
+                    + 1
+                )
             else:
                 self.copy_num = 1
 
         if not self.barcode:
-            self.barcode = '%s-%s' % (self.book.isbn, self.copy_num)
+            self.barcode = "%s-%s" % (self.book.isbn, self.copy_num)
 
         super().save(*args, **kwargs)
 
@@ -85,5 +104,5 @@ class BookCopy(models.Model):
         return not self.borrow_count and not self.borrower
 
     class Meta:
-        ordering = ['book__title', 'book__year', 'book__edition', 'copy_num']
-        indexes = [models.Index(fields=['barcode'])]
+        ordering = ["book__title", "book__year", "book__edition", "copy_num"]
+        indexes = [models.Index(fields=["barcode"])]
diff --git a/biscuit/apps/exlibris/tables.py b/biscuit/apps/exlibris/tables.py
index 8baf6d26fd8175045769f9cabfc755bbb5a70981..1d6982e7589372942e3d073575ed20dcda944897 100644
--- a/biscuit/apps/exlibris/tables.py
+++ b/biscuit/apps/exlibris/tables.py
@@ -8,34 +8,48 @@ from django_tables2.utils import A
 class BooksTable(tables.Table):
     class Meta:
         attrs = {
-            'class': 'table table-striped table-bordered table-hover table-responsive-xl'}
-
-    isbn = tables.LinkColumn('book_by_id', args=[A('id')])
-
-    title = tables.LinkColumn('book_by_id', args=[A('id')], attrs={'td': {
-                              'data-poload': lambda record: reverse('book_card_by_id', kwargs={'id_': record.id})}})
+            "class": "table table-striped table-bordered table-hover table-responsive-xl"
+        }
+
+    isbn = tables.LinkColumn("book_by_id", args=[A("id")])
+
+    title = tables.LinkColumn(
+        "book_by_id",
+        args=[A("id")],
+        attrs={
+            "td": {
+                "data-poload": lambda record: reverse(
+                    "book_card_by_id", kwargs={"id_": record.id}
+                )
+            }
+        },
+    )
     author = tables.Column()
 
-    num_copies = tables.Column(verbose_name=_(
-        'Copies'), accessor='copies.count')
+    num_copies = tables.Column(verbose_name=_("Copies"), accessor="copies.count")
 
-    edit = tables.LinkColumn('edit_book_by_id', args=[
-                             A('id')], verbose_name='', text=_('Edit'))
-    delete = tables.LinkColumn('delete_book_by_id', args=[
-                               A('id')], verbose_name='', text=_('Delete'))
+    edit = tables.LinkColumn(
+        "edit_book_by_id", args=[A("id")], verbose_name="", text=_("Edit")
+    )
+    delete = tables.LinkColumn(
+        "delete_book_by_id", args=[A("id")], verbose_name="", text=_("Delete")
+    )
 
 
 class BookCopiesTable(tables.Table):
     class Meta:
         attrs = {
-            'class': 'table table-striped table-bordered table-hover table-responsive-xl'}
+            "class": "table table-striped table-bordered table-hover table-responsive-xl"
+        }
 
     copy_num = tables.Column()
     borrower = tables.Column()
     condition = tables.Column()
     borrow_count = tables.Column()
 
-    edit = tables.LinkColumn('edit_book_copy_by_id', args=[
-                             A('id')], verbose_name='', text=_('Edit'))
-    delete = tables.LinkColumn('delete_book_copy_by_id', args=[
-                               A('id')], verbose_name='', text=_('Delete'))
+    edit = tables.LinkColumn(
+        "edit_book_copy_by_id", args=[A("id")], verbose_name="", text=_("Edit")
+    )
+    delete = tables.LinkColumn(
+        "delete_book_copy_by_id", args=[A("id")], verbose_name="", text=_("Delete")
+    )
diff --git a/biscuit/apps/exlibris/urls.py b/biscuit/apps/exlibris/urls.py
index ec7ebd00f587dc82096b771b116597a6e1064601..97cc05b7f3b73c3ab2bc94c07d594f1b038f9260 100644
--- a/biscuit/apps/exlibris/urls.py
+++ b/biscuit/apps/exlibris/urls.py
@@ -2,27 +2,36 @@ from django.urls import path
 
 from . import views
 
-
 urlpatterns = [
-    path('book/<int:id_>', views.book,
-         {'template': 'full'}, name='book_by_id'),
-    path('book/<int:id_>/card', views.book,
-         {'template': 'card'}, name='book_card_by_id'),
-    path('book/<int:id_>/edit', views.edit_book, name='edit_book_by_id'),
-    path('book/<int:id_>/delete', views.delete_book, name='delete_book_by_id'),
-    path('book/get_copy', views.get_copy, name='get_copy'),
-    path('book/copy/<barcode>', views.book_copy,
-         {'template': 'full'}, name='book_copy_by_barcode'),
-    path('book/<int:id_>/copies/labels', views.book_copies_labels,
-         name='copies_labels_by_book_id'),
-    path('book/copy/<int:id_>/edit', views.edit_book_copy,
-         name='edit_book_copy_by_id'),
-    path('book/copy/<int:id_>/delete', views.delete_book_copy,
-         name='delete_book_copy_by_id'),
-    path('book/<int:id_>/copies/add', views.add_book_copies,
-         name='add_copies_by_book_id'),
-    path('book/add', views.add_book, name='add_book'),
-    path('book/isbn/<isbn>', views.edit_book, name='edit_book_by_isbn'),
-    path('books', views.books, name='books'),
-    path('books/borrowing/person', views.person_borrow, name='person_borrow')
+    path("book/<int:id_>", views.book, {"template": "full"}, name="book_by_id"),
+    path(
+        "book/<int:id_>/card", views.book, {"template": "card"}, name="book_card_by_id"
+    ),
+    path("book/<int:id_>/edit", views.edit_book, name="edit_book_by_id"),
+    path("book/<int:id_>/delete", views.delete_book, name="delete_book_by_id"),
+    path("book/get_copy", views.get_copy, name="get_copy"),
+    path(
+        "book/copy/<barcode>",
+        views.book_copy,
+        {"template": "full"},
+        name="book_copy_by_barcode",
+    ),
+    path(
+        "book/<int:id_>/copies/labels",
+        views.book_copies_labels,
+        name="copies_labels_by_book_id",
+    ),
+    path("book/copy/<int:id_>/edit", views.edit_book_copy, name="edit_book_copy_by_id"),
+    path(
+        "book/copy/<int:id_>/delete",
+        views.delete_book_copy,
+        name="delete_book_copy_by_id",
+    ),
+    path(
+        "book/<int:id_>/copies/add", views.add_book_copies, name="add_copies_by_book_id"
+    ),
+    path("book/add", views.add_book, name="add_book"),
+    path("book/isbn/<isbn>", views.edit_book, name="edit_book_by_isbn"),
+    path("books", views.books, name="books"),
+    path("books/borrowing/person", views.person_borrow, name="person_borrow"),
 ]
diff --git a/biscuit/apps/exlibris/util.py b/biscuit/apps/exlibris/util.py
index 645ad2f436b9c365560a8e5b323d264eba197850..6cd6db0cb09ef6b3f144c0a6deb57c963c39f774 100644
--- a/biscuit/apps/exlibris/util.py
+++ b/biscuit/apps/exlibris/util.py
@@ -6,24 +6,24 @@ import isbnlib
 def get_book_meta(isbn: str) -> Dict[str, str]:
     meta_result = {}
 
-    for provider in 'dnb', 'openl', 'goob':
+    for provider in "dnb", "openl", "goob":
         try:
             meta_result.update(isbnlib.meta(isbn, provider))
         except:
             pass
 
     meta_translated = {}
-    if 'Title' in meta_result:
-        meta_translated['title'] = meta_result['Title']
-    if 'Authors' in meta_result:
-        meta_translated['author'] = ', '.join(meta_result['Authors'])
-    if 'Publisher' in meta_result:
-        meta_translated['publisher'] = meta_result['Publisher']
-    if 'Year' in meta_result:
+    if "Title" in meta_result:
+        meta_translated["title"] = meta_result["Title"]
+    if "Authors" in meta_result:
+        meta_translated["author"] = ", ".join(meta_result["Authors"])
+    if "Publisher" in meta_result:
+        meta_translated["publisher"] = meta_result["Publisher"]
+    if "Year" in meta_result:
         try:
-            meta_translated['year'] = int(meta_result['Year'])
+            meta_translated["year"] = int(meta_result["Year"])
         except ValueError:
             pass
-    meta_translated['isbn'] = isbn
+    meta_translated["isbn"] = isbn
 
     return meta_translated
diff --git a/biscuit/apps/exlibris/views.py b/biscuit/apps/exlibris/views.py
index f223f2f44e755a08d0e6c30903b42675ddd4a29b..70350f4b2e4686134e03dfa2213bf23e683187bd 100644
--- a/biscuit/apps/exlibris/views.py
+++ b/biscuit/apps/exlibris/views.py
@@ -1,5 +1,5 @@
-from io import BytesIO
 import os
+from io import BytesIO
 from tempfile import TemporaryDirectory
 from typing import Optional
 
@@ -9,17 +9,24 @@ from django.shortcuts import get_object_or_404, redirect, render
 from django.utils.text import slugify
 from django.utils.translation import ugettext as _
 
-from django_tables2 import RequestConfig
 import labels
 import PIL
+from django_tables2 import RequestConfig
 from reportlab.graphics import barcode, shapes
 
 from biscuit.core.models import School
 from biscuit.core.util import messages
 
-from .forms import BookAddISBNForm, BookEditForm, BookCopiesBulkAddForm, BookCopyEditForm, BookGetCopyForm, PersonBorrowForm
+from .forms import (
+    BookAddISBNForm,
+    BookCopiesBulkAddForm,
+    BookCopyEditForm,
+    BookEditForm,
+    BookGetCopyForm,
+    PersonBorrowForm,
+)
 from .models import Book, BookCopy
-from .tables import BooksTable, BookCopiesTable
+from .tables import BookCopiesTable, BooksTable
 from .util import get_book_meta
 
 
@@ -33,9 +40,9 @@ def books(request: HttpRequest) -> HttpResponse:
     # Build table
     books_table = BooksTable(books)
     RequestConfig(request).configure(books_table)
-    context['books_table'] = books_table
+    context["books_table"] = books_table
 
-    return render(request, 'exlibris/books.html', context)
+    return render(request, "exlibris/books.html", context)
 
 
 @login_required
@@ -44,17 +51,21 @@ def add_book(request: HttpRequest) -> HttpResponse:
 
     book_add_isbn_form = BookAddISBNForm(request.POST or None)
 
-    if request.method == 'POST':
+    if request.method == "POST":
         if book_add_isbn_form.is_valid():
-            return redirect('edit_book_by_isbn', isbn=book_add_isbn_form.cleaned_data['isbn'])
+            return redirect(
+                "edit_book_by_isbn", isbn=book_add_isbn_form.cleaned_data["isbn"]
+            )
 
-    context['book_add_isbn_form'] = book_add_isbn_form
+    context["book_add_isbn_form"] = book_add_isbn_form
 
-    return render(request, 'exlibris/add_book.html', context)
+    return render(request, "exlibris/add_book.html", context)
 
 
 @login_required
-def edit_book(request: HttpRequest, id_: Optional[int] = None, isbn: Optional[str] = None) -> HttpResponse:
+def edit_book(
+    request: HttpRequest, id_: Optional[int] = None, isbn: Optional[str] = None
+) -> HttpResponse:
     context = {}
 
     if id_:
@@ -62,9 +73,10 @@ def edit_book(request: HttpRequest, id_: Optional[int] = None, isbn: Optional[st
 
         book = get_object_or_404(Book, pk=id_)
         book_edit_form = BookEditForm(
-            request.POST or None, request.FILES or None, instance=book)
+            request.POST or None, request.FILES or None, instance=book
+        )
 
-        context['book'] = book
+        context["book"] = book
     else:
         # If no id was passed, create a new book
 
@@ -73,24 +85,24 @@ def edit_book(request: HttpRequest, id_: Optional[int] = None, isbn: Optional[st
         initial = get_book_meta(isbn)
 
         if initial:
-            messages.info(request, _(
-                'Information found for this ISBN was pre-filled.'))
+            messages.info(request, _("Information found for this ISBN was pre-filled."))
         else:
-            messages.warning(request, _('No information found for this ISBN.'))
+            messages.warning(request, _("No information found for this ISBN."))
 
         book_edit_form = BookEditForm(
-            request.POST or None, request.FILES or None, initial=initial)
+            request.POST or None, request.FILES or None, initial=initial
+        )
 
-    if request.method == 'POST':
+    if request.method == "POST":
         if book_edit_form.is_valid():
             book_edit_form.save(commit=True)
 
-            messages.success(request, _('The book has been saved.'))
-            return redirect('books')
+            messages.success(request, _("The book has been saved."))
+            return redirect("books")
 
-    context['book_edit_form'] = book_edit_form
+    context["book_edit_form"] = book_edit_form
 
-    return render(request, 'exlibris/edit_book.html', context)
+    return render(request, "exlibris/edit_book.html", context)
 
 
 @login_required
@@ -100,12 +112,13 @@ def delete_book(request: HttpRequest, id_: int) -> HttpResponse:
 
     if book.is_deleteable():
         book.delete()
-        messages.success(request, _('Book %s has been deleted.') % title)
+        messages.success(request, _("Book %s has been deleted.") % title)
     else:
-        messages.error(request,
-                       _('Books with copies that have been borrowed cannot be deleted.'))
+        messages.error(
+            request, _("Books with copies that have been borrowed cannot be deleted.")
+        )
 
-    return redirect('books')
+    return redirect("books")
 
 
 @login_required
@@ -113,7 +126,7 @@ def book(request: HttpRequest, id_: int, template: str) -> HttpResponse:
     context = {}
 
     book = get_object_or_404(Book, pk=id_)
-    context['book'] = book
+    context["book"] = book
 
     # Get all copies
     copies = book.copies.all()
@@ -121,9 +134,9 @@ def book(request: HttpRequest, id_: int, template: str) -> HttpResponse:
     # Build table
     copies_table = BookCopiesTable(copies)
     RequestConfig(request).configure(copies_table)
-    context['copies_table'] = copies_table
+    context["copies_table"] = copies_table
 
-    return render(request, 'exlibris/book_%s.html' % template, context)
+    return render(request, "exlibris/book_%s.html" % template, context)
 
 
 @login_required
@@ -131,25 +144,28 @@ def add_book_copies(request: HttpRequest, id_: int) -> HttpResponse:
     context = {}
 
     book = get_object_or_404(Book, pk=id_)
-    context['book'] = book
+    context["book"] = book
 
     bulk_add_form = BookCopiesBulkAddForm(request.POST or None)
 
-    if request.method == 'POST':
+    if request.method == "POST":
         if bulk_add_form.is_valid():
-            new_copies = [BookCopy(book=book) for _ in range(
-                bulk_add_form.cleaned_data['count'])]
+            new_copies = [
+                BookCopy(book=book) for _ in range(bulk_add_form.cleaned_data["count"])
+            ]
             for new_copy in new_copies:
                 new_copy.save()
 
-            messages.success(request, _('%d copies have been created.') %
-                             bulk_add_form.cleaned_data['count'])
-            return redirect('book_by_id', id_=book.pk)
+            messages.success(
+                request,
+                _("%d copies have been created.") % bulk_add_form.cleaned_data["count"],
+            )
+            return redirect("book_by_id", id_=book.pk)
 
-    context['book'] = book
-    context['bulk_add_form'] = bulk_add_form
+    context["book"] = book
+    context["bulk_add_form"] = bulk_add_form
 
-    return render(request, 'exlibris/add_book_copies.html', context)
+    return render(request, "exlibris/add_book_copies.html", context)
 
 
 @login_required
@@ -157,21 +173,20 @@ def edit_book_copy(request: HttpRequest, id_: int) -> HttpResponse:
     context = {}
 
     book_copy = get_object_or_404(BookCopy, pk=id_)
-    book_copy_edit_form = BookCopyEditForm(
-        request.POST or None, instance=book_copy)
+    book_copy_edit_form = BookCopyEditForm(request.POST or None, instance=book_copy)
 
-    context['book_copy'] = book_copy
+    context["book_copy"] = book_copy
 
-    if request.method == 'POST':
+    if request.method == "POST":
         if book_copy_edit_form.is_valid():
             book_copy_edit_form.save(commit=True)
 
-            messages.success(request, _('The book copy has been saved.'))
-            return redirect('book_by_id', id_=book_copy.book.pk)
+            messages.success(request, _("The book copy has been saved."))
+            return redirect("book_by_id", id_=book_copy.book.pk)
 
-    context['book_copy_edit_form'] = book_copy_edit_form
+    context["book_copy_edit_form"] = book_copy_edit_form
 
-    return render(request, 'exlibris/edit_book_copy.html', context)
+    return render(request, "exlibris/edit_book_copy.html", context)
 
 
 @login_required
@@ -181,13 +196,13 @@ def delete_book_copy(request: HttpRequest, id_: int) -> HttpResponse:
 
     if book_copy.is_deleteable():
         book_copy.delete()
-        messages.success(request, _(
-            'Book copy of %s has been deleted.') % book.title)
+        messages.success(request, _("Book copy of %s has been deleted.") % book.title)
     else:
-        messages.error(request,
-                       _('Book copies that have been borrowed cannot be deleted.'))
+        messages.error(
+            request, _("Book copies that have been borrowed cannot be deleted.")
+        )
 
-    return redirect('book_by_id', id_=book.id)
+    return redirect("book_by_id", id_=book.id)
 
 
 @login_required
@@ -196,32 +211,46 @@ def book_copies_labels(request: HttpRequest, id_: int) -> HttpResponse:
     copies = book.copies.all()
 
     with TemporaryDirectory() as temp_dir:
+
         def draw_label(label, width, height, obj):
             title = shapes.String(0, height - 10, obj.book.title, fontSize=10)
             label.add(title)
 
             copy_desc = shapes.String(
-                0, height - 20, _('Copy number: %d') % obj.copy_num, fontSize=8)
+                0, height - 20, _("Copy number: %d") % obj.copy_num, fontSize=8
+            )
             label.add(copy_desc)
 
             barcode_raw = barcode.createBarcodeImageInMemory(
-                'Code128', value=obj.barcode, width=400, height=120)
+                "Code128", value=obj.barcode, width=400, height=120
+            )
             barcode_image = PIL.Image.open(BytesIO(barcode_raw))
             barcode_file = os.path.join(temp_dir, "%s.png" % obj.barcode)
-            barcode_image.save(barcode_file, 'png')
-            label.add(shapes.Image(0, 30, width, 30,
-                                   os.path.join(temp_dir, barcode_file)))
+            barcode_image.save(barcode_file, "png")
+            label.add(
+                shapes.Image(0, 30, width, 30, os.path.join(temp_dir, barcode_file))
+            )
 
-            school = shapes.String(
-                0, 8, School.objects.first().name, fontSize=10)
+            school = shapes.String(0, 8, School.objects.first().name, fontSize=10)
             label.add(school)
 
             bottom_line = shapes.String(
-                0, 0, 'BiscuIT, the Free School Information System', fontSize=6)
+                0, 0, "BiscuIT, the Free School Information System", fontSize=6
+            )
             label.add(bottom_line)
 
         specs = labels.Specification(
-            210, 297, 3, 7, 63, 40, left_padding=3, top_padding=3, bottom_padding=3, right_padding=3)
+            210,
+            297,
+            3,
+            7,
+            63,
+            40,
+            left_padding=3,
+            top_padding=3,
+            bottom_padding=3,
+            right_padding=3,
+        )
         sheet = labels.Sheet(specs, draw_label)
 
         sheet.add_labels(copies)
@@ -229,7 +258,7 @@ def book_copies_labels(request: HttpRequest, id_: int) -> HttpResponse:
         pdf_file = os.path.join(temp_dir, "label_%s.pdf" % slugify(book.title))
         sheet.save(pdf_file)
 
-        return FileResponse(open(pdf_file, 'rb'), as_attachment=True)
+        return FileResponse(open(pdf_file, "rb"), as_attachment=True)
 
 
 @login_required
@@ -238,13 +267,15 @@ def get_copy(request: HttpRequest) -> HttpResponse:
 
     book_copy_form = BookGetCopyForm(request.POST or None)
 
-    if request.method == 'POST':
+    if request.method == "POST":
         if book_copy_form.is_valid():
-            return redirect('book_copy_by_barcode', barcode=book_copy_form.cleaned_data['barcode'])
+            return redirect(
+                "book_copy_by_barcode", barcode=book_copy_form.cleaned_data["barcode"]
+            )
 
-    context['book_copy_form'] = book_copy_form
+    context["book_copy_form"] = book_copy_form
 
-    return render(request, 'exlibris/get_copy.html', context)
+    return render(request, "exlibris/get_copy.html", context)
 
 
 @login_required
@@ -252,9 +283,9 @@ def book_copy(request: HttpRequest, barcode: str, template: str) -> HttpResponse
     context = {}
 
     book_copy = get_object_or_404(BookCopy, barcode=barcode)
-    context['book_copy'] = book_copy
+    context["book_copy"] = book_copy
 
-    return render(request, 'exlibris/copy_%s.html' % template, context)
+    return render(request, "exlibris/copy_%s.html" % template, context)
 
 
 @login_required
@@ -263,27 +294,35 @@ def person_borrow(request: HttpRequest) -> HttpResponse:
 
     person_borrow_form = PersonBorrowForm(request.POST or None)
 
-    if request.method == 'POST':
+    if request.method == "POST":
         if person_borrow_form.is_valid():
-            person = person_borrow_form.cleaned_data['borrower']
+            person = person_borrow_form.cleaned_data["borrower"]
 
-            for barcode_line in person_borrow_form.cleaned_data['barcodes'].splitlines():
+            for barcode_line in person_borrow_form.cleaned_data[
+                "barcodes"
+            ].splitlines():
                 try:
                     book_copy = BookCopy.objects.get(barcode=barcode_line)
                 except BookCopy.DoesNotExist:
-                    messages.error(request, _('Barcode %(barcode)s is invalid.') %
-                                   {'barcode': barcode_line})
+                    messages.error(
+                        request,
+                        _("Barcode %(barcode)s is invalid.")
+                        % {"barcode": barcode_line},
+                    )
                     continue
 
                 book_copy.borrower = person
                 book_copy.borrow_count = book_copy.borrow_count + 1
                 book_copy.save()
 
-                messages.success(request, _('Book %(title)s borrowed to %(person)s.') %
-                                 {'title': book_copy.book.title, 'person': person})
+                messages.success(
+                    request,
+                    _("Book %(title)s borrowed to %(person)s.")
+                    % {"title": book_copy.book.title, "person": person},
+                )
 
             person_borrow_form = PersonBorrowForm()
 
-    context['person_borrow_form'] = person_borrow_form
+    context["person_borrow_form"] = person_borrow_form
 
-    return render(request, 'exlibris/person_borrow.html', context)
+    return render(request, "exlibris/person_borrow.html", context)