Compare commits
No commits in common. "cfe706b1f54760ea16bc41c44780bf5728e52a13" and "c00b2b0e5265b487bc1bb18a07eabdd2aaf0df6f" have entirely different histories.
cfe706b1f5
...
c00b2b0e52
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -78,11 +78,11 @@ INSTALLED_APPS = [
|
|||||||
'django.contrib.messages',
|
'django.contrib.messages',
|
||||||
'django.contrib.staticfiles',
|
'django.contrib.staticfiles',
|
||||||
"library",
|
"library",
|
||||||
'debug_toolbar', # DEBUG purposes
|
# 'debug_toolbar', # DEBUG purposes
|
||||||
]
|
]
|
||||||
|
|
||||||
MIDDLEWARE = [
|
MIDDLEWARE = [
|
||||||
'debug_toolbar.middleware.DebugToolbarMiddleware', # DEBUG purposes
|
# 'debug_toolbar.middleware.DebugToolbarMiddleware', # DEBUG purposes
|
||||||
'django.middleware.security.SecurityMiddleware',
|
'django.middleware.security.SecurityMiddleware',
|
||||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||||
'django.middleware.common.CommonMiddleware',
|
'django.middleware.common.CommonMiddleware',
|
||||||
|
@ -30,8 +30,8 @@ urlpatterns = [
|
|||||||
] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
|
] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
|
||||||
|
|
||||||
|
|
||||||
if settings.DEBUG: # DEBUG purposes
|
# if settings.DEBUG: # DEBUG purposes
|
||||||
import debug_toolbar
|
# import debug_toolbar
|
||||||
urlpatterns = [
|
# urlpatterns = [
|
||||||
path('__debug__/', include(debug_toolbar.urls)),
|
# path('__debug__/', include(debug_toolbar.urls)),
|
||||||
] + urlpatterns
|
# ] + urlpatterns
|
||||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,107 +0,0 @@
|
|||||||
from sqlalchemy import create_engine
|
|
||||||
from sqlalchemy.ext.declarative import declarative_base
|
|
||||||
from sqlalchemy.orm import sessionmaker
|
|
||||||
engine = create_engine('sqlite:///C://Users//MassiveAtoms//Documents//Calibre Library//metadata.db.', echo=True)
|
|
||||||
Base = declarative_base(engine)
|
|
||||||
########################################################################
|
|
||||||
|
|
||||||
class Author(Base): # needed
|
|
||||||
""""""
|
|
||||||
__tablename__ = 'authors'
|
|
||||||
__table_args__ = {'autoload':True}
|
|
||||||
# has int id, text name, sort
|
|
||||||
|
|
||||||
class Comment(Base): # needed
|
|
||||||
""""""
|
|
||||||
__tablename__ = 'comments'
|
|
||||||
__table_args__ = {'autoload':True}
|
|
||||||
# has int id, int book, text text
|
|
||||||
|
|
||||||
# class Data(Base): # maybe
|
|
||||||
# """"""
|
|
||||||
# __tablename__ = 'data'
|
|
||||||
# __table_args__ = {'autoload':True}
|
|
||||||
# # has int id, int book, text format, text name
|
|
||||||
|
|
||||||
class Identifier(Base): # needed
|
|
||||||
""""""
|
|
||||||
__tablename__ = 'identifiers'
|
|
||||||
__table_args__ = {'autoload':True}
|
|
||||||
# has int id, int book, text value
|
|
||||||
|
|
||||||
class Publisher(Base): # needed
|
|
||||||
""""""
|
|
||||||
__tablename__ = 'publishers'
|
|
||||||
__table_args__ = {'autoload':True}
|
|
||||||
# has int id, text name
|
|
||||||
|
|
||||||
class Rating(Base): # needed
|
|
||||||
""""""
|
|
||||||
__tablename__ = 'ratings'
|
|
||||||
__table_args__ = {'autoload':True}
|
|
||||||
# has int id, int rating
|
|
||||||
|
|
||||||
class Series(Base): # needed
|
|
||||||
""""""
|
|
||||||
__tablename__ = 'series'
|
|
||||||
__table_args__ = {'autoload':True}
|
|
||||||
# has int id, text name
|
|
||||||
|
|
||||||
class Tag(Base): # needed
|
|
||||||
""""""
|
|
||||||
__tablename__ = 'tags'
|
|
||||||
__table_args__ = {'autoload':True}
|
|
||||||
# has int id, text name
|
|
||||||
|
|
||||||
class Book(Base): # needed
|
|
||||||
""""""
|
|
||||||
__tablename__ = 'books'
|
|
||||||
__table_args__ = {'autoload':True}
|
|
||||||
# has int id, text title, text sort, time timestamp, time pubdate,
|
|
||||||
# float series_index, text path
|
|
||||||
|
|
||||||
class Book_author_link(Base): # needed
|
|
||||||
""""""
|
|
||||||
__tablename__ = 'books_authors_link'
|
|
||||||
__table_args__ = {'autoload':True}
|
|
||||||
# has int id, id book, id author
|
|
||||||
|
|
||||||
class Book_publisher_link(Base): # needed
|
|
||||||
""""""
|
|
||||||
__tablename__ = 'books_publishers_link'
|
|
||||||
__table_args__ = {'autoload':True}
|
|
||||||
# has int id, id book, id publisher
|
|
||||||
|
|
||||||
class Book_rating_link(Base): # needed
|
|
||||||
""""""
|
|
||||||
__tablename__ = 'books_ratings_link'
|
|
||||||
__table_args__ = {'autoload':True}
|
|
||||||
# has int id, id book, id rating
|
|
||||||
|
|
||||||
class Book_series_link(Base): # needed
|
|
||||||
""""""
|
|
||||||
__tablename__ = 'books_series_link'
|
|
||||||
__table_args__ = {'autoload':True}
|
|
||||||
# has int id, id book, id series
|
|
||||||
|
|
||||||
class Book_tags_link(Base): # needed
|
|
||||||
""""""
|
|
||||||
__tablename__ = 'books_tags_link'
|
|
||||||
__table_args__ = {'autoload':True}
|
|
||||||
# has int id, id book, id tag
|
|
||||||
|
|
||||||
|
|
||||||
#----------------------------------------------------------------------
|
|
||||||
def loadSession():
|
|
||||||
""""""
|
|
||||||
metadata = Base.metadata
|
|
||||||
Session = sessionmaker(bind=engine)
|
|
||||||
session = Session()
|
|
||||||
return session
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
session = loadSession()
|
|
||||||
res = session.query(Book).all()
|
|
||||||
for i in res:
|
|
||||||
print(i.id, i.title, i.sort, i.timestamp, i.pubdate, i.series_index, i.path)
|
|
||||||
|
|
@ -1,22 +1,13 @@
|
|||||||
from .models import Author, Tag, Publisher, Language, Rating, Series
|
from .models import Author, Tag, Publisher, Language, Rating, Series
|
||||||
from django.db.models import Count
|
|
||||||
|
|
||||||
|
|
||||||
def filters(request):
|
def filters(request):
|
||||||
# unique_authors = Author.objects.all().order_by('sort')
|
unique_authors = Author.objects.all().order_by('sort')
|
||||||
# unique_tags = Tag.objects.all().order_by('name')
|
unique_tags = Tag.objects.all().order_by('name')
|
||||||
# unique_publishers = Publisher.objects.all().order_by('name')
|
unique_publishers = Publisher.objects.all().order_by('name')
|
||||||
# unique_ratings = Rating.objects.all().order_by('rating')
|
unique_languages = Language.objects.all()
|
||||||
# unique_languages = Language.objects.all()
|
unique_ratings = Rating.objects.all().order_by('rating')
|
||||||
# unique_series = Series.objects.all().order_by('sort')
|
unique_series = Series.objects.all().order_by('sort')
|
||||||
# unique_authors = Author.objects.annotate(num_books=Count('book')).order_by('sort')
|
|
||||||
unique_authors = Author.objects.only('name', "id").annotate(num_books=Count('book')).order_by('name')
|
|
||||||
unique_tags = Tag.objects.annotate(num_books=Count('book')).order_by('name')
|
|
||||||
unique_publishers = Publisher.objects.annotate(num_books=Count('book')).order_by('name')
|
|
||||||
unique_languages = Language.objects.annotate(num_books=Count('book')).order_by('rating')
|
|
||||||
unique_ratings = Rating.objects.annotate(num_books=Count('book'))
|
|
||||||
unique_series = Series.objects.annotate(num_books=Count('book')).order_by('sort')
|
|
||||||
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"unique_authors": unique_authors,
|
"unique_authors": unique_authors,
|
||||||
|
@ -1,221 +0,0 @@
|
|||||||
# Generated by Django 3.0.7 on 2020-07-11 16:22
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('library', '0001_initial'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='Author',
|
|
||||||
fields=[
|
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('name', models.TextField()),
|
|
||||||
('sort', models.TextField(blank=True, null=True)),
|
|
||||||
('link', models.TextField()),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'db_table': 'authors',
|
|
||||||
'managed': False,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='Book',
|
|
||||||
fields=[
|
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('title', models.TextField()),
|
|
||||||
('sort', models.TextField(blank=True, null=True)),
|
|
||||||
('timestamp', models.TextField(blank=True, null=True)),
|
|
||||||
('pubdate', models.TextField(blank=True, null=True)),
|
|
||||||
('series_index', models.FloatField()),
|
|
||||||
('author_sort', models.TextField(blank=True, null=True)),
|
|
||||||
('isbn', models.TextField(blank=True, null=True)),
|
|
||||||
('lccn', models.TextField(blank=True, null=True)),
|
|
||||||
('path', models.TextField()),
|
|
||||||
('flags', models.IntegerField()),
|
|
||||||
('uuid', models.TextField(blank=True, null=True)),
|
|
||||||
('has_cover', models.BooleanField(blank=True, null=True)),
|
|
||||||
('last_modified', models.TextField()),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'db_table': 'books',
|
|
||||||
'managed': False,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='BookAuthorLink',
|
|
||||||
fields=[
|
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'db_table': 'books_authors_link',
|
|
||||||
'managed': False,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='BookLanguageLink',
|
|
||||||
fields=[
|
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('item_order', models.IntegerField()),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'db_table': 'books_languages_link',
|
|
||||||
'managed': False,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='BookPublisherLink',
|
|
||||||
fields=[
|
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'db_table': 'books_publishers_link',
|
|
||||||
'managed': False,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='BookRatingLink',
|
|
||||||
fields=[
|
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'db_table': 'books_ratings_link',
|
|
||||||
'managed': False,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='BookSeriesLink',
|
|
||||||
fields=[
|
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'db_table': 'books_series_link',
|
|
||||||
'managed': False,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='BookTagLink',
|
|
||||||
fields=[
|
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'db_table': 'books_tags_link',
|
|
||||||
'managed': False,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='Comment',
|
|
||||||
fields=[
|
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('text', models.TextField()),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'db_table': 'comments',
|
|
||||||
'managed': False,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='Identifier',
|
|
||||||
fields=[
|
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('book', models.IntegerField()),
|
|
||||||
('type', models.TextField()),
|
|
||||||
('val', models.TextField()),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'db_table': 'identifiers',
|
|
||||||
'managed': False,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='Language',
|
|
||||||
fields=[
|
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('lang_code', models.TextField()),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'db_table': 'languages',
|
|
||||||
'managed': False,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='Publisher',
|
|
||||||
fields=[
|
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('name', models.TextField()),
|
|
||||||
('sort', models.TextField(blank=True, null=True)),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'db_table': 'publishers',
|
|
||||||
'managed': False,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='Rating',
|
|
||||||
fields=[
|
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('rating', models.IntegerField(blank=True, null=True)),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'db_table': 'ratings',
|
|
||||||
'managed': False,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='Tag',
|
|
||||||
fields=[
|
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('name', models.TextField()),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'db_table': 'tags',
|
|
||||||
'managed': False,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.DeleteModel(
|
|
||||||
name='Authors',
|
|
||||||
),
|
|
||||||
migrations.DeleteModel(
|
|
||||||
name='Books',
|
|
||||||
),
|
|
||||||
migrations.DeleteModel(
|
|
||||||
name='BooksAuthorsLink',
|
|
||||||
),
|
|
||||||
migrations.DeleteModel(
|
|
||||||
name='BooksLanguagesLink',
|
|
||||||
),
|
|
||||||
migrations.DeleteModel(
|
|
||||||
name='BooksPublishersLink',
|
|
||||||
),
|
|
||||||
migrations.DeleteModel(
|
|
||||||
name='BooksRatingsLink',
|
|
||||||
),
|
|
||||||
migrations.DeleteModel(
|
|
||||||
name='BooksSeriesLink',
|
|
||||||
),
|
|
||||||
migrations.DeleteModel(
|
|
||||||
name='BooksTagsLink',
|
|
||||||
),
|
|
||||||
migrations.DeleteModel(
|
|
||||||
name='Comments',
|
|
||||||
),
|
|
||||||
migrations.DeleteModel(
|
|
||||||
name='Identifiers',
|
|
||||||
),
|
|
||||||
migrations.DeleteModel(
|
|
||||||
name='Languages',
|
|
||||||
),
|
|
||||||
migrations.DeleteModel(
|
|
||||||
name='Publishers',
|
|
||||||
),
|
|
||||||
migrations.DeleteModel(
|
|
||||||
name='Ratings',
|
|
||||||
),
|
|
||||||
migrations.DeleteModel(
|
|
||||||
name='Tags',
|
|
||||||
),
|
|
||||||
]
|
|
Binary file not shown.
Binary file not shown.
@ -17,7 +17,7 @@ class Author(models.Model):
|
|||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
"""Returns the url to access a particular instance of MyModelName."""
|
"""Returns the url to access a particular instance of MyModelName."""
|
||||||
return reverse('author-detail-view', args=[str(self.id)])
|
return reverse('author-detail-view', args=[str(self.id)])
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
"""String for representing the MyModelName object (in Admin site etc.)."""
|
"""String for representing the MyModelName object (in Admin site etc.)."""
|
||||||
return self.name
|
return self.name
|
||||||
@ -27,11 +27,12 @@ class Author(models.Model):
|
|||||||
db_table = 'authors'
|
db_table = 'authors'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Comment(models.Model):
|
class Comment(models.Model):
|
||||||
book = models.ForeignKey("Book", db_column="book",
|
book = models.ForeignKey("Book", db_column="book", on_delete=models.CASCADE)
|
||||||
on_delete=models.CASCADE)
|
|
||||||
text = models.TextField()
|
text = models.TextField()
|
||||||
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
managed = False
|
managed = False
|
||||||
db_table = 'comments'
|
db_table = 'comments'
|
||||||
@ -40,6 +41,7 @@ class Comment(models.Model):
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Data(models.Model):
|
class Data(models.Model):
|
||||||
book = models.IntegerField()
|
book = models.IntegerField()
|
||||||
format = models.TextField()
|
format = models.TextField()
|
||||||
@ -59,7 +61,7 @@ class Identifier(models.Model):
|
|||||||
book = models.IntegerField()
|
book = models.IntegerField()
|
||||||
type = models.TextField()
|
type = models.TextField()
|
||||||
val = models.TextField()
|
val = models.TextField()
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
"""String for representing the MyModelName object (in Admin site etc.)."""
|
"""String for representing the MyModelName object (in Admin site etc.)."""
|
||||||
return self.val
|
return self.val
|
||||||
@ -75,7 +77,7 @@ class Language(models.Model):
|
|||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
"""Returns the url to access a particular instance of MyModelName."""
|
"""Returns the url to access a particular instance of MyModelName."""
|
||||||
return reverse('language-detail-view', args=[str(self.lang_code)])
|
return reverse('language-detail-view', args=[str(self.lang_code)])
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
"""String for representing the MyModelName object (in Admin site etc.)."""
|
"""String for representing the MyModelName object (in Admin site etc.)."""
|
||||||
return self.lang_code
|
return self.lang_code
|
||||||
@ -96,12 +98,12 @@ class Publisher(models.Model):
|
|||||||
through='BookPublisherLink',
|
through='BookPublisherLink',
|
||||||
through_fields=('publisher', 'book'),
|
through_fields=('publisher', 'book'),
|
||||||
related_name="released"
|
related_name="released"
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
"""Returns the url to access a particular instance of MyModelName."""
|
"""Returns the url to access a particular instance of MyModelName."""
|
||||||
return reverse('publisher-detail-view', args=[str(self.id)])
|
return reverse('publisher-detail-view', args=[str(self.id)])
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
"""String for representing the MyModelName object (in Admin site etc.)."""
|
"""String for representing the MyModelName object (in Admin site etc.)."""
|
||||||
return self.name
|
return self.name
|
||||||
@ -116,11 +118,10 @@ class Publisher(models.Model):
|
|||||||
|
|
||||||
class Rating(models.Model):
|
class Rating(models.Model):
|
||||||
rating = models.IntegerField(blank=True, null=True)
|
rating = models.IntegerField(blank=True, null=True)
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
"""Returns the url to access a particular instance of MyModelName."""
|
"""Returns the url to access a particular instance of MyModelName."""
|
||||||
return reverse('rating-detail-view', args=[str(self.id)])
|
return reverse('rating-detail-view', args=[str(self.id)])
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
"""String for representing the MyModelName object (in Admin site etc.)."""
|
"""String for representing the MyModelName object (in Admin site etc.)."""
|
||||||
return str(self.rating)
|
return str(self.rating)
|
||||||
@ -137,7 +138,7 @@ class Series(models.Model):
|
|||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
"""Returns the url to access a particular instance of MyModelName."""
|
"""Returns the url to access a particular instance of MyModelName."""
|
||||||
return reverse('series-detail-view', args=[str(self.id)])
|
return reverse('series-detail-view', args=[str(self.id)])
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
"""String for representing the MyModelName object (in Admin site etc.)."""
|
"""String for representing the MyModelName object (in Admin site etc.)."""
|
||||||
return self.name
|
return self.name
|
||||||
@ -152,11 +153,10 @@ class Series(models.Model):
|
|||||||
|
|
||||||
class Tag(models.Model):
|
class Tag(models.Model):
|
||||||
name = models.TextField()
|
name = models.TextField()
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
"""Returns the url to access a particular instance of MyModelName."""
|
"""Returns the url to access a particular instance of MyModelName."""
|
||||||
return reverse('tag-detail-view', args=[str(self.id)])
|
return reverse('tag-detail-view', args=[str(self.id)])
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
"""String for representing the MyModelName object (in Admin site etc.)."""
|
"""String for representing the MyModelName object (in Admin site etc.)."""
|
||||||
return self.name
|
return self.name
|
||||||
@ -193,28 +193,14 @@ class Book(models.Model):
|
|||||||
Language,
|
Language,
|
||||||
through='BookLanguageLink',
|
through='BookLanguageLink',
|
||||||
through_fields=('book', 'lang_code'))
|
through_fields=('book', 'lang_code'))
|
||||||
|
|
||||||
@property
|
|
||||||
def language(self):
|
|
||||||
return self.languages.first()
|
|
||||||
|
|
||||||
publishers = models.ManyToManyField(
|
publishers = models.ManyToManyField(
|
||||||
Publisher,
|
Publisher,
|
||||||
through='BookPublisherLink',
|
through='BookPublisherLink',
|
||||||
through_fields=('book', 'publisher'))
|
through_fields=('book', 'publisher'))
|
||||||
|
|
||||||
@property
|
|
||||||
def publisher(self):
|
|
||||||
return self.publishers.first()
|
|
||||||
|
|
||||||
series = models.ManyToManyField(
|
series = models.ManyToManyField(
|
||||||
Series,
|
Series,
|
||||||
through='BookSeriesLink',
|
through='BookSeriesLink',
|
||||||
through_fields=('book', 'series'))
|
through_fields=('book', 'series'))
|
||||||
|
|
||||||
@property
|
|
||||||
def serie(self):
|
|
||||||
return self.series.first()
|
|
||||||
tags = models.ManyToManyField(
|
tags = models.ManyToManyField(
|
||||||
Tag,
|
Tag,
|
||||||
through='BookTagLink',
|
through='BookTagLink',
|
||||||
@ -223,15 +209,10 @@ class Book(models.Model):
|
|||||||
Rating,
|
Rating,
|
||||||
through='BookRatingLink',
|
through='BookRatingLink',
|
||||||
through_fields=('book', 'rating'))
|
through_fields=('book', 'rating'))
|
||||||
|
|
||||||
@property
|
|
||||||
def rating(self):
|
|
||||||
return self.rating.first()
|
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
"""Returns the url to access a particular instance of MyModelName."""
|
"""Returns the url to access a particular instance of MyModelName."""
|
||||||
return reverse('book-detail-view', args=[str(self.id)])
|
return reverse('book-detail-view', args=[str(self.id)])
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
"""String for representing the MyModelName object (in Admin site etc.)."""
|
"""String for representing the MyModelName object (in Admin site etc.)."""
|
||||||
return self.title
|
return self.title
|
||||||
|
112
CalibreWebCompanion/library/static/css/styles.css
Normal file
112
CalibreWebCompanion/library/static/css/styles.css
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
/* sidenav */
|
||||||
|
|
||||||
|
|
||||||
|
/* Fixed sidenav, full height */
|
||||||
|
.sidenav {
|
||||||
|
height: 100%;
|
||||||
|
width: 200px;
|
||||||
|
position: fixed;
|
||||||
|
z-index: 1;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
background-color: #111;
|
||||||
|
overflow-x: hidden;
|
||||||
|
padding-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Style the sidenav links and the dropdown button */
|
||||||
|
.sidenav a,
|
||||||
|
.dropdown-btn {
|
||||||
|
padding: 6px 8px 6px 16px;
|
||||||
|
text-decoration: none;
|
||||||
|
font-size: 20px;
|
||||||
|
color: #818181;
|
||||||
|
display: block;
|
||||||
|
border: none;
|
||||||
|
background: none;
|
||||||
|
width: 100%;
|
||||||
|
text-align: left;
|
||||||
|
cursor: pointer;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* On mouse-over */
|
||||||
|
.sidenav a:hover,
|
||||||
|
.dropdown-btn:hover {
|
||||||
|
color: #f1f1f1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Main content */
|
||||||
|
.main {
|
||||||
|
margin-left: 200px;
|
||||||
|
/* Same as the width of the sidenav */
|
||||||
|
font-size: 20px;
|
||||||
|
/* Increased text to enable scrolling */
|
||||||
|
padding: 0px 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add an active class to the active dropdown button */
|
||||||
|
.active {
|
||||||
|
background-color: green;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Dropdown container (hidden by default). Optional: add a lighter background color and some left padding to change the design of the dropdown content */
|
||||||
|
.dropdown-container {
|
||||||
|
display: none;
|
||||||
|
background-color: #262626;
|
||||||
|
padding-left: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Optional: Style the caret down icon */
|
||||||
|
.fa-caret-down {
|
||||||
|
float: right;
|
||||||
|
padding-right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ul.topnav {
|
||||||
|
list-style-type: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
background-color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.topnav li {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.topnav li a {
|
||||||
|
display: block;
|
||||||
|
color: white;
|
||||||
|
text-align: center;
|
||||||
|
padding: 14px 16px;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.topnav li a:hover {
|
||||||
|
background-color: #111;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Table */
|
||||||
|
table {
|
||||||
|
border-spacing: 0;
|
||||||
|
width: 100%;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
th {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
th,
|
||||||
|
td {
|
||||||
|
text-align: left;
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr:nth-child(even) {
|
||||||
|
background-color: #f2f2f2
|
||||||
|
}
|
14
CalibreWebCompanion/library/static/js/nav.js
Normal file
14
CalibreWebCompanion/library/static/js/nav.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
var dropdown = document.getElementsByClassName("dropdown-btn");
|
||||||
|
var i;
|
||||||
|
|
||||||
|
for (i = 0; i < dropdown.length; i++) {
|
||||||
|
dropdown[i].addEventListener("click", function() {
|
||||||
|
this.classList.toggle("active");
|
||||||
|
var dropdownContent = this.nextElementSibling;
|
||||||
|
if (dropdownContent.style.display === "block") {
|
||||||
|
dropdownContent.style.display = "none";
|
||||||
|
} else {
|
||||||
|
dropdownContent.style.display = "block";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
@ -3,125 +3,98 @@
|
|||||||
|
|
||||||
<head>
|
<head>
|
||||||
{% block title %}<title>Local Library</title>{% endblock %}
|
{% block title %}<title>Local Library</title>{% endblock %}
|
||||||
|
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css"
|
||||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
|
integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
|
||||||
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
<!-- Add additional CSS in static file -->
|
||||||
<!-- Compiled and minified CSS -->
|
{% load static %}
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0-beta/css/materialize.min.css">
|
<link rel="stylesheet" href="{% static 'css/styles.css' %}">
|
||||||
<!-- Compiled and minified JavaScript -->
|
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0-beta/js/materialize.min.js"></script>
|
|
||||||
<style>
|
|
||||||
table {
|
|
||||||
width: 100%;
|
|
||||||
table-layout: fixed;
|
|
||||||
}
|
|
||||||
|
|
||||||
th {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.title {
|
|
||||||
width: 40%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.author {
|
|
||||||
width: 20%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.rating {
|
|
||||||
width: 5%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tags {
|
|
||||||
width: 15%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.added {
|
|
||||||
width: 20%;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
{% block topnav%}
|
||||||
|
<ul class="topnav">
|
||||||
|
|
||||||
<div class="navbar-fixed">
|
{% if user.is_authenticated %}
|
||||||
<nav>
|
<li class="active"><a href="{{user.get_absolute_url}}"> {{ user.get_username }}</a></li>
|
||||||
<div class="nav-wrapper row green darken-1">
|
<li><a href="{% url 'logout'%}?next={{request.path}}">Logout</a></li>
|
||||||
|
{% else %}
|
||||||
<ul class="right">
|
<li><a href="{% url 'sign-up'%}?next={{request.path}}">Sign up</a></li>
|
||||||
{% if user.is_authenticated %}
|
<li><a href="{% url 'login'%}?next={{request.path}}">Login</a></li>
|
||||||
<li class="active"><a href="{{user.get_absolute_url}}"> {{ user.get_username }}</a></li>
|
{% endif %}
|
||||||
<li><a href="{% url 'logout'%}?next={{request.path}}">Logout</a></li>
|
</ul>
|
||||||
</ul>
|
{% endblock %}
|
||||||
|
|
||||||
<ul class="left">
|
|
||||||
<li><a href="{% url 'search' %}">Search</a></li>
|
|
||||||
<li><a href="{% url 'books' %}">Books</a></li>
|
|
||||||
<li><a class="dropdown-trigger" href="#!" data-target="dropdown-authors">Authors<i
|
|
||||||
class="material-icons right">arrow_drop_down</i></a></li>
|
|
||||||
<li><a class="dropdown-trigger" href="#!" data-target="dropdown-ratings">Ratings<i
|
|
||||||
class="material-icons right">arrow_drop_down</i></a></li>
|
|
||||||
<li><a class="dropdown-trigger" href="#!" data-target="dropdown-tags">Tags<i
|
|
||||||
class="material-icons right">arrow_drop_down</i></a></li>
|
|
||||||
</ul>
|
|
||||||
<ul id="dropdown-authors" class="dropdown-content">
|
|
||||||
{% for author in unique_authors %}
|
|
||||||
<li><a href="{{author.get_absolute_url}}">{{author}}</a></li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
<ul id="dropdown-ratings" class="dropdown-content">
|
|
||||||
{% for rating in unique_ratings %}
|
|
||||||
<li><a href="{{rating.get_absolute_url}}">{{rating}}</a></li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
<ul id="dropdown-tags" class="dropdown-content">
|
|
||||||
{% for tag in unique_tags %}
|
|
||||||
<li><a href="{{tag.get_absolute_url}}">{{tag}}</a></li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
{% else %}
|
|
||||||
<li><a href="{% url 'sign-up'%}?next={{request.path}}">Sign up</a></li>
|
|
||||||
<li><a href="{% url 'login'%}?next={{request.path}}">Login</a></li>
|
|
||||||
</ul>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
<script>
|
|
||||||
$(".dropdown-trigger").dropdown({
|
|
||||||
hover: true,
|
|
||||||
constrainWidth: false,
|
|
||||||
coverTrigger: false
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
{% if user.is_authenticated %}
|
{% if user.is_authenticated %}
|
||||||
{% block content %} {% endblock %}
|
<div class="container-fluid">
|
||||||
{% else %}
|
<div class="row">
|
||||||
<div class="valign-wrapper" style="width:100%;height:100%;position: absolute;">
|
<div class="col-sm-2">
|
||||||
<div class="valign" style="width:100%;">
|
{% block sidebar %}
|
||||||
<div class="container">
|
<div class="sidenav">
|
||||||
<div class="row">
|
<a href="{% url 'search' %}">Search</a>
|
||||||
<div class="col s12 m6 offset-m3">
|
<a href="{% url 'books' %}">Books</a>
|
||||||
<div class="card">
|
<button class="dropdown-btn">Authors
|
||||||
<div class="card-content center">
|
<i class="fa fa-caret-down"></i>
|
||||||
<p>You don't have permission to view this.</p>
|
</button>
|
||||||
</div>
|
<div class="dropdown-container">
|
||||||
<div class="card-action center">
|
{% for author in unique_authors %}
|
||||||
<a class="waves-effect waves-light btn-large green accent-4" href="{% url 'login'%}?next={{request.path}}">Login</a>
|
<a href="{{author.get_absolute_url}}">{{author}}</a>
|
||||||
</div>
|
|
||||||
</div>
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<button class="dropdown-btn">Publishers
|
||||||
|
<i class="fa fa-caret-down"></i>
|
||||||
|
</button>
|
||||||
|
<div class="dropdown-container">
|
||||||
|
{% for publisher in unique_publishers %}
|
||||||
|
<a href="{{publisher.get_absolute_url}}">{{publisher}}</a>
|
||||||
|
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button class="dropdown-btn">Ratings
|
||||||
|
<i class="fa fa-caret-down"></i>
|
||||||
|
</button>
|
||||||
|
<div class="dropdown-container">
|
||||||
|
{% for rating in unique_ratings %}
|
||||||
|
<a href="{{rating.get_absolute_url}}">{{rating}}</a>
|
||||||
|
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
<button class="dropdown-btn">Tags
|
||||||
|
<i class="fa fa-caret-down"></i>
|
||||||
|
</button>
|
||||||
|
<div class="dropdown-container">
|
||||||
|
{% for tag in unique_tags %}
|
||||||
|
<a href="{{tag.get_absolute_url}}">{{tag}}</a>
|
||||||
|
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
{% endblock %}
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-sm-10 ">{% block content %}{% endblock %}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
<script>
|
||||||
|
var dropdown = document.getElementsByClassName("dropdown-btn");
|
||||||
|
var i;
|
||||||
|
|
||||||
|
for (i = 0; i < dropdown.length; i++) {
|
||||||
|
dropdown[i].addEventListener("click", function () {
|
||||||
|
this.classList.toggle("active");
|
||||||
|
var dropdownContent = this.nextElementSibling;
|
||||||
|
if (dropdownContent.style.display === "block") {
|
||||||
|
dropdownContent.style.display = "none";
|
||||||
|
} else {
|
||||||
|
dropdownContent.style.display = "block";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
function sortTable(n) {
|
function sortTable(n) {
|
||||||
@ -180,6 +153,17 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
{% else %}
|
||||||
|
<h1>You don't have permission to view this.</h1>
|
||||||
|
<li><a href="{% url 'login'%}?next={{request.path}}">Login</a></li>
|
||||||
|
or
|
||||||
|
<li><a href="{% url 'sign-up'%}?next={{request.path}}">Sign up</a></li>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
@ -1,22 +1,6 @@
|
|||||||
{% if user.is_authenticated %}
|
{% if user.is_authenticated %}
|
||||||
|
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="valign-wrapper" style="width:100%;height:100%;position: absolute;">
|
<h1>You don't have permission to view this.</h1>
|
||||||
<div class="valign" style="width:100%;">
|
<li><a href="{% url 'login'%}?next={{request.path}}">Login</a></li>
|
||||||
<div class="container">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col s12 m6 offset-m3">
|
|
||||||
<div class="card">
|
|
||||||
<div class="card-content center">
|
|
||||||
<p>You don't have permission to view this.</p>
|
|
||||||
</div>
|
|
||||||
<div class="card-action center">
|
|
||||||
<a class="waves-effect waves-light btn-large green accent-4" href="{% url 'login'%}?next={{request.path}}">Login</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
{% endif %}
|
@ -1,17 +1,17 @@
|
|||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
{% load static %}
|
||||||
<h1>{{author}}</h1>
|
<h1>{{author}}</h1>
|
||||||
|
|
||||||
<table id="books" class="highlight centered">
|
<table id="books">
|
||||||
<tr>
|
<tr>
|
||||||
<!--When a header is clicked, run the sortTable function, with a parameter, 0 for sorting by names, 1 for sorting by country:-->
|
<!--When a header is clicked, run the sortTable function, with a parameter, 0 for sorting by names, 1 for sorting by country:-->
|
||||||
<th class="title" onclick="sortTable(0)">Title</th>
|
<th onclick="sortTable(0)">Title</th>
|
||||||
<th class="author" onclick="sortTable(1)">Author</th>
|
<th onclick="sortTable(1)">Author</th>
|
||||||
<th class="rating" onclick="sortTable(2)">Rating</th>
|
<th onclick="sortTable(2)">Rating</th>
|
||||||
<th class="tags" onclick="sortTable(3)">Tags</th>
|
<th onclick="sortTable(3)">Tags</th>
|
||||||
<th class="added" onclick="sortTable(4)">Added</th>
|
<th onclick="sortTable(4)">Added</th>
|
||||||
</tr>
|
</tr>
|
||||||
{% for book in books %}
|
{% for book in books %}
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
{% load static %}
|
||||||
<h1>Author List</h1>
|
<h1>Author List</h1>
|
||||||
{% if author_list %}
|
{% if author_list %}
|
||||||
<ul>
|
<ul>
|
||||||
|
@ -2,60 +2,49 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
{% load static %}
|
{% load static %}
|
||||||
|
<h1>{{book.title}} by
|
||||||
|
{% if book.authors %}
|
||||||
|
{% for author in book.authors.all %}
|
||||||
|
<a href="{{author.get_absolute_url}}">{{author.name}}</a>
|
||||||
|
{%endfor%}
|
||||||
|
{% else %}
|
||||||
|
|
||||||
<div class="col s12 m7">
|
{{book.author_sort}}
|
||||||
<div class="card z-depth-0 horizontal">
|
{%endif%}
|
||||||
<div class="card-image">
|
|
||||||
<a style="padding-top:15%" href="{{download}}"><img src=" {% static "" %}{{imgpath}}" alt="download" srcset=""></a>
|
Published by
|
||||||
</div>
|
{% if book.publishers %}
|
||||||
<div class="card-stacked">
|
{% for pub in book.publishers.all %}
|
||||||
<div class="card-content">
|
<a href="{{pub.get_absolute_url}}">{{pub.name}}</a>
|
||||||
<h1> {{book.title}}</h1>
|
{%endfor%}
|
||||||
<h4> by
|
{% else %}
|
||||||
{% if book.authors %}
|
Unknown
|
||||||
{% for author in book.authors.all %}
|
|
||||||
<a href="{{author.get_absolute_url}}">{{author.name}}</a>
|
{%endif%}
|
||||||
{%endfor%}
|
|
||||||
{% else %}
|
Tags:
|
||||||
{{book.author_sort}}
|
{% if book.tags %}
|
||||||
{%endif%}
|
{% for tag in book.tags.all %}
|
||||||
<br>
|
<a href="{{tag.get_absolute_url}}">{{tag.name}}</a>,
|
||||||
Published by
|
{%endfor%}
|
||||||
{% if book.publishers %}
|
{% else %}
|
||||||
{% for pub in book.publishers.all %}
|
{%endif%}
|
||||||
<a href="{{pub.get_absolute_url}}">{{pub.name}}</a>
|
|
||||||
{%endfor%}
|
Rating:
|
||||||
{% else %}
|
{% if book.ratings %}
|
||||||
Unknown
|
{% for rating in book.ratings.all %}
|
||||||
{%endif%}
|
<a href="{{rating.get_absolute_url}}">{{rating}}</a>
|
||||||
<br>
|
{%endfor%}
|
||||||
Tags:
|
{% else %}
|
||||||
{% if book.tags %}
|
{%endif%}
|
||||||
{% for tag in book.tags.all %}
|
|
||||||
<a href="{{tag.get_absolute_url}}">{{tag.name}}</a>,
|
<a href="{{book.publisher.get_absolute_url}}">{{book.publisher}}</a>
|
||||||
{%endfor%}
|
</h1>
|
||||||
{% else %}
|
|
||||||
{%endif%}
|
<a href="{% static "" %}{{download}}"><img src="{% static "" %}{{imgpath}}" alt="download" srcset=""></a>
|
||||||
<br>
|
|
||||||
Rating:
|
|
||||||
{% if book.ratings %}
|
|
||||||
{% for rating in book.ratings.all %}
|
|
||||||
<a href="{{rating.get_absolute_url}}">{{rating}}</a>
|
|
||||||
{%endfor%}
|
|
||||||
{% else %}
|
|
||||||
{%endif%}
|
|
||||||
<br>
|
|
||||||
<a href="{{book.publisher.get_absolute_url}}">{{book.publisher}}</a>
|
|
||||||
</h4>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="container">
|
|
||||||
{% autoescape off %}
|
{% autoescape off %}
|
||||||
{{comment}}
|
{{comment}}
|
||||||
{% endautoescape %}
|
{% endautoescape %}
|
||||||
</div>
|
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
@ -1,21 +1,17 @@
|
|||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
{% load static %}
|
||||||
|
<h1>Book List</h1>
|
||||||
|
|
||||||
<h1 class="center">Book List</h1>
|
<table id="books">
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="col s1 m0">
|
|
||||||
</div>
|
|
||||||
<div class="col s10 m12">
|
|
||||||
<table id="books" class="highlight centered">
|
|
||||||
<tr>
|
<tr>
|
||||||
<!--When a header is clicked, run the sortTable function, with a parameter, 0 for sorting by names, 1 for sorting by country:-->
|
<!--When a header is clicked, run the sortTable function, with a parameter, 0 for sorting by names, 1 for sorting by country:-->
|
||||||
<th class="title" onclick="sortTable(0)">Title</th>
|
<th onclick="sortTable(0)">Title</th>
|
||||||
<th class="author" onclick="sortTable(1)">Author</th>
|
<th onclick="sortTable(1)">Author</th>
|
||||||
<th class="rating" onclick="sortTable(2)">Rating</th>
|
<th onclick="sortTable(2)">Rating</th>
|
||||||
<th class="tags" onclick="sortTable(3)">Tags</th>
|
<th onclick="sortTable(3)">Tags</th>
|
||||||
<th class="added" onclick="sortTable(4)">Added</th>
|
<th onclick="sortTable(4)">Added</th>
|
||||||
</tr>
|
</tr>
|
||||||
{% for book in book_list %}
|
{% for book in book_list %}
|
||||||
<tr>
|
<tr>
|
||||||
@ -34,8 +30,11 @@
|
|||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</table>
|
</table>
|
||||||
<div class="col s1 m0">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
@ -1,18 +1,18 @@
|
|||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
{% load static %}
|
||||||
<h1>{{publisher}} </h1>
|
<h1>{{publisher}} </h1>
|
||||||
|
|
||||||
{% if publisher.released %}
|
{% if publisher.released %}
|
||||||
<table id="books" class="highlight centered">
|
<table id="books">
|
||||||
<tr>
|
<tr>
|
||||||
<!--When a header is clicked, run the sortTable function, with a parameter, 0 for sorting by names, 1 for sorting by country:-->
|
<!--When a header is clicked, run the sortTable function, with a parameter, 0 for sorting by names, 1 for sorting by country:-->
|
||||||
<th class="title" onclick="sortTable(0)">Title</th>
|
<th onclick="sortTable(0)">Title</th>
|
||||||
<th class="author" onclick="sortTable(1)">Author</th>
|
<th onclick="sortTable(1)">Author</th>
|
||||||
<th class="rating" onclick="sortTable(2)">Rating</th>
|
<th onclick="sortTable(2)">Rating</th>
|
||||||
<th class="tags" onclick="sortTable(3)">Tags</th>
|
<th onclick="sortTable(3)">Tags</th>
|
||||||
<th class="added" onclick="sortTable(4)">Added</th>
|
<th onclick="sortTable(4)">Added</th>
|
||||||
</tr>
|
</tr>
|
||||||
{% for book in books %}
|
{% for book in books %}
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
{% load static %}
|
||||||
<h1>Publishers List</h1>
|
<h1>Publishers List</h1>
|
||||||
{% if publisher_list %}
|
{% if publisher_list %}
|
||||||
<ul>
|
<ul>
|
||||||
|
@ -1,17 +1,18 @@
|
|||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
{% load static %}
|
||||||
|
|
||||||
<h1 class="left">Books with rating: {{rating}}</h1>
|
<h1>{{rating}}</h1>
|
||||||
{% if books %}
|
{% if books %}
|
||||||
<table id="books" class="highlight centered">
|
<table id="books">
|
||||||
<tr>
|
<tr>
|
||||||
<!--When a header is clicked, run the sortTable function, with a parameter, 0 for sorting by names, 1 for sorting by country:-->
|
<!--When a header is clicked, run the sortTable function, with a parameter, 0 for sorting by names, 1 for sorting by country:-->
|
||||||
<th class="title" onclick="sortTable(0)">Title</th>
|
<th onclick="sortTable(0)">Title</th>
|
||||||
<th class="author" onclick="sortTable(1)">Author</th>
|
<th onclick="sortTable(1)">Author</th>
|
||||||
<th class="rating" onclick="sortTable(2)">Rating</th>
|
<th onclick="sortTable(2)">Rating</th>
|
||||||
<th class="tags" onclick="sortTable(3)">Tags</th>
|
<th onclick="sortTable(3)">Tags</th>
|
||||||
<th class="added" onclick="sortTable(4)">Added</th>
|
<th onclick="sortTable(4)">Added</th>
|
||||||
</tr>
|
</tr>
|
||||||
{% for book in books %}
|
{% for book in books %}
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
{% load static %}
|
||||||
<h1>Ratings List</h1>
|
<h1>Ratings List</h1>
|
||||||
{% if rating_list %}
|
{% if rating_list %}
|
||||||
<ul>
|
<ul>
|
||||||
|
@ -1,40 +0,0 @@
|
|||||||
{% extends "base.html" %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
{% load static %}
|
|
||||||
<h1>Results</h1>
|
|
||||||
|
|
||||||
<table id="books">
|
|
||||||
<tr>
|
|
||||||
<!--When a header is clicked, run the sortTable function, with a parameter, 0 for sorting by names, 1 for sorting by country:-->
|
|
||||||
<th onclick="sortTable(0)">Title</th>
|
|
||||||
<th onclick="sortTable(1)">Author</th>
|
|
||||||
<th onclick="sortTable(2)">Rating</th>
|
|
||||||
<th onclick="sortTable(3)">Tags</th>
|
|
||||||
<th onclick="sortTable(4)">Added</th>
|
|
||||||
</tr>
|
|
||||||
{% for book in book_list %}
|
|
||||||
<tr>
|
|
||||||
<td><a href="{{ book.get_absolute_url }}">{{ book.title }}</a></td>
|
|
||||||
<td>{{book.author_sort}}</td>
|
|
||||||
<td> {% for rating in book.ratings.all %}
|
|
||||||
{{rating}}
|
|
||||||
{% endfor %}
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
{% for tag in book.tags.all %}
|
|
||||||
{{tag}},
|
|
||||||
{% endfor %}
|
|
||||||
</td>
|
|
||||||
<td>{{book.timestamp}}</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</table>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{% endblock %}
|
|
@ -1,17 +1,18 @@
|
|||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
{% load static %}
|
||||||
|
|
||||||
<h1>{{tag}}</h1>
|
<h1>{{tag}}</h1>
|
||||||
{% if books %}
|
{% if books %}
|
||||||
<table id="books" class="highlight centered">
|
<table id="books">
|
||||||
<tr>
|
<tr>
|
||||||
<!--When a header is clicked, run the sortTable function, with a parameter, 0 for sorting by names, 1 for sorting by country:-->
|
<!--When a header is clicked, run the sortTable function, with a parameter, 0 for sorting by names, 1 for sorting by country:-->
|
||||||
<th class="title" onclick="sortTable(0)">Title</th>
|
<th onclick="sortTable(0)">Title</th>
|
||||||
<th class="author" onclick="sortTable(1)">Author</th>
|
<th onclick="sortTable(1)">Author</th>
|
||||||
<th class="rating" onclick="sortTable(2)">Rating</th>
|
<th onclick="sortTable(2)">Rating</th>
|
||||||
<th class="tags" onclick="sortTable(3)">Tags</th>
|
<th onclick="sortTable(3)">Tags</th>
|
||||||
<th class="added" onclick="sortTable(4)">Added</th>
|
<th onclick="sortTable(4)">Added</th>
|
||||||
</tr>
|
</tr>
|
||||||
{% for book in books %}
|
{% for book in books %}
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
{% load static %}
|
||||||
<h1>Tags List</h1>
|
<h1>Tags List</h1>
|
||||||
{% if tag_list %}
|
{% if tag_list %}
|
||||||
<ul>
|
<ul>
|
||||||
|
@ -2,6 +2,19 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
|
{% if form.errors %}
|
||||||
|
<p>Your username and password didn't match. Please try again.</p>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if next %}
|
||||||
|
{% if user.is_authenticated %}
|
||||||
|
<p>Your account doesn't have access to this page. To proceed,
|
||||||
|
please login with an account that has access.</p>
|
||||||
|
{% else %}
|
||||||
|
<p>Please login to see this page.</p>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<form method="post" action="{% url 'login' %}">
|
<form method="post" action="{% url 'login' %}">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<table>
|
<table>
|
||||||
@ -14,23 +27,7 @@
|
|||||||
<td>{{ form.password }}</td>
|
<td>{{ form.password }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
<input type="submit" value="login" />
|
||||||
<div style="color:#f44336">
|
|
||||||
{% if form.errors %}
|
|
||||||
<p>Your username and password didn't match. Please try again.</p>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if next %}
|
|
||||||
{% if user.is_authenticated %}
|
|
||||||
<p>Your account doesn't have access to this page. To proceed,
|
|
||||||
please login with an account that has access.</p>
|
|
||||||
{% else %}
|
|
||||||
<p>Please login to see this page.</p>
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<button class="waves-effect waves-light btn green accent-4" type="submit">login</button>
|
|
||||||
<input type="hidden" name="next" value="{{ next }}" />
|
<input type="hidden" name="next" value="{{ next }}" />
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
<form method="post">
|
<form method="post">
|
||||||
{% csrf_token %} {{form.as_p}} <button class="waves-effect waves-light btn green accent-4" type="submit">sign up</button></form>
|
{% csrf_token %} {{form.as_p}} <input type="submit" value="Sign up"></form>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
{% load static %}
|
||||||
<h1>Results</h1>
|
<h1>Results</h1>
|
||||||
|
|
||||||
<table id="books">
|
<table id="books">
|
||||||
<tr>
|
<tr>
|
||||||
<!--When a header is clicked, run the sortTable function, with a parameter, 0 for sorting by names, 1 for sorting by country:-->
|
<!--When a header is clicked, run the sortTable function, with a parameter, 0 for sorting by names, 1 for sorting by country:-->
|
||||||
<th class="title" onclick="sortTable(0)">Title</th>
|
<th onclick="sortTable(0)">Title</th>
|
||||||
<th class="author" onclick="sortTable(1)">Author</th>
|
<th onclick="sortTable(1)">Author</th>
|
||||||
<th class="rating" onclick="sortTable(2)">Rating</th>
|
<th onclick="sortTable(2)">Rating</th>
|
||||||
<th class="tags" onclick="sortTable(3)">Tags</th>
|
<th onclick="sortTable(3)">Tags</th>
|
||||||
<th class="added" onclick="sortTable(4)">Added</th>
|
<th onclick="sortTable(4)">Added</th>
|
||||||
</tr>
|
</tr>
|
||||||
{% for book in book_list %}
|
{% for book in book_list %}
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
{% load static %}
|
||||||
<div class="container">
|
<form action="{% url 'results' %}" method="get">
|
||||||
<form action="{% url 'results' %}" method="get" style="padding-top:2em">
|
|
||||||
<label for="title">Title: </label>
|
<label for="title">Title: </label>
|
||||||
<input id="title" type="text" name="title" value="">
|
<input id="title" type="text" name="title" value="">
|
||||||
<label for="author">Author: </label>
|
<label for="author">Author: </label>
|
||||||
<input id="author" type="text" name="author" value="">
|
<input id="author" type="text" name="author" value="">
|
||||||
<button class="waves-effect waves-light btn green accent-4" type="submit">search</button>
|
<input type="submit" value="search">
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
@ -5,39 +5,36 @@
|
|||||||
{% block title %}<title>Local Library</title>{% endblock %}
|
{% block title %}<title>Local Library</title>{% endblock %}
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css"
|
||||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
|
integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
|
||||||
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
<!-- Add additional CSS in static file -->
|
||||||
<!-- Compiled and minified CSS -->
|
{% load static %}
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0-beta/css/materialize.min.css">
|
<link rel="stylesheet" href="{% static 'css/styles.css' %}">
|
||||||
<!-- Compiled and minified JavaScript -->
|
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0-beta/js/materialize.min.js"></script>
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
{% block topnav%}
|
||||||
|
<ul class="topnav">
|
||||||
|
|
||||||
<div class="navbar-fixed">
|
{% if user.is_authenticated %}
|
||||||
<nav>
|
<li class="active"><a href="{{user.get_absolute_url}}"></a> {{ user.get_username }}</a></li>
|
||||||
<div class="nav-wrapper row green darken-1">
|
<li><a href="{% url 'logout'%}?next={{request.path}}">Logout</a></li>
|
||||||
|
{% else %}
|
||||||
|
<li><a href="{% url 'sign-up'%}?next={{request.path}}">Sign up</a></li>
|
||||||
|
<li><a href="{% url 'login'%}?next={{request.path}}">Login</a></li>
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
<ul class="right">
|
|
||||||
{% if user.is_authenticated %}
|
|
||||||
<li class="active"><a href="{{user.get_absolute_url}}"> {{ user.get_username }}</a></li>
|
<div class="container-fluid">
|
||||||
<li><a href="{% url 'logout'%}?next={{request.path}}">Logout</a></li>
|
<div class="row">
|
||||||
</ul>
|
|
||||||
{% else %}
|
<div class="col-sm-10 ">{% block content %}{% endblock %}</div>
|
||||||
<li><a href="{% url 'sign-up'%}?next={{request.path}}">Sign up</a></li>
|
|
||||||
<li><a href="{% url 'login'%}?next={{request.path}}">Login</a></li>
|
|
||||||
</ul>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
<div class="container">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col s10 ">{% block content %}{% endblock %}</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
|
14
README.md
14
README.md
@ -7,16 +7,4 @@ Set CALIBREPATH to the path of your library
|
|||||||
`./CalibreWebCompanion`
|
`./CalibreWebCompanion`
|
||||||
run `./manage.py runserver`
|
run `./manage.py runserver`
|
||||||
|
|
||||||
this is in development mode. don't actually use it or release it like this. The debug info it shows is spicy.
|
this is in development mode. don't actually use it or release it like this. The debug info it shows is spicy.
|
||||||
# Features
|
|
||||||
|
|
||||||
- [x] Books
|
|
||||||
- [x] navbar with tags, series, authors, etc
|
|
||||||
- [x] Search
|
|
||||||
- [x] authentication
|
|
||||||
|
|
||||||
|
|
||||||
# TODO
|
|
||||||
|
|
||||||
- [ ] fix author_detail_view with annotate instead of current implementation
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user