From 968ebeb0b6397720a77b8f0634b62c94c6e96413 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniele=20Vigan=C3=B2?= Date: Mon, 2 Oct 2023 00:02:24 +0200 Subject: [PATCH] First bookshelf implementation --- ram/bookshelf/__init__.py | 0 ram/bookshelf/admin.py | 43 ++++++ ram/bookshelf/apps.py | 6 + ram/bookshelf/migrations/0001_initial.py | 119 +++++++++++++++ ...language_book_numbers_of_pages_and_more.py | 142 ++++++++++++++++++ ram/bookshelf/migrations/__init__.py | 0 ram/bookshelf/models.py | 80 ++++++++++ ram/bookshelf/tests.py | 3 + ram/bookshelf/views.py | 3 + ram/ram/__init__.py | 2 +- ram/ram/settings.py | 1 + 11 files changed, 398 insertions(+), 1 deletion(-) create mode 100644 ram/bookshelf/__init__.py create mode 100644 ram/bookshelf/admin.py create mode 100644 ram/bookshelf/apps.py create mode 100644 ram/bookshelf/migrations/0001_initial.py create mode 100644 ram/bookshelf/migrations/0002_book_language_book_numbers_of_pages_and_more.py create mode 100644 ram/bookshelf/migrations/__init__.py create mode 100644 ram/bookshelf/models.py create mode 100644 ram/bookshelf/tests.py create mode 100644 ram/bookshelf/views.py diff --git a/ram/bookshelf/__init__.py b/ram/bookshelf/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ram/bookshelf/admin.py b/ram/bookshelf/admin.py new file mode 100644 index 0000000..71deb73 --- /dev/null +++ b/ram/bookshelf/admin.py @@ -0,0 +1,43 @@ +from django.contrib import admin + +from bookshelf.models import BookProperty, Book, Author, Publisher + + +class BookPropertyInline(admin.TabularInline): + model = BookProperty + min_num = 0 + extra = 0 + + +@admin.register(Book) +class BookAdmin(admin.ModelAdmin): + inlines = (BookPropertyInline,) + list_display = ( + "title", + "get_authors", + "get_publisher", + "publication_year", + "numbers_of_pages" + ) + search_fields = ("title",) + list_filter = ("publisher__name",) + + @admin.display(description="Publisher") + def get_publisher(self, obj): + return obj.publisher.name + + @admin.display(description="Authors") + def get_authors(self, obj): + return ", ".join(a.short_name() for a in obj.authors.all()) + + +@admin.register(Author) +class AuthorAdmin(admin.ModelAdmin): + search_fields = ("first_name", "last_name",) + list_filter = ("last_name",) + + +@admin.register(Publisher) +class PublisherAdmin(admin.ModelAdmin): + list_display = ("name", "country") + search_fields = ("name",) diff --git a/ram/bookshelf/apps.py b/ram/bookshelf/apps.py new file mode 100644 index 0000000..49fa81a --- /dev/null +++ b/ram/bookshelf/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class BookshelfConfig(AppConfig): + default_auto_field = "django.db.models.BigAutoField" + name = "bookshelf" diff --git a/ram/bookshelf/migrations/0001_initial.py b/ram/bookshelf/migrations/0001_initial.py new file mode 100644 index 0000000..61c8b35 --- /dev/null +++ b/ram/bookshelf/migrations/0001_initial.py @@ -0,0 +1,119 @@ +# Generated by Django 4.2.5 on 2023-10-01 20:16 + +import ckeditor_uploader.fields +from django.db import migrations, models +import django.db.models.deletion +import uuid + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ("metadata", "0012_alter_decoder_manufacturer_decoderdocument"), + ] + + operations = [ + migrations.CreateModel( + name="Author", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("first_name", models.CharField(max_length=100)), + ("last_name", models.CharField(max_length=100)), + ], + ), + migrations.CreateModel( + name="Book", + fields=[ + ( + "uuid", + models.UUIDField( + default=uuid.uuid4, + editable=False, + primary_key=True, + serialize=False, + ), + ), + ("title", models.CharField(max_length=200)), + ("ISBN", models.CharField(max_length=13, unique=True)), + ("publication_year", models.SmallIntegerField(blank=True, null=True)), + ("purchase_date", models.DateField(blank=True, null=True)), + ("notes", ckeditor_uploader.fields.RichTextUploadingField(blank=True)), + ("creation_time", models.DateTimeField(auto_now_add=True)), + ("updated_time", models.DateTimeField(auto_now=True)), + ("authors", models.ManyToManyField(to="bookshelf.author")), + ], + ), + migrations.CreateModel( + name="Publisher", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("name", models.CharField(max_length=200)), + ("website", models.URLField()), + ], + ), + migrations.CreateModel( + name="BookProperty", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("value", models.CharField(max_length=256)), + ( + "book", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="property", + to="bookshelf.book", + ), + ), + ( + "property", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="metadata.property", + ), + ), + ], + options={ + "verbose_name_plural": "Properties", + }, + ), + migrations.AddField( + model_name="book", + name="publisher", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, to="bookshelf.publisher" + ), + ), + migrations.AddField( + model_name="book", + name="tags", + field=models.ManyToManyField( + blank=True, related_name="bookshelf", to="metadata.tag" + ), + ), + ] diff --git a/ram/bookshelf/migrations/0002_book_language_book_numbers_of_pages_and_more.py b/ram/bookshelf/migrations/0002_book_language_book_numbers_of_pages_and_more.py new file mode 100644 index 0000000..ed2fb25 --- /dev/null +++ b/ram/bookshelf/migrations/0002_book_language_book_numbers_of_pages_and_more.py @@ -0,0 +1,142 @@ +# Generated by Django 4.2.5 on 2023-10-01 21:33 + +from django.db import migrations, models +import django_countries.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ("bookshelf", "0001_initial"), + ] + + operations = [ + migrations.AddField( + model_name="book", + name="language", + field=models.CharField( + choices=[ + ("af", "Afrikaans"), + ("ar", "Arabic"), + ("ar-dz", "Algerian Arabic"), + ("ast", "Asturian"), + ("az", "Azerbaijani"), + ("bg", "Bulgarian"), + ("be", "Belarusian"), + ("bn", "Bengali"), + ("br", "Breton"), + ("bs", "Bosnian"), + ("ca", "Catalan"), + ("ckb", "Central Kurdish (Sorani)"), + ("cs", "Czech"), + ("cy", "Welsh"), + ("da", "Danish"), + ("de", "German"), + ("dsb", "Lower Sorbian"), + ("el", "Greek"), + ("en", "English"), + ("en-au", "Australian English"), + ("en-gb", "British English"), + ("eo", "Esperanto"), + ("es", "Spanish"), + ("es-ar", "Argentinian Spanish"), + ("es-co", "Colombian Spanish"), + ("es-mx", "Mexican Spanish"), + ("es-ni", "Nicaraguan Spanish"), + ("es-ve", "Venezuelan Spanish"), + ("et", "Estonian"), + ("eu", "Basque"), + ("fa", "Persian"), + ("fi", "Finnish"), + ("fr", "French"), + ("fy", "Frisian"), + ("ga", "Irish"), + ("gd", "Scottish Gaelic"), + ("gl", "Galician"), + ("he", "Hebrew"), + ("hi", "Hindi"), + ("hr", "Croatian"), + ("hsb", "Upper Sorbian"), + ("hu", "Hungarian"), + ("hy", "Armenian"), + ("ia", "Interlingua"), + ("id", "Indonesian"), + ("ig", "Igbo"), + ("io", "Ido"), + ("is", "Icelandic"), + ("it", "Italian"), + ("ja", "Japanese"), + ("ka", "Georgian"), + ("kab", "Kabyle"), + ("kk", "Kazakh"), + ("km", "Khmer"), + ("kn", "Kannada"), + ("ko", "Korean"), + ("ky", "Kyrgyz"), + ("lb", "Luxembourgish"), + ("lt", "Lithuanian"), + ("lv", "Latvian"), + ("mk", "Macedonian"), + ("ml", "Malayalam"), + ("mn", "Mongolian"), + ("mr", "Marathi"), + ("ms", "Malay"), + ("my", "Burmese"), + ("nb", "Norwegian Bokmål"), + ("ne", "Nepali"), + ("nl", "Dutch"), + ("nn", "Norwegian Nynorsk"), + ("os", "Ossetic"), + ("pa", "Punjabi"), + ("pl", "Polish"), + ("pt", "Portuguese"), + ("pt-br", "Brazilian Portuguese"), + ("ro", "Romanian"), + ("ru", "Russian"), + ("sk", "Slovak"), + ("sl", "Slovenian"), + ("sq", "Albanian"), + ("sr", "Serbian"), + ("sr-latn", "Serbian Latin"), + ("sv", "Swedish"), + ("sw", "Swahili"), + ("ta", "Tamil"), + ("te", "Telugu"), + ("tg", "Tajik"), + ("th", "Thai"), + ("tk", "Turkmen"), + ("tr", "Turkish"), + ("tt", "Tatar"), + ("udm", "Udmurt"), + ("uk", "Ukrainian"), + ("ur", "Urdu"), + ("uz", "Uzbek"), + ("vi", "Vietnamese"), + ("zh-hans", "Simplified Chinese"), + ("zh-hant", "Traditional Chinese"), + ], + default="en", + max_length=7, + ), + ), + migrations.AddField( + model_name="book", + name="numbers_of_pages", + field=models.SmallIntegerField(blank=True, null=True), + ), + migrations.AddField( + model_name="publisher", + name="country", + field=django_countries.fields.CountryField(blank=True, max_length=2), + ), + migrations.AlterField( + model_name="book", + name="ISBN", + field=models.CharField(blank=True, max_length=13), + ), + migrations.AlterField( + model_name="publisher", + name="website", + field=models.URLField(blank=True), + ), + ] diff --git a/ram/bookshelf/migrations/__init__.py b/ram/bookshelf/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ram/bookshelf/models.py b/ram/bookshelf/models.py new file mode 100644 index 0000000..d151fdf --- /dev/null +++ b/ram/bookshelf/models.py @@ -0,0 +1,80 @@ +from uuid import uuid4 +from django.db import models +from django.conf import settings +from django_countries.fields import CountryField + +from ckeditor_uploader.fields import RichTextUploadingField + +from metadata.models import ( + Property, + Tag, +) + + +class Publisher(models.Model): + name = models.CharField(max_length=200) + country = CountryField(blank=True) + website = models.URLField(blank=True) + + def __str__(self): + return self.name + + +class Author(models.Model): + first_name = models.CharField(max_length=100) + last_name = models.CharField(max_length=100) + + def __str__(self): + return f"{self.last_name}, {self.first_name}" + + def short_name(self): + return f"{self.last_name} {self.first_name[0]}." + + +class Book(models.Model): + uuid = models.UUIDField(primary_key=True, default=uuid4, editable=False) + title = models.CharField(max_length=200) + authors = models.ManyToManyField(Author) + publisher = models.ForeignKey(Publisher, on_delete=models.CASCADE) + ISBN = models.CharField(max_length=13, blank=True) + language = models.CharField( + max_length=7, + choices=settings.LANGUAGES, + default='en' + ) + numbers_of_pages = models.SmallIntegerField(null=True, blank=True) + publication_year = models.SmallIntegerField(null=True, blank=True) + purchase_date = models.DateField(null=True, blank=True) + tags = models.ManyToManyField( + Tag, related_name="bookshelf", blank=True + ) + notes = RichTextUploadingField(blank=True) + creation_time = models.DateTimeField(auto_now_add=True) + updated_time = models.DateTimeField(auto_now=True) + + def __str__(self): + return self.title + + def publisher_name(self): + return self.publisher.name + + # def get_absolute_url(self): + # return reverse("rolling_stock", kwargs={"uuid": self.uuid}) + + +class BookProperty(models.Model): + book = models.ForeignKey( + Book, + on_delete=models.CASCADE, + null=False, + blank=False, + related_name="property", + ) + property = models.ForeignKey(Property, on_delete=models.CASCADE) + value = models.CharField(max_length=256) + + def __str__(self): + return self.property.name + + class Meta: + verbose_name_plural = "Properties" diff --git a/ram/bookshelf/tests.py b/ram/bookshelf/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/ram/bookshelf/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/ram/bookshelf/views.py b/ram/bookshelf/views.py new file mode 100644 index 0000000..91ea44a --- /dev/null +++ b/ram/bookshelf/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here. diff --git a/ram/ram/__init__.py b/ram/ram/__init__.py index d83f9cb..6754000 100644 --- a/ram/ram/__init__.py +++ b/ram/ram/__init__.py @@ -1,4 +1,4 @@ from ram.utils import git_suffix -__version__ = "0.4.3" +__version__ = "0.5.0" __version__ += git_suffix(__file__) diff --git a/ram/ram/settings.py b/ram/ram/settings.py index de654ce..8d2c340 100644 --- a/ram/ram/settings.py +++ b/ram/ram/settings.py @@ -55,6 +55,7 @@ INSTALLED_APPS = [ "metadata", "roster", "consist", + "bookshelf", ] MIDDLEWARE = [