+++ /dev/null
-# -*- coding: utf-8 -*-
-# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
-# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
-#
-import csv
-import sys
-from django.core.management.base import BaseCommand
-from django.utils.timezone import localtime
-
-from catalogue.models import Book
-from librarian import RDFNS, DCNS
-
-
-FORMATS = ('PDF', 'HTML', 'TXT', 'EPUB', 'MOBI')
-
-FORMATS_WITH_CHILDREN = ('PDF', 'EPUB', 'MOBI')
-
-
-PRODUCT_FORMS_1 = {
- 'HTML': 'EC',
- 'PDF': 'EB',
- 'TXT': 'EB',
- 'EPUB': 'ED',
- 'MOBI': 'ED',
-}
-
-PRODUCT_FORMS_2 = {
- 'HTML': 'E105',
- 'PDF': 'E107',
- 'TXT': 'E112',
- 'EPUB': 'E101',
- 'MOBI': 'E127',
-}
-
-
-def is_institution(name):
- return name.startswith(u'Zgromadzenie Ogólne')
-
-
-VOLUME_SEPARATORS = (u'. część ', u', część ', u', tom ', u'. der tragödie ')
-
-
-def get_volume(title):
- for volume_separator in VOLUME_SEPARATORS:
- if volume_separator in title.lower():
- vol_idx = title.lower().index(volume_separator)
- stripped = title[:vol_idx]
- vol_name = title[vol_idx + 2:]
- return stripped, vol_name
- return title, ''
-
-
-class Command(BaseCommand):
- @staticmethod
- def dc_values(desc, tag):
- return [e.text for e in desc.findall('.//' + DCNS(tag))]
-
- def handle(self, *args, **options):
- slugs = [line.strip() for line in sys.stdin]
- writer = csv.writer(sys.stdout)
- all_books = Book.objects.filter(slug__in=slugs)
- books_without_children = all_books.filter(children=None)
- for file_format in FORMATS:
- if file_format in FORMATS_WITH_CHILDREN:
- books = all_books
- else:
- books = books_without_children
- for book in books:
- desc = book.wldocument().edoc.find('.//' + RDFNS('Description'))
- imprint = '; '.join(self.dc_values(desc, 'publisher'))
- title, volume = get_volume(book.title)
- subtitle = ''
- year = ''
- publication_date = localtime(book.created_at).date().isoformat()
- info_date = publication_date
- author = '; '.join(author.strip() for author in self.dc_values(desc, 'creator'))
- author_person = author if not is_institution(author) else ''
- author_institution = author if is_institution(author) else ''
- publication_type = 'DGO'
- edition = '1'
- product_form1 = PRODUCT_FORMS_1[file_format]
- product_form2 = PRODUCT_FORMS_2[file_format]
- language = self.dc_values(desc, 'language')[0]
- row = [
- imprint,
- title,
- subtitle,
- year,
- volume,
- publication_date,
- info_date,
- author_person,
- author_institution,
- publication_type,
- edition,
- product_form1,
- product_form2,
- language,
- book.slug,
- file_format,
- ]
- writer.writerow([s.encode('utf-8') for s in row])
--- /dev/null
+# -*- coding: utf-8 -*-
+from urllib2 import urlopen
+
+from django import forms
+from django.utils.translation import ugettext_lazy as _
+from fnpdjango.utils.text.slughifi import slughifi
+
+from isbn.management.commands.import_onix import UNKNOWN
+from isbn.models import ONIXRecord, ISBNPool
+from isbn.utils import isbn_data, PRODUCT_FORMS, PRODUCT_FORM_DETAILS
+from librarian.parser import WLDocument
+
+
+class WLISBNForm(forms.Form):
+ platform_url = forms.URLField(label=u'Adres na platformie')
+ publishing_date = forms.DateField(label=u'Data publikacji')
+
+ def prepare_data(self):
+ platform_url = self.cleaned_data['platform_url']
+ platform_slug = platform_url.strip('/').split('/')[-1]
+ xml_url = 'https://redakcja.wolnelektury.pl/documents/book/%s/xml' % platform_slug
+ doc = WLDocument.from_file(urlopen(xml_url))
+ data = isbn_data(doc)
+ data['publishing_date'] = self.cleaned_data['publishing_date']
+ return data
+
+
+class WLConfirmForm(WLISBNForm):
+ platform_url = forms.URLField(widget=forms.HiddenInput)
+ publishing_date = forms.DateField(widget=forms.HiddenInput)
+
+ @staticmethod
+ def contributors(data):
+ person_name = data['name']
+ corporate_name = data['corporate_name']
+ if person_name:
+ # assuming that unknown can't be a co-author
+ if person_name == UNKNOWN:
+ return [{'role': 'A01', 'unnamed': '01'}]
+ else:
+ return [{'role': 'A01', 'name': name} for name in person_name.split('; ')]
+ if corporate_name:
+ return [{'role': 'A01', 'corporate_name': name} for name in corporate_name.split('; ')]
+
+ def save(self):
+ data = self.prepare_data()
+ for file_format in data['formats']:
+ data['product_form'] = PRODUCT_FORMS[file_format]
+ data['product_form_detail'] = PRODUCT_FORM_DETAILS[file_format]
+ data['contributors'] = self.contributors(data)
+ ONIXRecord.new_record(purpose=ISBNPool.PURPOSE_WL, data=data)
+ return data
+
+
+class FNPISBNForm(forms.Form):
+ FORMAT_CHOICES = (
+ ('HTML', 'HTML'),
+ ('PDF', 'PDF'),
+ ('EPUB', 'ePUB'),
+ ('MOBI', 'MOBI'),
+ ('TXT', 'TXT'),
+ ('SOFT', _('Soft cover book')),
+ )
+ LANGUAGE_CHOICES = (
+ ('pol', u'polski'),
+ ('eng', u'angielski'),
+ ('ger', u'niemiecki'),
+ ('fre', u'francuski'),
+ )
+
+ title = forms.CharField()
+ authors = forms.CharField(help_text=u'wartości oddzielone przecinkami lub „Wielu autorów”')
+ formats = forms.MultipleChoiceField(choices=FORMAT_CHOICES)
+ language = forms.ChoiceField(choices=LANGUAGE_CHOICES)
+ publishing_date = forms.DateField()
+
+ def prepare_author(self, name):
+ if name == u'Wielu autorów':
+ return {'role': 'A01', 'unnamed': '04'}
+ if ' ' in name:
+ first_name, last_name = [s.strip() for s in name.rsplit(' ', 1)]
+ output_name = '%s, %s' % (last_name, first_name)
+ else:
+ output_name = name.strip()
+ return {'role': 'A01', 'name': output_name}
+
+ def slug(self):
+ return slughifi('fnp %s %s' % (self.cleaned_data['authors'], self.cleaned_data['title']))
+
+ def save(self):
+ data = {
+ 'title': self.cleaned_data['title'],
+ 'language': self.cleaned_data['language'],
+ 'publishing_date': self.cleaned_data['publishing_date'],
+ 'contributors': [self.prepare_author(a) for a in self.cleaned_data['authors'].split(',')],
+ 'edition_type': 'NED',
+ 'imprint': 'Fundacja Nowoczesna Polska',
+ 'dc_slug': self.slug(),
+ }
+ formats = self.cleaned_data['formats']
+ for book_format in formats:
+ data['product_form'] = PRODUCT_FORMS[book_format]
+ if book_format in PRODUCT_FORM_DETAILS:
+ data['product_form_detail'] = PRODUCT_FORM_DETAILS[book_format]
+ else:
+ del data['product_form_detail']
+ ONIXRecord.new_record('FNP', data)
--- /dev/null
+# -*- coding: utf-8 -*-
+# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
+import csv
+import sys
+from django.core.management.base import BaseCommand
+from django.utils.timezone import localtime
+
+from catalogue.models import Book
+from isbn.utils import isbn_data, FORMATS, FORMATS_WITH_CHILDREN
+
+
+class Command(BaseCommand):
+
+ def handle(self, *args, **options):
+ slugs = [line.strip() for line in sys.stdin]
+ writer = csv.writer(sys.stdout)
+ all_books = Book.objects.filter(slug__in=slugs)
+ books_without_children = all_books.filter(children=None)
+ for file_format in FORMATS:
+ if file_format in FORMATS_WITH_CHILDREN:
+ books = all_books
+ else:
+ books = books_without_children
+ for book in books:
+ date = localtime(book.created_at).date().isoformat()
+ data = isbn_data(book.wldocument(), file_format)
+ row = [
+ data['imprint'],
+ data['title'],
+ data['subtitle'],
+ data['year'],
+ data['part_number'],
+ date,
+ date,
+ data['name'],
+ data['corporate_name'],
+ data['edition_type'],
+ data['edition_number'],
+ data['product_form'],
+ data['product_form_detail'],
+ data['language'],
+ book.slug,
+ file_format,
+ ]
+ writer.writerow([s.encode('utf-8') for s in row])
from django.core.management.base import BaseCommand
from isbn.models import ISBNPool, ONIXRecord
+from librarian import XMLNamespace
-ONIXNS = '{http://ns.editeur.org/onix/3.0/reference}'
+ONIXNS = XMLNamespace('http://ns.editeur.org/onix/3.0/reference')
DIRECT_FIELDS = {
'product_form': 'ProductForm',
'imprint': 'ImprintName',
}
-UNNAMED = u'Autor nieznany'
+UNKNOWN = u'Autor nieznany'
def parse_date(date_str):
def get_descendants(element, tags):
if isinstance(tags, basestring):
tags = [tags]
- return element.findall('.//' + '/'.join(ONIXNS + tag for tag in tags))
+ return element.findall('.//' + '/'.join(ONIXNS(tag) for tag in tags))
def get_field(element, tags, allow_multiple=False):
for key, value in data.iteritems():
if value:
contributor_data[key] = value
- if contributor_data.get('name') == UNNAMED:
+ if contributor_data.get('name') == UNKNOWN:
del contributor_data['name']
contributor_data['unnamed'] = '01'
for date_elem in get_descendants(contributor, 'ContributorDate'):
--- /dev/null
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('isbn', '0002_auto_20180213_1617'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='isbnpool',
+ name='purpose',
+ field=models.CharField(default='', max_length=4, choices=[(b'WL', b'Wolne Lektury'), (b'FNP', b'Fundacja Nowoczesna Polska')]),
+ preserve_default=False,
+ ),
+ ]
--- /dev/null
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('isbn', '0003_isbnpool_purpose'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='onixrecord',
+ name='dc_slug',
+ field=models.CharField(default=b'', max_length=256, db_index=True),
+ ),
+ migrations.AlterUniqueTogether(
+ name='onixrecord',
+ unique_together=set([('isbn_pool', 'suffix')]),
+ ),
+ ]
# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
#
from django.db import models
+from django.db.models import F
from jsonfield import JSONField
class ISBNPool(models.Model):
+ PURPOSE_WL = 'WL'
+ PURPOSE_FNP = 'FNP'
+ PURPOSE_CHOICES = (
+ (PURPOSE_WL, 'Wolne Lektury'),
+ (PURPOSE_FNP, 'Fundacja Nowoczesna Polska'),
+ )
+
prefix = models.CharField(max_length=10)
suffix_from = models.IntegerField()
suffix_to = models.IntegerField()
ref_from = models.IntegerField()
next_suffix = models.IntegerField()
+ purpose = models.CharField(max_length=4, choices=PURPOSE_CHOICES)
+
+ def __unicode__(self):
+ return self.prefix
+
+ @classmethod
+ def active_pool(cls, purpose):
+ pools = cls.objects.filter(purpose=purpose)
+ pools = pools.exclude(next_suffix__gt=F('suffix_to'))
+ if len(pools) == 1:
+ return pools.get()
+ else:
+ pools.exclude(next_suffix=F('suffix_from'))
+ return pools.get()
@staticmethod
def check_digit(prefix12):
digits = [int(d) for d in prefix12]
return str((-sum(digits[0::2]) + 7 * sum(digits[1::2])) % 10)
- def isbn(self, suffix):
+ def isbn(self, suffix, dashes=False):
prefix_length = len(self.prefix)
suffix_length = 12 - prefix_length
suffix_str = ('%%0%dd' % suffix_length) % suffix
prefix12 = self.prefix + suffix_str
- return prefix12 + self.check_digit(prefix12)
+ if dashes:
+ prefix12_final = '%s-%s-%s-%s-' % (self.prefix[:3], self.prefix[3:5], self.prefix[5:], suffix_str)
+ else:
+ prefix12_final = prefix12
+ return prefix12_final + self.check_digit(prefix12)
class ONIXRecord(models.Model):
language = models.CharField(max_length=4)
imprint = models.CharField(max_length=256)
publishing_date = models.DateField()
+ dc_slug = models.CharField(max_length=256, default='', db_index=True)
class Meta:
ordering = ['isbn_pool__id', 'suffix']
+ unique_together = ['isbn_pool', 'suffix']
+
+ @classmethod
+ def new_record(cls, purpose, data):
+ pool = ISBNPool.active_pool(purpose)
+ fields = {
+ 'isbn_pool': pool,
+ 'suffix': pool.next_suffix,
+ }
+ fields_to_copy = [
+ 'product_form',
+ 'product_form_detail',
+ 'title',
+ 'part_number',
+ 'contributors', # ???
+ 'edition_type',
+ 'edition_number',
+ 'language',
+ 'imprint',
+ 'publishing_date',
+ 'dc_slug',
+ ]
+ for field in fields_to_copy:
+ if field in data:
+ fields[field] = data[field]
+ cls.objects.create(**fields)
+ pool.next_suffix += 1
+ pool.save()
- def isbn(self):
- return self.isbn_pool.isbn(self.suffix)
+ def isbn(self, dashes=False):
+ return self.isbn_pool.isbn(self.suffix, dashes=dashes)
def reference(self):
return 'pl-eisbn-%s' % (self.isbn_pool.ref_from + self.suffix)
--- /dev/null
+{% extends "base/base.html" %}
+
+{% block title %}Dodaj ISBN{% endblock %}
+
+{% block body %}
+
+ <h1>Dodaj ISBN</h1>
+
+ <form method="post" class="submit-form" action="{{ next_view }}">
+ {% csrf_token %}
+ <table>
+ {{ form.as_table }}
+ <tr><td></td><td><button type="submit">Wyślij</button></td></tr>
+ </table>
+ </form>
+
+{% endblock %}
--- /dev/null
+{% extends "base/base.html" %}
+
+{% block title %}Przypisane ISBN{% endblock %}
+
+{% block body %}
+
+ <h1>Przypisane ISBN</h1>
+ <h2>{{ title }}</h2>
+ <dl>
+ {% for format, isbn in isbn_formats %}
+ <dt>{{ format }}</dt><dd>{{ isbn }}</dd>
+ {% endfor %}
+ </dl>
+{% endblock %}
--- /dev/null
+{% extends "base/base.html" %}
+
+{% block title %}Potwierdź dane{% endblock %}
+
+{% block body %}
+
+ <h1>Potwierdź dane</h1>
+
+ <form method="post" class="submit-form" action="{% url 'save_wl_onix' %}">
+ {% csrf_token %}
+ <table>
+ <tr><th>Formaty</th><td>{{ data.formats|join:", " }}</td></tr>
+ <tr><th>Tytuł</th><td>{{ data.title }}</td></tr>
+ {% if data.part_number %}<tr><th>Numer części</th><td>{{ data.part_number }}</td></tr>{% endif %}
+ {% if data.name %}<tr><th>Nazwa autora</th><td>{{ data.name }}</td></tr>{% endif %}
+ {% if data.corporate_name %}<tr><th>Nazwa instytucji</th><td>{{ data.corporate_name }}</td></tr>{% endif %}
+ <tr><th>Język</th><td>{{ data.language }}</td></tr>
+ <tr><th>Imprint</th><td>{{ data.imprint }}</td></tr>
+ <tr><th>Data publikacji</th><td>{{ form.publishing_date.value }}</td></tr>
+ {{ form.as_table }}
+ <tr><td></td><td><button type="submit">Zatwierdź</button></td></tr>
+ </table>
+ </form>
+
+{% endblock %}
--- /dev/null
+{% extends "base/base.html" %}
+
+{% block title %}Znaczniki ISBN{% endblock %}
+
+{% block body %}
+
+ <h1>Znaczniki ISBN</h1>
+ <h2>{{ title }}</h2>
+<code>{% for format, content_type, isbn in isbn_formats %}
+<dc:relation.hasFormat id="{{ format }}" xmlns:dc="http://purl.org/dc/elements/1.1/">https://wolnelektury.pl/{% if format == 'html' %}katalog/lektura{% else %}media/book/{{ format }}{% endif %}/{{ slug }}.{{ format }}</dc:relation.hasFormat><br>
+<meta refines="#{{ format }}" id="{{ format }}-id" property="dcterms:identifier">ISBN-{{ isbn }}</meta><br>
+<meta refines="#{{ format }}-id" property="identifier-type">ISBN</meta><br>
+ <meta refines="#{{ format }}" property="dcterms:format">{{ content_type }}</meta><br>{% endfor %}</code>
+{% endblock %}
\ No newline at end of file
--- /dev/null
+# -*- coding: utf-8 -*-
+from django.conf.urls import url
+from . import views
+
+urlpatterns = (
+ url(r'^dodaj/$', views.add_isbn_wl, name='add_isbn_wl'),
+ url(r'^potwierdzenie/$', views.confirm_isbn_wl, name='confirm_isbn_wl'),
+ url(r'^save-wl-onix/$', views.save_wl_onix, name='save_wl_onix'),
+ url(r'^tagi-isbn/(?P<slug>[a-z0-9-]*)/$', views.wl_dc_tags, name='wl_dc_tags'),
+
+ url(r'^dodaj-fnp/$', views.add_isbn_fnp, name='add_isbn_fnp'),
+ url(r'^przypisane/(?P<slug>[a-z0-9-]*)/$', views.assigned_isbn, name='assigned_isbn'),
+)
--- /dev/null
+# -*- coding: utf-8 -*-
+from librarian import RDFNS, DCNS
+
+FORMATS = ('PDF', 'HTML', 'TXT', 'EPUB', 'MOBI')
+
+FORMATS_WITH_CHILDREN = ('PDF', 'EPUB', 'MOBI')
+
+PRODUCT_FORMS = {
+ 'HTML': 'EC',
+ 'PDF': 'EB',
+ 'TXT': 'EB',
+ 'EPUB': 'ED',
+ 'MOBI': 'ED',
+ 'SOFT': 'BC',
+}
+
+PRODUCT_FORM_DETAILS = {
+ 'HTML': 'E105',
+ 'PDF': 'E107',
+ 'TXT': 'E112',
+ 'EPUB': 'E101',
+ 'MOBI': 'E127',
+}
+
+PRODUCT_FORMATS = {
+ 'E105': ('html', 'text/html'),
+ 'E107': ('pdf', 'application/pdf'),
+ 'E112': ('txt', 'text/plain'),
+ 'E101': ('epub', 'application/epub+zip'),
+ 'E127': ('mobi', 'application/x-mobipocket-ebook'),
+}
+
+VOLUME_SEPARATORS = (u'. część ', u', część ', u', tom ', u'. der tragödie ')
+
+
+def is_institution(name):
+ return name.startswith(u'Zgromadzenie Ogólne')
+
+
+def get_volume(title):
+ for volume_separator in VOLUME_SEPARATORS:
+ if volume_separator in title.lower():
+ vol_idx = title.lower().index(volume_separator)
+ stripped = title[:vol_idx]
+ vol_name = title[vol_idx + 2:]
+ return stripped, vol_name
+ return title, ''
+
+
+def dc_values(desc, tag):
+ return [e.text.strip() for e in desc.findall('.//' + DCNS(tag))]
+
+
+def isbn_data(wldoc, file_format=None):
+ desc = wldoc.edoc.find('.//' + RDFNS('Description'))
+ title, volume = get_volume(dc_values(desc, 'title')[0])
+ author = '; '.join(author.strip() for author in dc_values(desc, 'creator'))
+ data = {
+ 'imprint': '; '.join(dc_values(desc, 'publisher')),
+ 'title': title,
+ 'subtitle': '',
+ 'year': '',
+ 'part_number': volume,
+ 'name': author if not is_institution(author) else '',
+ 'corporate_name': author if is_institution(author) else '',
+ 'edition_type': 'DGO',
+ 'edition_number': '1',
+ 'language': dc_values(desc, 'language')[0],
+ 'dc_slug': wldoc.book_info.url.slug,
+ }
+ if file_format:
+ data['product_form'] = PRODUCT_FORMS[file_format]
+ data['product_form_detail'] = PRODUCT_FORM_DETAILS[file_format]
+ return data
+ else:
+ has_children = len(dc_values(desc, 'relation.hasPart')) > 0
+ data['formats'] = FORMATS_WITH_CHILDREN if has_children else FORMATS
+ return data
--- /dev/null
+# -*- coding: utf-8 -*-
+from django.contrib.auth.decorators import permission_required
+from django.core.urlresolvers import reverse
+from django.http.response import HttpResponseRedirect
+from django.shortcuts import render
+from django.views.decorators.http import require_POST
+
+from isbn.forms import WLISBNForm, WLConfirmForm, FNPISBNForm
+from isbn.models import ONIXRecord
+from isbn.utils import PRODUCT_FORMATS, PRODUCT_FORMS
+
+
+@permission_required('add_onixrecord')
+def add_isbn_wl(request):
+ form = WLISBNForm()
+ return render(request, 'isbn/add_isbn.html', {
+ 'form': form,
+ 'next_view': reverse('confirm_isbn_wl'),
+ })
+
+
+@require_POST
+@permission_required('add_onixrecord')
+def confirm_isbn_wl(request):
+ form = WLConfirmForm(data=request.POST)
+ if not form.is_valid():
+ # komunikat?
+ return HttpResponseRedirect(reverse('add_isbn_wl'))
+ data = form.prepare_data()
+ if ONIXRecord.objects.filter(dc_slug=data['dc_slug']).exists():
+ return HttpResponseRedirect(reverse('wl_dc_tags', kwargs={'slug': data['dc_slug']}))
+ return render(request, 'isbn/confirm_isbn_wl.html', {
+ 'data': data,
+ 'form': form,
+ })
+
+
+@require_POST
+@permission_required('add_onixrecord')
+def save_wl_onix(request):
+ form = WLConfirmForm(data=request.POST)
+ if not form.is_valid():
+ return HttpResponseRedirect(reverse('add_isbn_wl'))
+ data = form.save()
+ return HttpResponseRedirect(reverse('wl_dc_tags', kwargs={'slug': data['dc_slug']}))
+
+
+@permission_required('add_onixrecord')
+def wl_dc_tags(request, slug):
+ records = ONIXRecord.objects.filter(dc_slug=slug)
+ isbn_formats = []
+ for record in records:
+ file_format, content_type = PRODUCT_FORMATS[record.product_form_detail]
+ isbn_formats.append((file_format, content_type, record.isbn(dashes=True)))
+ return render(request, 'isbn/wl_dc_tags.html', {
+ 'slug': slug,
+ 'isbn_formats': isbn_formats,
+ 'title': records[0].title,
+ })
+
+
+@permission_required('add_onixrecord')
+def add_isbn_fnp(request):
+ if request.POST:
+ form = FNPISBNForm(data=request.POST)
+ if form.is_valid():
+ form.save()
+ return HttpResponseRedirect(reverse('assigned_isbn', kwargs={'slug': form.slug()}))
+ else:
+ form = FNPISBNForm()
+ return render(request, 'isbn/add_isbn.html', {
+ 'form': form,
+ 'next_view': '',
+ })
+
+
+def get_format(record):
+ if record.product_form_detail:
+ return PRODUCT_FORMATS[record.product_form_detail][0]
+ else:
+ return [key for key, value in PRODUCT_FORMS.iteritems() if value == record.product_form][0]
+
+
+@permission_required('add_onixrecord')
+def assigned_isbn(request, slug):
+ records = ONIXRecord.objects.filter(dc_slug=slug)
+ isbn_formats = [
+ (get_format(record), record.isbn(dashes=True)) for record in records]
+ return render(request, 'isbn/assigned_isbn.html', {
+ 'title': records[0].title,
+ 'isbn_formats': isbn_formats,
+ })
url(r'^sponsors/', include('sponsors.urls')),
url(r'^newsletter/', include('newsletter.urls')),
url(r'^formularz/', include('contact.urls')),
+ url(r'^isbn/', include('isbn.urls')),
# Admin panel
url(r'^admin/catalogue/book/import$', catalogue.views.import_book, name='import_book'),