mirror of
				https://gitlab.crans.org/mediatek/med.git
				synced 2025-11-04 09:42:11 +01:00 
			
		
		
		
	Adapt media to ISBN
This commit is contained in:
		@@ -0,0 +1,5 @@
 | 
			
		||||
# -*- mode: python; coding: utf-8 -*-
 | 
			
		||||
# Copyright (C) 2017-2019 by BDE ENS Paris-Saclay
 | 
			
		||||
# SPDX-License-Identifier: GPL-3.0-or-later
 | 
			
		||||
 | 
			
		||||
default_app_config = 'logs.apps.LogsConfig'
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,7 @@
 | 
			
		||||
# -*- mode: python; coding: utf-8 -*-
 | 
			
		||||
# Copyright (C) 2017-2019 by BDE ENS Paris-Saclay
 | 
			
		||||
# SPDX-License-Identifier: GPL-3.0-or-later
 | 
			
		||||
 | 
			
		||||
from django.apps import AppConfig
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,5 @@
 | 
			
		||||
# -*- mode: python; coding: utf-8 -*-
 | 
			
		||||
# Copyright (C) 2017-2019 by BDE ENS Paris-Saclay
 | 
			
		||||
# SPDX-License-Identifier: GPL-3.0-or-later
 | 
			
		||||
 | 
			
		||||
default_app_config = 'media.apps.MediaConfig'
 | 
			
		||||
 
 | 
			
		||||
@@ -17,18 +17,21 @@ class AuteurAdmin(VersionAdmin):
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class MediaAdmin(VersionAdmin):
 | 
			
		||||
    list_display = ('titre', 'authors', 'cote')
 | 
			
		||||
    search_fields = ('titre', 'auteur__nom', 'cote')
 | 
			
		||||
    autocomplete_fields = ('auteur',)
 | 
			
		||||
    list_display = ('title', 'authors_list', 'side_title', 'isbn')
 | 
			
		||||
    search_fields = ('title', 'authors__nom', 'side_title', 'subtitle', 'isbn')
 | 
			
		||||
    autocomplete_fields = ('authors',)
 | 
			
		||||
    date_hierarchy = 'publish_date'
 | 
			
		||||
 | 
			
		||||
    def authors(self, obj):
 | 
			
		||||
        return ", ".join([a.nom for a in obj.auteur.all()])
 | 
			
		||||
    def authors_list(self, obj):
 | 
			
		||||
        return ", ".join([a.nom for a in obj.authors.all()])
 | 
			
		||||
 | 
			
		||||
    authors_list.short_description = _('authors')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class EmpruntAdmin(VersionAdmin):
 | 
			
		||||
    list_display = ('media', 'user', 'date_emprunt', 'date_rendu',
 | 
			
		||||
                    'permanencier_emprunt', 'permanencier_rendu_custom')
 | 
			
		||||
    search_fields = ('media__titre', 'media__cote', 'user__username',
 | 
			
		||||
    search_fields = ('media__title', 'media__side_title', 'user__username',
 | 
			
		||||
                     'date_emprunt', 'date_rendu')
 | 
			
		||||
    date_hierarchy = 'date_emprunt'
 | 
			
		||||
    autocomplete_fields = ('media', 'user', 'permanencier_emprunt',
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,7 @@
 | 
			
		||||
# -*- mode: python; coding: utf-8 -*-
 | 
			
		||||
# Copyright (C) 2017-2019 by BDE ENS Paris-Saclay
 | 
			
		||||
# SPDX-License-Identifier: GPL-3.0-or-later
 | 
			
		||||
 | 
			
		||||
from django.apps import AppConfig
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										55
									
								
								media/fields.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								media/fields.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,55 @@
 | 
			
		||||
# -*- mode: python; coding: utf-8 -*-
 | 
			
		||||
# Copyright (C) 2017-2019 by BDE ENS Paris-Saclay
 | 
			
		||||
# SPDX-License-Identifier: GPL-3.0-or-later
 | 
			
		||||
 | 
			
		||||
"""
 | 
			
		||||
Based on https://github.com/secnot/django-isbn-field
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
from django.core.validators import EMPTY_VALUES
 | 
			
		||||
from django.db.models import CharField
 | 
			
		||||
from django.utils.translation import gettext_lazy as _
 | 
			
		||||
 | 
			
		||||
from .validators import isbn_validator
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ISBNField(CharField):
 | 
			
		||||
    description = _("ISBN-10 or ISBN-13")
 | 
			
		||||
 | 
			
		||||
    def __init__(self, clean_isbn=True, *args, **kwargs):
 | 
			
		||||
        self.clean_isbn = clean_isbn
 | 
			
		||||
        kwargs['max_length'] = kwargs[
 | 
			
		||||
            'max_length'] if 'max_length' in kwargs else 28
 | 
			
		||||
        kwargs['verbose_name'] = kwargs[
 | 
			
		||||
            'verbose_name'] if 'verbose_name' in kwargs else u'ISBN'
 | 
			
		||||
        kwargs['validators'] = [isbn_validator]
 | 
			
		||||
        super(ISBNField, self).__init__(*args, **kwargs)
 | 
			
		||||
 | 
			
		||||
    def formfield(self, **kwargs):
 | 
			
		||||
        defaults = {
 | 
			
		||||
            'min_length': 10,
 | 
			
		||||
            'validators': [isbn_validator],
 | 
			
		||||
        }
 | 
			
		||||
        defaults.update(kwargs)
 | 
			
		||||
        return super(ISBNField, self).formfield(**defaults)
 | 
			
		||||
 | 
			
		||||
    def deconstruct(self):
 | 
			
		||||
        name, path, args, kwargs = super(ISBNField, self).deconstruct()
 | 
			
		||||
        # Only include clean_isbn in kwarg if it's not the default value
 | 
			
		||||
        if not self.clean_isbn:
 | 
			
		||||
            kwargs['clean_isbn'] = self.clean_isbn
 | 
			
		||||
        return name, path, args, kwargs
 | 
			
		||||
 | 
			
		||||
    def pre_save(self, model_instance, add):
 | 
			
		||||
        """
 | 
			
		||||
        Remove dashes, spaces, and convert isbn to uppercase before saving
 | 
			
		||||
        when clean_isbn is enabled
 | 
			
		||||
        """
 | 
			
		||||
        value = getattr(model_instance, self.attname)
 | 
			
		||||
        if self.clean_isbn and value not in EMPTY_VALUES:
 | 
			
		||||
            cleaned_isbn = value.replace(' ', '').replace('-', '').upper()
 | 
			
		||||
            setattr(model_instance, self.attname, cleaned_isbn)
 | 
			
		||||
        return super(ISBNField, self).pre_save(model_instance, add)
 | 
			
		||||
 | 
			
		||||
    def __unicode__(self):
 | 
			
		||||
        return self.value
 | 
			
		||||
							
								
								
									
										18
									
								
								media/migrations/0010_auto_20190811_0901.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								media/migrations/0010_auto_20190811_0901.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
			
		||||
# Generated by Django 2.2.4 on 2019-08-11 07:01
 | 
			
		||||
 | 
			
		||||
from django.db import migrations
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Migration(migrations.Migration):
 | 
			
		||||
 | 
			
		||||
    dependencies = [
 | 
			
		||||
        ('media', '0009_auto_20190802_1455'),
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    operations = [
 | 
			
		||||
        migrations.RenameField(
 | 
			
		||||
            model_name='media',
 | 
			
		||||
            old_name='titre',
 | 
			
		||||
            new_name='title',
 | 
			
		||||
        ),
 | 
			
		||||
    ]
 | 
			
		||||
							
								
								
									
										23
									
								
								media/migrations/0011_auto_20190811_0903.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								media/migrations/0011_auto_20190811_0903.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,23 @@
 | 
			
		||||
# Generated by Django 2.2.4 on 2019-08-11 07:03
 | 
			
		||||
 | 
			
		||||
from django.db import migrations, models
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Migration(migrations.Migration):
 | 
			
		||||
 | 
			
		||||
    dependencies = [
 | 
			
		||||
        ('media', '0010_auto_20190811_0901'),
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    operations = [
 | 
			
		||||
        migrations.AddField(
 | 
			
		||||
            model_name='media',
 | 
			
		||||
            name='subtitle',
 | 
			
		||||
            field=models.CharField(blank=True, max_length=255, null=True, verbose_name='subtitle'),
 | 
			
		||||
        ),
 | 
			
		||||
        migrations.AlterField(
 | 
			
		||||
            model_name='media',
 | 
			
		||||
            name='title',
 | 
			
		||||
            field=models.CharField(max_length=255, verbose_name='title'),
 | 
			
		||||
        ),
 | 
			
		||||
    ]
 | 
			
		||||
							
								
								
									
										18
									
								
								media/migrations/0012_media_external_url.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								media/migrations/0012_media_external_url.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
			
		||||
# Generated by Django 2.2.4 on 2019-08-11 07:05
 | 
			
		||||
 | 
			
		||||
from django.db import migrations, models
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Migration(migrations.Migration):
 | 
			
		||||
 | 
			
		||||
    dependencies = [
 | 
			
		||||
        ('media', '0011_auto_20190811_0903'),
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    operations = [
 | 
			
		||||
        migrations.AddField(
 | 
			
		||||
            model_name='media',
 | 
			
		||||
            name='external_url',
 | 
			
		||||
            field=models.URLField(blank=True, null=True, verbose_name='external URL'),
 | 
			
		||||
        ),
 | 
			
		||||
    ]
 | 
			
		||||
							
								
								
									
										18
									
								
								media/migrations/0013_auto_20190811_0907.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								media/migrations/0013_auto_20190811_0907.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
			
		||||
# Generated by Django 2.2.4 on 2019-08-11 07:07
 | 
			
		||||
 | 
			
		||||
from django.db import migrations
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Migration(migrations.Migration):
 | 
			
		||||
 | 
			
		||||
    dependencies = [
 | 
			
		||||
        ('media', '0012_media_external_url'),
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    operations = [
 | 
			
		||||
        migrations.RenameField(
 | 
			
		||||
            model_name='media',
 | 
			
		||||
            old_name='auteur',
 | 
			
		||||
            new_name='authors',
 | 
			
		||||
        ),
 | 
			
		||||
    ]
 | 
			
		||||
							
								
								
									
										23
									
								
								media/migrations/0014_auto_20190811_0908.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								media/migrations/0014_auto_20190811_0908.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,23 @@
 | 
			
		||||
# Generated by Django 2.2.4 on 2019-08-11 07:08
 | 
			
		||||
 | 
			
		||||
from django.db import migrations, models
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Migration(migrations.Migration):
 | 
			
		||||
 | 
			
		||||
    dependencies = [
 | 
			
		||||
        ('media', '0013_auto_20190811_0907'),
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    operations = [
 | 
			
		||||
        migrations.AddField(
 | 
			
		||||
            model_name='media',
 | 
			
		||||
            name='number_of_pages',
 | 
			
		||||
            field=models.PositiveIntegerField(blank=True, null=True, verbose_name='number of pages'),
 | 
			
		||||
        ),
 | 
			
		||||
        migrations.AlterField(
 | 
			
		||||
            model_name='media',
 | 
			
		||||
            name='authors',
 | 
			
		||||
            field=models.ManyToManyField(to='media.Auteur', verbose_name='authors'),
 | 
			
		||||
        ),
 | 
			
		||||
    ]
 | 
			
		||||
							
								
								
									
										18
									
								
								media/migrations/0015_media_publish_date.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								media/migrations/0015_media_publish_date.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
			
		||||
# Generated by Django 2.2.4 on 2019-08-11 07:09
 | 
			
		||||
 | 
			
		||||
from django.db import migrations, models
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Migration(migrations.Migration):
 | 
			
		||||
 | 
			
		||||
    dependencies = [
 | 
			
		||||
        ('media', '0014_auto_20190811_0908'),
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    operations = [
 | 
			
		||||
        migrations.AddField(
 | 
			
		||||
            model_name='media',
 | 
			
		||||
            name='publish_date',
 | 
			
		||||
            field=models.DateField(blank=True, null=True, verbose_name='publish date'),
 | 
			
		||||
        ),
 | 
			
		||||
    ]
 | 
			
		||||
							
								
								
									
										20
									
								
								media/migrations/0016_media_isbn.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								media/migrations/0016_media_isbn.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
			
		||||
# Generated by Django 2.2.4 on 2019-08-11 07:17
 | 
			
		||||
 | 
			
		||||
from django.db import migrations
 | 
			
		||||
import media.fields
 | 
			
		||||
import media.validators
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Migration(migrations.Migration):
 | 
			
		||||
 | 
			
		||||
    dependencies = [
 | 
			
		||||
        ('media', '0015_media_publish_date'),
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    operations = [
 | 
			
		||||
        migrations.AddField(
 | 
			
		||||
            model_name='media',
 | 
			
		||||
            name='isbn',
 | 
			
		||||
            field=media.fields.ISBNField(blank=True, max_length=28, null=True, validators=[media.validators.isbn_validator], verbose_name='ISBN'),
 | 
			
		||||
        ),
 | 
			
		||||
    ]
 | 
			
		||||
							
								
								
									
										20
									
								
								media/migrations/0017_auto_20190811_0918.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								media/migrations/0017_auto_20190811_0918.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
			
		||||
# Generated by Django 2.2.4 on 2019-08-11 07:18
 | 
			
		||||
 | 
			
		||||
from django.db import migrations
 | 
			
		||||
import media.fields
 | 
			
		||||
import media.validators
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Migration(migrations.Migration):
 | 
			
		||||
 | 
			
		||||
    dependencies = [
 | 
			
		||||
        ('media', '0016_media_isbn'),
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    operations = [
 | 
			
		||||
        migrations.AlterField(
 | 
			
		||||
            model_name='media',
 | 
			
		||||
            name='isbn',
 | 
			
		||||
            field=media.fields.ISBNField(blank=True, help_text='You may be able to scan it from a bar code.', max_length=28, null=True, validators=[media.validators.isbn_validator], verbose_name='ISBN'),
 | 
			
		||||
        ),
 | 
			
		||||
    ]
 | 
			
		||||
							
								
								
									
										18
									
								
								media/migrations/0018_auto_20190811_0918.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								media/migrations/0018_auto_20190811_0918.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
			
		||||
# Generated by Django 2.2.4 on 2019-08-11 07:18
 | 
			
		||||
 | 
			
		||||
from django.db import migrations
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Migration(migrations.Migration):
 | 
			
		||||
 | 
			
		||||
    dependencies = [
 | 
			
		||||
        ('media', '0017_auto_20190811_0918'),
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    operations = [
 | 
			
		||||
        migrations.RenameField(
 | 
			
		||||
            model_name='media',
 | 
			
		||||
            old_name='cote',
 | 
			
		||||
            new_name='side_title',
 | 
			
		||||
        ),
 | 
			
		||||
    ]
 | 
			
		||||
							
								
								
									
										18
									
								
								media/migrations/0019_auto_20190811_0919.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								media/migrations/0019_auto_20190811_0919.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
			
		||||
# Generated by Django 2.2.4 on 2019-08-11 07:19
 | 
			
		||||
 | 
			
		||||
from django.db import migrations, models
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Migration(migrations.Migration):
 | 
			
		||||
 | 
			
		||||
    dependencies = [
 | 
			
		||||
        ('media', '0018_auto_20190811_0918'),
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    operations = [
 | 
			
		||||
        migrations.AlterField(
 | 
			
		||||
            model_name='media',
 | 
			
		||||
            name='side_title',
 | 
			
		||||
            field=models.CharField(max_length=255, verbose_name='side title'),
 | 
			
		||||
        ),
 | 
			
		||||
    ]
 | 
			
		||||
@@ -6,6 +6,8 @@ from django.core.validators import MinValueValidator
 | 
			
		||||
from django.db import models
 | 
			
		||||
from django.utils.translation import gettext_lazy as _
 | 
			
		||||
 | 
			
		||||
from .fields import ISBNField
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Auteur(models.Model):
 | 
			
		||||
    nom = models.CharField(max_length=255, unique=True)
 | 
			
		||||
@@ -19,12 +21,48 @@ class Auteur(models.Model):
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Media(models.Model):
 | 
			
		||||
    titre = models.CharField(max_length=255)
 | 
			
		||||
    cote = models.CharField(max_length=31)
 | 
			
		||||
    auteur = models.ManyToManyField('Auteur')
 | 
			
		||||
    isbn = ISBNField(
 | 
			
		||||
        _('ISBN'),
 | 
			
		||||
        help_text=_('You may be able to scan it from a bar code.'),
 | 
			
		||||
        blank=True,
 | 
			
		||||
        null=True,
 | 
			
		||||
    )
 | 
			
		||||
    title = models.CharField(
 | 
			
		||||
        verbose_name=_('title'),
 | 
			
		||||
        max_length=255,
 | 
			
		||||
    )
 | 
			
		||||
    subtitle = models.CharField(
 | 
			
		||||
        verbose_name=_('subtitle'),
 | 
			
		||||
        max_length=255,
 | 
			
		||||
        blank=True,
 | 
			
		||||
        null=True,
 | 
			
		||||
    )
 | 
			
		||||
    external_url = models.URLField(
 | 
			
		||||
        verbose_name=_('external URL'),
 | 
			
		||||
        blank=True,
 | 
			
		||||
        null=True,
 | 
			
		||||
    )
 | 
			
		||||
    side_title = models.CharField(
 | 
			
		||||
        verbose_name=_('side title'),
 | 
			
		||||
        max_length=255,
 | 
			
		||||
    )
 | 
			
		||||
    authors = models.ManyToManyField(
 | 
			
		||||
        'Auteur',
 | 
			
		||||
        verbose_name=_('authors'),
 | 
			
		||||
    )
 | 
			
		||||
    number_of_pages = models.PositiveIntegerField(
 | 
			
		||||
        verbose_name=_('number of pages'),
 | 
			
		||||
        blank=True,
 | 
			
		||||
        null=True,
 | 
			
		||||
    )
 | 
			
		||||
    publish_date = models.DateField(
 | 
			
		||||
        verbose_name=_('publish date'),
 | 
			
		||||
        blank=True,
 | 
			
		||||
        null=True,
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    def __str__(self):
 | 
			
		||||
        return str(self.titre) + ' - ' + str(self.auteur.all().first())
 | 
			
		||||
        return str(self.title) + ' - ' + str(self.authors.all().first())
 | 
			
		||||
 | 
			
		||||
    class Meta:
 | 
			
		||||
        verbose_name = _("medium")
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										46
									
								
								media/static/media/isbn_fetcher.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								media/static/media/isbn_fetcher.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,46 @@
 | 
			
		||||
// curl 'https://openlibrary.org/api/books?bibkeys=ISBN:0201558025&format=json&jscmd=data'
 | 
			
		||||
a = {
 | 
			
		||||
    "ISBN:0201558025": {
 | 
			
		||||
        "publishers": [{"name": "Addison-Wesley"}],
 | 
			
		||||
        "pagination": "xiii, 657 p. :",
 | 
			
		||||
        "identifiers": {
 | 
			
		||||
            "lccn": ["93040325"],
 | 
			
		||||
            "openlibrary": ["OL1429049M"],
 | 
			
		||||
            "isbn_10": ["0201558025"],
 | 
			
		||||
            "wikidata": ["Q15303722"],
 | 
			
		||||
            "goodreads": ["112243"],
 | 
			
		||||
            "librarything": ["45844"]
 | 
			
		||||
        },
 | 
			
		||||
        //"subtitle": "a foundation for computer science",
 | 
			
		||||
        //"title": "Concrete mathematics",
 | 
			
		||||
        //"url": "https://openlibrary.org/books/OL1429049M/Concrete_mathematics",
 | 
			
		||||
        "classifications": {"dewey_decimal_class": ["510"], "lc_classifications": ["QA39.2 .G733 1994"]},
 | 
			
		||||
        "notes": "Includes bibliographical references (p. 604-631) and index.",
 | 
			
		||||
        "number_of_pages": 657,
 | 
			
		||||
        "cover": {
 | 
			
		||||
            "small": "https://covers.openlibrary.org/b/id/135182-S.jpg",
 | 
			
		||||
            "large": "https://covers.openlibrary.org/b/id/135182-L.jpg",
 | 
			
		||||
            "medium": "https://covers.openlibrary.org/b/id/135182-M.jpg"
 | 
			
		||||
        },
 | 
			
		||||
        "subjects": [{
 | 
			
		||||
            "url": "https://openlibrary.org/subjects/computer_science",
 | 
			
		||||
            "name": "Computer science"
 | 
			
		||||
        }, {"url": "https://openlibrary.org/subjects/mathematics", "name": "Mathematics"}],
 | 
			
		||||
        "publish_date": "1994",
 | 
			
		||||
        "key": "/books/OL1429049M",
 | 
			
		||||
        "authors": [{
 | 
			
		||||
            "url": "https://openlibrary.org/authors/OL720958A/Ronald_L._Graham",
 | 
			
		||||
            "name": "Ronald L. Graham"
 | 
			
		||||
        }, {
 | 
			
		||||
            "url": "https://openlibrary.org/authors/OL229501A/Donald_Knuth",
 | 
			
		||||
            "name": "Donald Knuth"
 | 
			
		||||
        }, {"url": "https://openlibrary.org/authors/OL2669938A/Oren_Patashnik", "name": "Oren Patashnik"}],
 | 
			
		||||
        "by_statement": "Ronald L. Graham, Donald E. Knuth, Oren Patashnik.",
 | 
			
		||||
        "publish_places": [{"name": "Reading, Mass"}],
 | 
			
		||||
        "ebooks": [{
 | 
			
		||||
            "formats": {},
 | 
			
		||||
            "preview_url": "https://archive.org/details/concretemathemat00grah_444",
 | 
			
		||||
            "availability": "restricted"
 | 
			
		||||
        }]
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										31
									
								
								media/validators.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								media/validators.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,31 @@
 | 
			
		||||
# -*- mode: python; coding: utf-8 -*-
 | 
			
		||||
# Copyright (C) 2017-2019 by BDE ENS Paris-Saclay
 | 
			
		||||
# SPDX-License-Identifier: GPL-3.0-or-later
 | 
			
		||||
 | 
			
		||||
"""
 | 
			
		||||
Based on https://github.com/secnot/django-isbn-field
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
from django.core.exceptions import ValidationError
 | 
			
		||||
from django.utils.translation import ugettext_lazy as _
 | 
			
		||||
from six import string_types
 | 
			
		||||
from stdnum import isbn
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def isbn_validator(raw_isbn):
 | 
			
		||||
    """Check string is a valid ISBN number"""
 | 
			
		||||
    isbn_to_check = raw_isbn.replace('-', '').replace(' ', '')
 | 
			
		||||
 | 
			
		||||
    if not isinstance(isbn_to_check, string_types):
 | 
			
		||||
        raise ValidationError(_(u'Invalid ISBN: Not a string'))
 | 
			
		||||
 | 
			
		||||
    if len(isbn_to_check) != 10 and len(isbn_to_check) != 13:
 | 
			
		||||
        raise ValidationError(_(u'Invalid ISBN: Wrong length'))
 | 
			
		||||
 | 
			
		||||
    if not isbn.is_valid(isbn_to_check):
 | 
			
		||||
        raise ValidationError(_(u'Invalid ISBN: Failed checksum'))
 | 
			
		||||
 | 
			
		||||
    if isbn_to_check != isbn_to_check.upper():
 | 
			
		||||
        raise ValidationError(_(u'Invalid ISBN: Only upper case allowed'))
 | 
			
		||||
 | 
			
		||||
    return True
 | 
			
		||||
@@ -4,4 +4,5 @@ Pillow==5.4.1
 | 
			
		||||
pytz==2019.1
 | 
			
		||||
six==1.12.0
 | 
			
		||||
sqlparse==0.2.4
 | 
			
		||||
django-reversion==3.0.3
 | 
			
		||||
django-reversion==3.0.3
 | 
			
		||||
python-stdnum==1.10
 | 
			
		||||
		Reference in New Issue
	
	Block a user