├── core ├── __init__.py ├── .env.example ├── asgi.py ├── wsgi.py ├── urls.py └── settings.py ├── library ├── __init__.py ├── migrations │ ├── __init__.py │ ├── 0005_auto_20210415_1729.py │ ├── 0006_auto_20210415_1730.py │ ├── 0007_auto_20210417_0835.py │ ├── 0003_auto_20210326_2011.py │ ├── 0001_initial.py │ ├── 0004_auto_20210415_1728.py │ └── 0002_fine_issue.py ├── tests.py ├── apps.py ├── urls.py ├── utilities.py ├── admin.py ├── models.py └── views.py ├── student ├── __init__.py ├── migrations │ ├── __init__.py │ └── 0001_initial.py ├── tests.py ├── apps.py ├── urls.py ├── models.py ├── admin.py └── views.py ├── templates ├── library │ ├── paystatus.html │ ├── myfines.html │ ├── allfines.html │ ├── payfine.html │ ├── myissues.html │ ├── addbook.html │ ├── allissues.html │ └── home.html ├── footer.html ├── student │ ├── login.html │ └── signup.html ├── base.html └── nav.html ├── screenshots ├── login.png ├── signup.png ├── allbooks.png ├── allfines.png ├── myfines.png ├── myissues.png ├── all-issues.png ├── paysuccess.png ├── search-book.png ├── all-students.png ├── choospaymode.png ├── search-author.png ├── user-details.png ├── confirmpayment.png ├── homepage-student.png ├── issue-requests.png ├── signup-same-id.png ├── student-details.png └── admin-dashboard-home.png ├── requirements.txt ├── manage.py ├── .gitignore └── Readme.md /core/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /library/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /student/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /library/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /student/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /templates/library/paystatus.html: -------------------------------------------------------------------------------- 1 |

Some unknown error occurred !

2 | -------------------------------------------------------------------------------- /library/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /student/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /screenshots/login.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhik-b/django-library-management/HEAD/screenshots/login.png -------------------------------------------------------------------------------- /screenshots/signup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhik-b/django-library-management/HEAD/screenshots/signup.png -------------------------------------------------------------------------------- /screenshots/allbooks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhik-b/django-library-management/HEAD/screenshots/allbooks.png -------------------------------------------------------------------------------- /screenshots/allfines.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhik-b/django-library-management/HEAD/screenshots/allfines.png -------------------------------------------------------------------------------- /screenshots/myfines.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhik-b/django-library-management/HEAD/screenshots/myfines.png -------------------------------------------------------------------------------- /screenshots/myissues.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhik-b/django-library-management/HEAD/screenshots/myissues.png -------------------------------------------------------------------------------- /core/.env.example: -------------------------------------------------------------------------------- 1 | SECRET_KEY = 'value' 2 | # 7_auto_lib_migr 3 | RAZORPAY_KEY_ID='value' 4 | RAZORPAY_KEY_SECRET='value' -------------------------------------------------------------------------------- /screenshots/all-issues.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhik-b/django-library-management/HEAD/screenshots/all-issues.png -------------------------------------------------------------------------------- /screenshots/paysuccess.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhik-b/django-library-management/HEAD/screenshots/paysuccess.png -------------------------------------------------------------------------------- /screenshots/search-book.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhik-b/django-library-management/HEAD/screenshots/search-book.png -------------------------------------------------------------------------------- /screenshots/all-students.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhik-b/django-library-management/HEAD/screenshots/all-students.png -------------------------------------------------------------------------------- /screenshots/choospaymode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhik-b/django-library-management/HEAD/screenshots/choospaymode.png -------------------------------------------------------------------------------- /screenshots/search-author.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhik-b/django-library-management/HEAD/screenshots/search-author.png -------------------------------------------------------------------------------- /screenshots/user-details.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhik-b/django-library-management/HEAD/screenshots/user-details.png -------------------------------------------------------------------------------- /library/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class LibraryConfig(AppConfig): 5 | name = 'library' 6 | -------------------------------------------------------------------------------- /screenshots/confirmpayment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhik-b/django-library-management/HEAD/screenshots/confirmpayment.png -------------------------------------------------------------------------------- /screenshots/homepage-student.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhik-b/django-library-management/HEAD/screenshots/homepage-student.png -------------------------------------------------------------------------------- /screenshots/issue-requests.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhik-b/django-library-management/HEAD/screenshots/issue-requests.png -------------------------------------------------------------------------------- /screenshots/signup-same-id.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhik-b/django-library-management/HEAD/screenshots/signup-same-id.png -------------------------------------------------------------------------------- /screenshots/student-details.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhik-b/django-library-management/HEAD/screenshots/student-details.png -------------------------------------------------------------------------------- /student/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class StudentConfig(AppConfig): 5 | name = 'student' 6 | -------------------------------------------------------------------------------- /screenshots/admin-dashboard-home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhik-b/django-library-management/HEAD/screenshots/admin-dashboard-home.png -------------------------------------------------------------------------------- /student/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | from .views import signup,login,logout 3 | 4 | urlpatterns = [ 5 | path('signup/', signup), 6 | path('login/', login), 7 | path('logout/', logout), 8 | 9 | 10 | ] -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | asgiref==3.3.1 2 | certifi==2020.12.5 3 | chardet==4.0.0 4 | Django==3.1.7 5 | django-environ==0.4.5 6 | idna==2.10 7 | Naked==0.1.31 8 | paytmchecksum==1.7.0 9 | Pillow==8.1.2 10 | pycryptodome==3.10.1 11 | pytz==2021.1 12 | PyYAML==5.4.1 13 | razorpay==1.2.0 14 | requests==2.25.1 15 | shellescape==3.8.1 16 | sqlparse==0.4.1 17 | urllib3==1.26.4 18 | -------------------------------------------------------------------------------- /core/asgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | ASGI config for core project. 3 | 4 | It exposes the ASGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/3.1/howto/deployment/asgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.asgi import get_asgi_application 13 | 14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'core.settings') 15 | 16 | application = get_asgi_application() 17 | -------------------------------------------------------------------------------- /core/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for core project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/3.1/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'core.settings') 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /library/migrations/0005_auto_20210415_1729.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.1.7 on 2021-04-15 11:59 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('library', '0004_auto_20210415_1728'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name='fine', 15 | name='datetime_of_payment', 16 | field=models.DateTimeField(blank=True, null=True), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /templates/footer.html: -------------------------------------------------------------------------------- 1 | 13 | -------------------------------------------------------------------------------- /library/migrations/0006_auto_20210415_1730.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.1.7 on 2021-04-15 12:00 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('library', '0005_auto_20210415_1729'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name='fine', 15 | name='order_id', 16 | field=models.CharField(blank=True, default=None, max_length=300, null=True, unique=True), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /library/migrations/0007_auto_20210417_0835.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.1.7 on 2021-04-17 03:05 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('library', '0006_auto_20210415_1730'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name='fine', 15 | name='order_id', 16 | field=models.CharField(blank=True, default=None, max_length=500, null=True, unique=True), 17 | ), 18 | ] 19 | 20 | # '=an0opy74a%d(plj5e@6-gtc=d&(%t7(teo3uoy&$((#w67_m+' 21 | 22 | # 'rzp_test_CWLIScpEnbRpw7' 23 | # 'fEVERgb1O7TavSEvPeJdmBIG' -------------------------------------------------------------------------------- /library/migrations/0003_auto_20210326_2011.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.1.7 on 2021-03-26 14:41 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('library', '0002_fine_issue'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name='issue', 15 | name='issued_at', 16 | field=models.DateTimeField(blank=True, null=True), 17 | ), 18 | migrations.AlterField( 19 | model_name='issue', 20 | name='return_date', 21 | field=models.DateTimeField(blank=True, null=True), 22 | ), 23 | ] 24 | -------------------------------------------------------------------------------- /manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Django's command-line utility for administrative tasks.""" 3 | import os 4 | import sys 5 | 6 | 7 | def main(): 8 | """Run administrative tasks.""" 9 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'core.settings') 10 | try: 11 | from django.core.management import execute_from_command_line 12 | except ImportError as exc: 13 | raise ImportError( 14 | "Couldn't import Django. Are you sure it's installed and " 15 | "available on your PYTHONPATH environment variable? Did you " 16 | "forget to activate a virtual environment?" 17 | ) from exc 18 | execute_from_command_line(sys.argv) 19 | 20 | 21 | if __name__ == '__main__': 22 | main() 23 | -------------------------------------------------------------------------------- /student/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | from django.contrib.auth.models import User 3 | 4 | # Create your models here. 5 | class Department(models.Model): 6 | name=models.CharField(max_length=200) 7 | 8 | def __str__(self): 9 | return self.name 10 | 11 | class Student(models.Model): 12 | first_name=models.CharField(max_length=120) 13 | last_name=models.CharField(max_length=120) 14 | department=models.ForeignKey(Department,on_delete=models.CASCADE) 15 | student_id=models.OneToOneField(User,on_delete=models.CASCADE) 16 | 17 | def __str__(self): 18 | last_4_digits=self.student_id.username[-4:] 19 | return "{}_{}-{}".format(self.first_name,last_4_digits,self.department) 20 | 21 | 22 | -------------------------------------------------------------------------------- /library/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | from .views import allbooks,search,addbook,deletebook,issuerequest,myissues,issue_book,return_book,requestedissues,myfines,allfines,deletefine,payfine,pay_status,sort 3 | urlpatterns = [ 4 | path('',allbooks,name='home'), 5 | path('search/',search), 6 | path('sort/',sort), 7 | path('addbook/',addbook), 8 | path('deletebook//',deletebook), 9 | path('request-book-issue//',issuerequest), 10 | path('my-issues/',myissues), 11 | path('my-fines/',myfines), 12 | path('payfines//',payfine), 13 | path('paystatus//',pay_status), 14 | path('all-issues/',requestedissues), 15 | path('all-fines/',allfines), 16 | path('issuebook//',issue_book), 17 | path('returnbook//',return_book), 18 | path('delete-fine//',deletefine), 19 | ] 20 | -------------------------------------------------------------------------------- /templates/library/myfines.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} {%block heading %} My Fines {% endblock heading %} 2 | 3 | {%block content %} 4 |
    5 | {% for fine in fines %} 6 |
  • 7 |
    8 |

    9 | Fine of 10 | ₹{{fine.amount}} for Book 11 | :- {{fine.issue.book.name}} 12 |

    13 | {%if fine.paid %} 14 |

    Paid on {{fine.datetime_of_payment}}

    15 | {% else %} 16 | Pay 21 | {% endif %} 22 |
    23 |
  • 24 | {% endfor %} 25 |
26 | {% endblock content %} 27 | -------------------------------------------------------------------------------- /library/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.1.7 on 2021-03-26 09:43 2 | 3 | from django.db import migrations, models 4 | import django.db.models.deletion 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | initial = True 10 | 11 | dependencies = [ 12 | ] 13 | 14 | operations = [ 15 | migrations.CreateModel( 16 | name='Author', 17 | fields=[ 18 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 19 | ('name', models.CharField(max_length=350)), 20 | ('description', models.CharField(max_length=450)), 21 | ], 22 | ), 23 | migrations.CreateModel( 24 | name='Book', 25 | fields=[ 26 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 27 | ('name', models.CharField(max_length=350)), 28 | ('image', models.ImageField(upload_to='')), 29 | ('category', models.CharField(max_length=220)), 30 | ('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='library.author')), 31 | ], 32 | ), 33 | ] 34 | -------------------------------------------------------------------------------- /core/urls.py: -------------------------------------------------------------------------------- 1 | """core URL Configuration 2 | 3 | The `urlpatterns` list routes URLs to views. For more information please see: 4 | https://docs.djangoproject.com/en/3.1/topics/http/urls/ 5 | Examples: 6 | Function views 7 | 1. Add an import: from my_app import views 8 | 2. Add a URL to urlpatterns: path('', views.home, name='home') 9 | Class-based views 10 | 1. Add an import: from other_app.views import Home 11 | 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') 12 | Including another URLconf 13 | 1. Import the include() function: from django.urls import include, path 14 | 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) 15 | """ 16 | from django.contrib import admin 17 | from django.urls import path,include 18 | from django.conf import settings 19 | from django.conf.urls.static import static 20 | 21 | 22 | admin.site.index_title='Library Management' 23 | admin.site.site_header='Admin Dashboard' 24 | 25 | 26 | # 27 | 28 | 29 | 30 | urlpatterns = [ 31 | path('admin/', admin.site.urls), 32 | path('student/',include('student.urls')), 33 | path('',include('library.urls')), 34 | ]+static(settings.STATIC_URL,document_root=settings.STATIC_ROOT)+static(settings.MEDIA_URL,document_root=settings.MEDIA_ROOT) 35 | -------------------------------------------------------------------------------- /student/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.1.1 on 2021-03-12 10:14 2 | 3 | from django.conf import settings 4 | from django.db import migrations, models 5 | import django.db.models.deletion 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | initial = True 11 | 12 | dependencies = [ 13 | migrations.swappable_dependency(settings.AUTH_USER_MODEL), 14 | ] 15 | 16 | operations = [ 17 | migrations.CreateModel( 18 | name='Department', 19 | fields=[ 20 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 21 | ('name', models.CharField(max_length=200)), 22 | ], 23 | ), 24 | migrations.CreateModel( 25 | name='Student', 26 | fields=[ 27 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 28 | ('first_name', models.CharField(max_length=120)), 29 | ('last_name', models.CharField(max_length=120)), 30 | ('department', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='student.department')), 31 | ('student_id', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), 32 | ], 33 | ), 34 | ] 35 | -------------------------------------------------------------------------------- /templates/student/login.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% block heading %} Login {% endblock heading %} 4 | 5 | 6 | {% block content %} 7 |
8 | {% csrf_token %} 9 |
10 | 11 | 17 | 18 |
19 | 20 | 26 | 27 | {% if request.GET.next %} 28 | 29 | {% endif %} 30 | 31 |
32 | 33 | {% endblock content %} 34 | -------------------------------------------------------------------------------- /student/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from .models import Student,Department 3 | from library.admin import FineInline,IssueInline 4 | 5 | from django.contrib.auth.models import User,Group 6 | from django.contrib.auth.admin import UserAdmin 7 | 8 | 9 | admin.site.unregister(User) 10 | admin.site.unregister(Group) 11 | class StudentInline(admin.TabularInline): 12 | model = Student 13 | # extra=0 14 | # Register out own model admin, based on the default UserAdmin 15 | @admin.register(User) 16 | class CustomUserAdmin(UserAdmin): 17 | list_display=('username','student','last_login') 18 | list_filter=('is_superuser','is_active') 19 | fieldsets = ( 20 | ('Standard info', { 21 | 'fields': ('username','password',) 22 | }), 23 | ('Important Date & Time ', { 24 | 'fields': ('last_login','date_joined',) 25 | }),) 26 | inlines = [ 27 | StudentInline 28 | ] 29 | 30 | 31 | 32 | 33 | @admin.register(Student) 34 | class StudentAdmin(admin.ModelAdmin): 35 | search_fields=['student_id__username','first_name','department'] 36 | fields=(('first_name','last_name'),('student_id','department')) 37 | list_display=('first_name','last_name','student_id','department') 38 | list_display_links = ('first_name', 'student_id') 39 | list_filter=('department__name',) 40 | list_per_page=30 41 | inlines = [ 42 | IssueInline,FineInline 43 | ] 44 | 45 | admin.site.register(Department) 46 | -------------------------------------------------------------------------------- /templates/library/allfines.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} {% block heading %} All Fines {% endblock heading %} 2 | {% block content %} 3 |
7 | 8 | 15 | 20 |
21 | 22 | 48 | {% endblock %} 49 | -------------------------------------------------------------------------------- /library/migrations/0004_auto_20210415_1728.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.1.7 on 2021-04-15 11:58 2 | 3 | from django.db import migrations, models 4 | import django.utils.timezone 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('library', '0003_auto_20210326_2011'), 11 | ] 12 | 13 | operations = [ 14 | migrations.AddField( 15 | model_name='fine', 16 | name='datetime_of_payment', 17 | field=models.DateTimeField(default=django.utils.timezone.now), 18 | ), 19 | migrations.AddField( 20 | model_name='fine', 21 | name='order_id', 22 | field=models.CharField(blank=True, default=None, max_length=100, null=True, unique=True), 23 | ), 24 | migrations.AddField( 25 | model_name='fine', 26 | name='paid', 27 | field=models.BooleanField(default=False), 28 | ), 29 | migrations.AddField( 30 | model_name='fine', 31 | name='razorpay_order_id', 32 | field=models.CharField(blank=True, max_length=500, null=True), 33 | ), 34 | migrations.AddField( 35 | model_name='fine', 36 | name='razorpay_payment_id', 37 | field=models.CharField(blank=True, max_length=500, null=True), 38 | ), 39 | migrations.AddField( 40 | model_name='fine', 41 | name='razorpay_signature', 42 | field=models.CharField(blank=True, max_length=500, null=True), 43 | ), 44 | ] 45 | -------------------------------------------------------------------------------- /library/utilities.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | from django.utils import timezone 3 | from .models import Fine,Book 4 | from student.models import Student 5 | 6 | def calcFine(issue): 7 | "Calculate fines of each issue if any" 8 | if(issue.issued==True and issue.returned==False): 9 | y,m,d=str(timezone.now().date()).split('-') 10 | today=datetime.date(int(y),int(m),int(d)) 11 | y2,m2,d2=str(issue.return_date.date()).split('-') 12 | lastdate=datetime.date(int(y2),int(m2),int(d2)) 13 | if(today>lastdate): 14 | diff=today-lastdate 15 | fine,created=Fine.objects.get_or_create(issue=issue,student=issue.student) 16 | if not fine.paid: 17 | fine.amount=diff.days*10 18 | fine.save() 19 | else: 20 | print('fine paid') 21 | else: 22 | return 'no fine' 23 | else: 24 | return 'no fine' 25 | 26 | def getmybooks(user): 27 | "Get issued books or requested books of a student, takes a user & returns a tuple " 28 | requestedbooks=[] 29 | issuedbooks=[] 30 | if user.is_authenticated: 31 | student = Student.objects.filter(student_id=user) 32 | if student: 33 | for b in Book.objects.all(): 34 | for i in b.issue_set.all(): 35 | if i.student==student[0]: 36 | if i.issued: 37 | issuedbooks.append(b) 38 | else: 39 | requestedbooks.append(b) 40 | return [requestedbooks,issuedbooks] -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Django # 2 | *.log 3 | *.pot 4 | *.pyc 5 | __pycache__ 6 | db.sqlite3 7 | media 8 | 9 | # Backup files # 10 | *.bak 11 | 12 | # Python # 13 | *.py[cod] 14 | *$py.class 15 | 16 | # Distribution / packaging 17 | .Python build/ 18 | develop-eggs/ 19 | dist/ 20 | downloads/ 21 | eggs/ 22 | .eggs/ 23 | lib/ 24 | lib64/ 25 | parts/ 26 | sdist/ 27 | var/ 28 | wheels/ 29 | *.egg-info/ 30 | .installed.cfg 31 | *.egg 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .coverage 43 | .coverage.* 44 | .cache 45 | .pytest_cache/ 46 | nosetests.xml 47 | coverage.xml 48 | *.cover 49 | .hypothesis/ 50 | 51 | 52 | # celery 53 | celerybeat-schedule.* 54 | 55 | # SageMath parsed files 56 | *.sage.py 57 | 58 | # Environments 59 | .env 60 | .venv 61 | env/ 62 | venv/ 63 | ENV/ 64 | env.bak/ 65 | venv.bak/ 66 | 67 | # mkdocs documentation 68 | /site 69 | 70 | # mypy 71 | .mypy_cache/ 72 | 73 | # Sublime Text # 74 | *.tmlanguage.cache 75 | *.tmPreferences.cache 76 | *.stTheme.cache 77 | *.sublime-workspace 78 | *.sublime-project 79 | 80 | # sftp configuration file 81 | sftp-config.json 82 | 83 | # Package control specific files Package 84 | Control.last-run 85 | Control.ca-list 86 | Control.ca-bundle 87 | Control.system-ca-bundle 88 | GitHub.sublime-settings 89 | 90 | # Visual Studio Code # 91 | .vscode/* 92 | !.vscode/settings.json 93 | !.vscode/tasks.json 94 | !.vscode/launch.json 95 | !.vscode/extensions.json 96 | .history -------------------------------------------------------------------------------- /library/migrations/0002_fine_issue.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.1.7 on 2021-03-26 14:38 2 | 3 | from django.db import migrations, models 4 | import django.db.models.deletion 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('student', '0001_initial'), 11 | ('library', '0001_initial'), 12 | ] 13 | 14 | operations = [ 15 | migrations.CreateModel( 16 | name='Issue', 17 | fields=[ 18 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 19 | ('created_at', models.DateTimeField(auto_now=True)), 20 | ('issued', models.BooleanField(default=False)), 21 | ('issued_at', models.DateTimeField()), 22 | ('returned', models.BooleanField(default=False)), 23 | ('return_date', models.DateTimeField(null=True)), 24 | ('book', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='library.book')), 25 | ('student', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='student.student')), 26 | ], 27 | ), 28 | migrations.CreateModel( 29 | name='Fine', 30 | fields=[ 31 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 32 | ('amount', models.DecimalField(decimal_places=2, default=0.0, max_digits=10)), 33 | ('issue', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='library.issue')), 34 | ('student', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='student.student')), 35 | ], 36 | ), 37 | ] 38 | -------------------------------------------------------------------------------- /templates/library/payfine.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {%block heading %} Confirm Fine payment {% endblock heading %} 4 | 5 | 6 | {%block content %} 7 | 13 |

14 | Payment of ₹{{amount_displayed}} for 15 | {{fine.issue.book.name}} (issue-id : 16 | {{fine.issue.id}}) 17 |

18 |
    19 |
  • 20 |
    21 |

    22 | Either Pay with Card / Net Banking / UPI / Wallets 23 |

    24 | 25 |
    26 | {% csrf_token %} 27 | 40 | 41 |
    42 |
    43 |
  • 44 |
  • 45 |

    Or Pay with Cash to Librarian In-Person

    46 |
  • 47 |
48 | {% endblock content %} 49 | 50 | -------------------------------------------------------------------------------- /templates/library/myissues.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} {% block heading %} My Issues {% endblock heading %} 2 | {% block content %} 3 | 4 |
9 | 16 | 23 | 30 |
31 |
    32 | {% for issue in issues %} 33 |
  • 34 |

    35 | {{issue.book.name}} Issue Requested 36 |

    37 |

    {{issue.created_at}}

    38 |
    39 | {% if issue.issued %} 40 |
    Issued
    41 |
    42 | Return Date : {{issue.return_date}} 43 |
    44 | {% else %} 45 |
    46 | Issue Request Pending 47 |
    48 | {% endif %} 49 | 50 | {% if issue.issued and issue.returned %} 51 |
    Returned
    52 | {% else %} 53 |
    {{issue.days_no}}
    54 | {% endif %} 55 |
    56 |
  • 57 | {% empty %} 58 |

    Nothing Found

    59 | {% endfor %} 60 |
61 | 62 | {% endblock %} 63 | -------------------------------------------------------------------------------- /templates/library/addbook.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} {% block heading %} Add Book {% endblock heading %} 2 | 3 | {% block content %} 4 | 5 |
11 | {% csrf_token %} 12 |
13 | 14 | 20 |
21 |
22 | 23 | 29 |
30 |
31 | 32 | 38 |
39 |
40 | 41 | 50 |
51 | 57 |
58 | {% endblock content%} 59 | -------------------------------------------------------------------------------- /templates/base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Library Management 8 | 12 | 30 | 31 | 32 | 33 | {% include 'nav.html' %} 34 | 35 |
38 |

39 | {%block heading %}{% endblock heading %} 40 |

41 | {% if user.is_anonymous %} 42 |

logged out

43 | {% else %} 44 |

logged in as {{user}}

45 | {% endif %} 46 |
47 |
48 | {% for message in messages %} 49 |

59 | {{message}} 60 |

61 | {%endfor %} 62 |
63 | 64 |
65 | {% block content %}{% endblock content %} 66 |
67 | 68 | {% include 'footer.html' %} 69 | 70 | 71 | -------------------------------------------------------------------------------- /templates/library/allissues.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} {% block heading %} All Issues {% endblock heading %} 2 | {% block content %} 3 |
7 | 8 | 15 | 20 |
21 | 22 | 23 |
    24 | {% for issue in issues %} 25 |
  • 26 |

    27 | {{issue.book.name}} Issue Requested by 28 | 33 | {{issue.student.student_id.username}}_{{issue.student.first_name}} 35 |

    36 |

    Created at:-{{issue.created_at}}

    37 |
    38 | {% if user.is_superuser %} {% if issue.issued %} 39 |
    40 | Issued 41 |
    42 | {%if issue.returned %} 43 |
    Returned
    44 | {% else %} 45 | return book 50 | {% endif %} {% else %} 51 | issue book 56 | {% endif %} {% endif %} 57 |
    58 |
  • 59 | {% empty %} 60 |

    Nothing Found

    61 | {% endfor %} 62 |
63 | 64 | {% endblock %} 65 | -------------------------------------------------------------------------------- /library/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | import datetime 3 | from django.utils import timezone 4 | from .models import Author,Book,Fine,Issue 5 | # Register your models here. 6 | 7 | 8 | 9 | @admin.register(Issue) 10 | class IssueAdmin(admin.ModelAdmin): 11 | list_display=('student','book','issued','returned' ,'days_remaining') 12 | list_filter=('issued','returned') 13 | fields=('student','book',('issued','returned'),'issued_at','return_date') 14 | search_fields=['student__student_id__username','book__name'] 15 | autocomplete_fields = ['student','book'] 16 | list_per_page=30 17 | 18 | 19 | 20 | def days_remaining(self,obj): 21 | if obj.returned: 22 | return 'returned' 23 | elif obj.return_date : 24 | y,m,d=str(timezone.now().date()).split('-') 25 | today=datetime.date(int(y),int(m),int(d)) 26 | y2,m2,d2=str(obj.return_date.date()).split('-') 27 | lastdate=datetime.date(int(y2),int(m2),int(d2)) 28 | if lastdate>today: 29 | return '{} days'.format((lastdate-today).days) 30 | return '{} days passed'.format((today-lastdate).days) 31 | return 'not issued' 32 | 33 | 34 | 35 | @admin.register(Fine) 36 | class FineAdmin(admin.ModelAdmin): 37 | list_display=('student','amount','order_id','paid') 38 | autocomplete_fields = ['student'] 39 | list_filter=('paid',) 40 | search_fields=['student__student_id__username','order_id'] 41 | list_per_page=30 42 | 43 | 44 | @admin.register(Book) 45 | class BookAdmin(admin.ModelAdmin): 46 | list_display=('name','author','category') 47 | search_fields=['name','category'] 48 | list_filter = ( 49 | ('author', admin.RelatedOnlyFieldListFilter), 50 | ) 51 | list_per_page=30 52 | 53 | 54 | 55 | class BookInline(admin.TabularInline): 56 | model = Book 57 | 58 | class IssueInline(admin.TabularInline): 59 | model = Issue 60 | extra=0 61 | class FineInline(admin.TabularInline): 62 | model = Fine 63 | extra=0 64 | 65 | @admin.register(Author) 66 | class AuthorAdmin(admin.ModelAdmin): 67 | list_display=('name',) 68 | search_fields=['name'] 69 | inlines = [ 70 | BookInline, 71 | ] 72 | list_per_page=30 73 | 74 | 75 | -------------------------------------------------------------------------------- /student/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render,redirect 2 | from .models import Student,Department 3 | from django.contrib import auth 4 | from django.contrib.auth.models import User 5 | from django.contrib import messages 6 | from django.core.files.storage import FileSystemStorage 7 | 8 | 9 | 10 | 11 | 12 | 13 | def logout(request): 14 | auth.logout(request) 15 | messages.success(request,'Logout successful') 16 | return redirect('home') 17 | 18 | 19 | def login(request): 20 | if request.method == 'POST': 21 | user = auth.authenticate(request, 22 | username=request.POST['studentID'], 23 | password=request.POST['password']) 24 | print(user) 25 | if user is None: 26 | messages.error(request,'Invalid CREDENTIALS') 27 | return redirect('/student/login/') 28 | else: 29 | auth.login(request, user) 30 | messages.success(request,'Login successful') 31 | if 'next' in request.POST: 32 | return redirect(request.POST['next']) 33 | return redirect('home') 34 | else: 35 | return render(request, 'student/login.html') 36 | 37 | 38 | def signup(request): 39 | 40 | if request.method=='POST': 41 | try: 42 | user=User.objects.get(username=request.POST['studentID']) 43 | messages.success(request,'user exists already !!') 44 | return redirect('/student/login/') 45 | 46 | 47 | except User.DoesNotExist: 48 | user=User.objects.create_user(username=request.POST['studentID'],password=request.POST['password']) 49 | 50 | newstudent=Student.objects.create(first_name=request.POST['firstname'],last_name=request.POST['lastname'], 51 | department=Department.objects.get(id=request.POST['department']),student_id=user 52 | ) 53 | 54 | auth.login(request,user) 55 | messages.success(request,'Signup successful') 56 | if "next" in request.POST: 57 | return redirect(request.POST.get('next')) 58 | return redirect('home') 59 | 60 | else: 61 | return render(request,'student/signup.html',{ 62 | "departments":Department.objects.all(), 63 | "users":list(User.objects.values_list('username',flat=True)) 64 | }) 65 | 66 | -------------------------------------------------------------------------------- /templates/nav.html: -------------------------------------------------------------------------------- 1 | 46 | 47 | 69 | -------------------------------------------------------------------------------- /templates/student/signup.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | {% block heading %} Signup {% endblock heading %} 3 | 4 | {% block content %} 5 | 6 |
7 | {% csrf_token %} 8 |
9 | 10 | 16 | 17 |
18 | 19 | 25 | 26 |
27 | 28 | 29 | 36 | 37 | 38 | 39 |
40 | 41 | 47 | 48 |
49 | 50 | 56 | 57 | 58 | 59 |
60 | 61 | 62 | 73 | {% endblock content %} 74 | -------------------------------------------------------------------------------- /library/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | from student.models import Student 3 | import datetime 4 | from django.utils import timezone 5 | # Create your models here. 6 | class Author(models.Model): 7 | name=models.CharField(max_length=350) 8 | description=models.CharField(max_length=450) 9 | def __str__(self): 10 | return self.name 11 | 12 | class Book(models.Model): 13 | name=models.CharField(max_length=350) 14 | author=models.ForeignKey(Author,on_delete=models.CASCADE) 15 | image=models.ImageField() 16 | category=models.CharField(max_length=220) 17 | 18 | def __str__(self): 19 | return self.name 20 | 21 | class Issue(models.Model): 22 | student=models.ForeignKey(Student,on_delete=models.CASCADE) 23 | book=models.ForeignKey(Book,on_delete=models.CASCADE) 24 | created_at=models.DateTimeField( auto_now=True) 25 | issued=models.BooleanField(default=False) 26 | issued_at=models.DateTimeField( auto_now=False,null=True,blank=True) 27 | returned=models.BooleanField(default=False) 28 | return_date=models.DateTimeField(auto_now=False,auto_created=False,auto_now_add=False,null=True,blank=True) 29 | 30 | def __str__(self): 31 | return "{}_{} book issue request".format(self.student,self.book) 32 | 33 | def days_no(self): 34 | "Returns the no. of days before returning / after return_date." 35 | if self.issued: 36 | y,m,d=str(timezone.now().date()).split('-') 37 | today=datetime.date(int(y),int(m),int(d)) 38 | y2,m2,d2=str(self.return_date.date()).split('-') 39 | lastdate=datetime.date(int(y2),int(m2),int(d2)) 40 | print(lastdate-today,lastdate>today) 41 | if lastdate > today: 42 | return "{} left".format(str(lastdate-today).split(',')[0]) 43 | else: 44 | return "{} passed".format(str(today-lastdate).split(',')[0]) 45 | else: 46 | return "" 47 | 48 | class Fine(models.Model): 49 | student=models.ForeignKey(Student,on_delete=models.CASCADE) 50 | issue=models.ForeignKey(Issue,on_delete=models.CASCADE) 51 | amount=models.DecimalField(default=0.00,max_digits=10,decimal_places=2) 52 | paid=models.BooleanField(default=False) 53 | order_id = models.CharField(unique=True, max_length=500, null=True, blank=True, default=None) 54 | datetime_of_payment = models.DateTimeField(auto_now=False,null=True,blank=True) 55 | 56 | # related to razorpay 57 | razorpay_order_id = models.CharField(max_length=500, null=True, blank=True) 58 | razorpay_payment_id = models.CharField(max_length=500, null=True, blank=True) 59 | razorpay_signature = models.CharField(max_length=500, null=True, blank=True) 60 | 61 | def save(self, *args, **kwargs): 62 | if self.order_id is None : 63 | self.order_id = "{}_{}_{}".format(self.student.department,self.student.student_id.username,timezone.now().strftime('%H%M%S') ) 64 | return super().save(*args, **kwargs) 65 | 66 | def __str__(self): 67 | return "{} fine->{}".format(self.issue,self.amount) -------------------------------------------------------------------------------- /core/settings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Django settings for core project. 3 | 4 | Generated by 'django-admin startproject' using Django 3.1.7. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/3.1/topics/settings/ 8 | 9 | For the full list of settings and their values, see 10 | https://docs.djangoproject.com/en/3.1/ref/settings/ 11 | """ 12 | 13 | from pathlib import Path 14 | import os 15 | from dotenv import load_dotenv 16 | 17 | # Build paths inside the project like this: BASE_DIR / 'subdir'. 18 | BASE_DIR = Path(__file__).resolve().parent.parent 19 | 20 | 21 | # Quick-start development settings - unsuitable for production 22 | # See https://docs.djangoproject.com/en/3.1/howto/deployment/checklist/ 23 | 24 | # SECURITY WARNING: keep the secret key used in production secret! 25 | load_dotenv() 26 | 27 | SECRET_KEY = os.getenv("SECRET_KEY") 28 | 29 | # SECURITY WARNING: don't run with debug turned on in production! 30 | DEBUG = True 31 | 32 | ALLOWED_HOSTS = [] 33 | 34 | 35 | # Application definition 36 | 37 | INSTALLED_APPS = [ 38 | 'django.contrib.admin', 39 | 'django.contrib.auth', 40 | 'django.contrib.contenttypes', 41 | 'django.contrib.sessions', 42 | 'django.contrib.messages', 43 | 'django.contrib.staticfiles', 44 | # LOCAL 45 | 'student', 46 | 'library', 47 | # 3RD PARTY 48 | 49 | ] 50 | 51 | MIDDLEWARE = [ 52 | 'django.middleware.security.SecurityMiddleware', 53 | 'django.contrib.sessions.middleware.SessionMiddleware', 54 | 'django.middleware.common.CommonMiddleware', 55 | 'django.middleware.csrf.CsrfViewMiddleware', 56 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 57 | 'django.contrib.messages.middleware.MessageMiddleware', 58 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 59 | ] 60 | 61 | ROOT_URLCONF = 'core.urls' 62 | 63 | TEMPLATES = [ 64 | { 65 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 66 | 'DIRS': [BASE_DIR,os.path.join('templates')], 67 | 'APP_DIRS': True, 68 | 'OPTIONS': { 69 | 'context_processors': [ 70 | 'django.template.context_processors.debug', 71 | 'django.template.context_processors.request', 72 | 'django.contrib.auth.context_processors.auth', 73 | 'django.contrib.messages.context_processors.messages', 74 | ], 75 | }, 76 | }, 77 | ] 78 | 79 | WSGI_APPLICATION = 'core.wsgi.application' 80 | 81 | 82 | # Database 83 | # https://docs.djangoproject.com/en/3.1/ref/settings/#databases 84 | 85 | DATABASES = { 86 | 'default': { 87 | 'ENGINE': 'django.db.backends.sqlite3', 88 | 'NAME': BASE_DIR / 'db.sqlite3', 89 | } 90 | } 91 | 92 | 93 | # Password validation 94 | # https://docs.djangoproject.com/en/3.1/ref/settings/#auth-password-validators 95 | 96 | AUTH_PASSWORD_VALIDATORS = [ 97 | { 98 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 99 | }, 100 | { 101 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 102 | }, 103 | { 104 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 105 | }, 106 | { 107 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 108 | }, 109 | ] 110 | 111 | 112 | # Internationalization 113 | # https://docs.djangoproject.com/en/3.1/topics/i18n/ 114 | 115 | LANGUAGE_CODE = 'en-us' 116 | 117 | TIME_ZONE = 'Asia/Kolkata' 118 | 119 | USE_I18N = True 120 | 121 | USE_L10N = True 122 | 123 | USE_TZ = True 124 | 125 | 126 | # Static files (CSS, JavaScript, Images) 127 | # https://docs.djangoproject.com/en/3.1/howto/static-files/ 128 | 129 | STATIC_URL = '/static/' 130 | STATIC_ROOT = '/static/' 131 | MEDIA_ROOT = os.path.join(BASE_DIR,'media') 132 | MEDIA_URL = '/media/' 133 | 134 | 135 | STATICFILES_DIRS=[ 136 | os.path.join(BASE_DIR,'static') 137 | ] 138 | 139 | RAZORPAY_KEY_ID=os.getenv("RAZORPAY_KEY_ID") 140 | RAZORPAY_KEY_SECRET=os.getenv("RAZORPAY_KEY_SECRET") -------------------------------------------------------------------------------- /templates/library/home.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} {% block heading %} Books List {% endblock heading %} 2 | 3 | {% block content %} 4 | 5 |
6 |
9 | 10 | 16 |
17 |
18 | 24 | 30 |
31 |
32 | 33 |
37 |

Sort :

38 | 46 |
    47 |
  • 48 |
  • 49 |
  • 50 |
  • 51 |
  • 52 |
  • 53 |
  • 54 |
  • 55 |
  • 56 |
  • 57 |
  • 58 |
  • 59 |
  • 60 |
  • 61 |
  • 62 |
  • 63 |
  • 64 |
  • 65 |
  • 66 |
  • 67 |
  • 68 |
  • 69 |
  • 70 |
  • 71 |
  • 72 |
  • 73 |
74 |
75 | 76 |
    79 | {% for book in books %} 80 |
  • 81 |

    {{book.name}}

    82 |

    {{book.author}}

    83 |

    {{book.category}}

    84 |
    85 | {{book.name}} 92 |
    93 | {% if not user.is_superuser and not user.is_anonymous %} 94 | 95 | 96 | {% if book in issuedbooks %} 97 |

    issued

    98 | {% elif book in requestedbooks %} 99 |

    issued requested

    100 | {% else %} 101 | 102 | Request Issue 107 | {% endif %} {% endif %} {% if user.is_superuser %} 108 | Edit 113 | {% endif %} 114 |
  • 115 | 116 | {% endfor %} 117 |
118 | 119 | 120 | {% if 'author' in request.get_full_path %} {% for author in author_results %} 121 | 122 |
123 |

{{author.name}}

124 | 125 |
    126 | {% for book in author.book_set.all %} 127 |
  • 128 |
    129 |

    {{book.name}}

    130 | {% if not user.is_superuser and not user.is_anonymous %} 131 | 132 | {% if book in issuedbooks %} 133 |

    issued

    134 | {% elif book in requestedbooks %} 135 |

    issued requested

    136 | {% else %} 137 | Request Issue 142 | {% endif %} {% endif %} 143 |
    144 |
  • 145 | 146 | {%empty %} 147 |

    No Books

    148 | {% endfor %} 149 |
150 |
151 | {%empty %} 152 |

Not Found

153 | {% endfor %} {% endif %} 154 | 155 | {% if 'book' in request.get_full_path %} 156 |
    159 | {% for book in books_results %} 160 |
  • 161 |

    {{book.name}}

    162 |

    {{book.author}}

    163 | {{book.name}} 170 | {% if not user.is_superuser and not user.is_anonymous %} 171 | 172 | {% if book in issuedbooks %} 173 |

    issued

    174 | {% elif book in requestedbooks %} 175 |

    issued requested

    176 | {% else %} 177 | Request Issue 182 | {% endif %} {% endif %} {% if user.is_superuser %} 183 | Edit 188 | {% endif %} 189 |
  • 190 | {%empty %} 191 |

    No Books Found

    192 | {% endfor %} 193 |
194 | {% endif %} 195 | 203 | {% endblock content %} 204 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # Library Management System 2 | 3 | This is a simple library management system built for Major Project 2021 by Abhik Bhattacharya (id : 181001102058) & Saikat Shee (id : 181001102053 ) 4 | 5 | 6 | 7 | This project is built with : 8 | 9 | ![HTML5](https://www.w3.org/html/logo/downloads/HTML5_Logo_64.png) , ![CSS3](https://upload.wikimedia.org/wikipedia/commons/thumb/d/d5/CSS3_logo_and_wordmark.svg/48px-CSS3_logo_and_wordmark.svg.png) , ![Vanilla JS](https://upload.wikimedia.org/wikipedia/commons/thumb/9/99/Unofficial_JavaScript_logo_2.svg/64px-Unofficial_JavaScript_logo_2.svg.png) , ![Python](https://www.quintagroup.com/++theme++quintagroup-theme/images/logo_python_section.png) , ![Django](https://www.quintagroup.com/++theme++quintagroup-theme/images/logo_django_section.png) , 10 | Tailwind CSS 11 | 12 | --- 13 | 14 | ## Features of this project: 15 | 16 | ##### Anyone can 17 | 18 | 1. see all the books in homepage 19 | 2. search books based on author or name of the book or category of the book 20 | 3. sort books or author alphabetically 21 | 22 | ##### Student can 23 | 24 | 1. login / signup , 25 | 2. can request book 26 | 3. see their own issues and filter them based on : 27 | 28 | - requested issues , 29 | - issued books or 30 | - all of them together 31 | 32 | 4. check their own fines 33 | 5. can see 34 | 35 | - the days remaining to return a particular book 36 | **or** 37 | - the number of days passed the return date of a particular book in the my fines page 38 | 39 | 6. Pay their fines online (powered by RazorPay) 40 | 41 | ##### Admin can 42 | 43 | 1. login to admin dashboard 44 | 2. check all issues : 45 | 46 | - see issues , 47 | - delete issues , 48 | - search issues by studentid 49 | - filter issues based on : 50 | 51 | - issued or not, 52 | - returned or not , 53 | 54 | 3. accept a issue : 55 | 56 | - from the dashboard where admin has to manually select return date 57 | **or** 58 | - from the Issue requests page where return date is automatically calculated 59 | 60 | 4. add , delete search books and filter books based on author 61 | 5. add , delete , search author 62 | 6. calculate fine by clicking a button , 63 | 7. create, delete fine ,search fines for studentid 64 | 8. toggle fine paid status (if paid in cash) 65 | 9. search ,modify,add,delete students , filter them based on department and check all fines and issues of that student 66 | 10. can see the last-login , date joined & the student associated to a particular user 67 | 11. can change password for any user 68 | 69 | ##### More ... 70 | 71 | 1. while signing up if studentID is already associated to a user in this platform then it will show a error without reloading the page and as soon as correct id is given then the error will go away 72 | 2. Books in homepage will show status of `issued` , `issue requested` or `request issue` based on whether the book is issued or requested for a issue or is not requested for logged-in students only 73 | 74 | --- 75 | 76 | ## Behind the scenes 77 | 78 | ### Student app 79 | 80 | We need this for writing our authentication views as well as student & department models. Student model has the first+last name ,department foreignkey and studentID which is one-to-one field to Django' User model. We use Django's User Model for authentication . There will be 3 views: login,signup and logout. The urls will have `/student/< login or signup or logout >/`. 81 | 82 | ### Library app 83 | 84 | This is our main app where we will write our library system's main logic. It comprises of 4 models: 85 | 86 | - **Author** - for storing name & description of author 87 | - **Book** - for storing name , image ,category of a book & connecting to the author 88 | - **Issue** - for tracking each & every issue a student requests. It will also track the book for which issue is requested , issue status (whether issued or not) , return status (whether returned or not) , return date (last date to return the book) and more... 89 | - **Fine** - for tracking the fines & calculating fines automatically for each student whose issued book/s is/are not returned and the last date is passed 90 | 91 | --- 92 | 93 | ## Some important logics : 94 | 95 | **Student ID** - Username of Django's User Model serves as our studentID 96 | 97 | **Signing Up** - so every student who signs up creates a new user instance with his/her student id as the username and then a student instance is also created with the names and department and this user we just created. 98 | 99 | **Calculating Fine - How ??** - 100 | We run a for loop and pass all the issues to this calculate fine function. Then: 101 | 102 | - for each issue , check whether the issue is issued or not (if issue is not issued then no need to calculate fines) 103 | 104 | - if issue is issued then check whether issue is returned or not (if issue is returned then no need to calculate fines) 105 | 106 | - if issue is not returned then check whether the issue's return date is passed or not (if not passed then no calculation of fines is needed) 107 | - create or get a fine instance with student & issue then calculate the amount and save it to the amount field 108 | 109 | **Calculating Fine - When ??** - 110 | 111 | - Whenever admin clicks on "_Calculate Fine_" button 112 | - Whenever a student opens his "_My Fines_" page 113 | 114 | **Payment of Fines** 115 | 116 | - when a student clicks on pay button (in myfines page) 117 | - we create a razorpay order with a dict containing fine amount (coverted to int and multiplied by 100 because razorpay wants in paisa) , order_id, currency 118 | - then we send the user to the payfines page (payfines.html) with the amount (in paisa ) , razorpay key id, razorpay order id & amount (which should be displayed) 119 | - user chooses proceed to payment online , selects paymode (Netbanking , Card , Wallet etc.) and pays the amount 120 | - we verify the payment status whether success or failure 121 | - then payment is (successfull/failure) message is shown on myfine page with (paid status / pay button) beside that fine 122 | 123 | ## Screenshots 124 | 125 | - Signup Page 126 | ![login](./screenshots/signup.png) 127 | - Login Page 128 | ![login](./screenshots/login.png) 129 | - If Student ID already signed up 130 | ![signup](./screenshots/signup-same-id.png) 131 | 132 | - Home Page for student 133 | ![homepage](./screenshots/homepage-student.png) 134 | - Search Book 135 | ![search-book](./screenshots/search-book.png) 136 | - Search Author 137 | ![search-author](./screenshots/search-author.png) 138 | 139 | - My Issues 140 | ![myissues](./screenshots/myissues.png) 141 | - My Fines 142 | ![myfines](./screenshots/myfines.png) 143 | - Confirm Payment 144 | ![paymentmode](./screenshots/confirmpayment.png) 145 | - Choose Payment Modes 146 | ![paymentmode](./screenshots/choospaymode.png) 147 | - Pay Success 148 | ![paymentmode](./screenshots/paysuccess.png) 149 | 150 | - Admin Dashboard 151 | ![admin](./screenshots/admin-dashboard-home.png) 152 | 153 | - All Books (Admin) 154 | ![allbooks](./screenshots/allbooks.png) 155 | 156 | - All issues , can be filtered ,searched (Admin) 157 | ![allissues](./screenshots/all-issues.png) 158 | - Requested Issues (Admin) 159 | ![allissues](./screenshots/issue-requests.png) 160 | 161 | - All fines , can be filtered ,searched (Admin) 162 | ![allfines](./screenshots/allfines.png) 163 | 164 | - All Students , can be filtered ,searched (Admin) 165 | ![allstudents](./screenshots/all-students.png) 166 | - Student Details (Admin) 167 | ![student-details](./screenshots/student-details.png) 168 | - User Details (Admin) 169 | ![student-details](./screenshots/user-details.png) 170 | 19 171 | -------------------------------------------------------------------------------- /library/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render,redirect 2 | from .models import Book,Author,Issue,Fine 3 | from student.models import Student 4 | from django.contrib.auth.decorators import login_required 5 | from django.contrib.auth.decorators import user_passes_test 6 | from django.contrib import messages 7 | from django.utils import timezone 8 | import datetime 9 | from .utilities import calcFine,getmybooks 10 | from django.db.models import Q 11 | from django.contrib.auth.models import User 12 | from django.contrib import auth 13 | from core import settings 14 | 15 | 16 | # Book 17 | def allbooks(request): 18 | requestedbooks,issuedbooks=getmybooks(request.user) 19 | allbooks=Book.objects.all() 20 | 21 | return render(request,'library/home.html',{'books':allbooks,'issuedbooks':issuedbooks,'requestedbooks':requestedbooks}) 22 | 23 | 24 | def sort(request): 25 | sort_type=request.GET.get('sort_type') 26 | sort_by=request.GET.get('sort') 27 | requestedbooks,issuedbooks=getmybooks(request.user) 28 | if 'author' in sort_type: 29 | author_results=Author.objects.filter(name__startswith=sort_by) 30 | return render(request,'library/home.html',{'author_results':author_results,'issuedbooks':issuedbooks,'requestedbooks':requestedbooks,'selected':'author'}) 31 | else: 32 | books_results=Book.objects.filter(name__startswith=sort_by) 33 | return render(request,'library/home.html',{'books_results':books_results,'issuedbooks':issuedbooks,'requestedbooks':requestedbooks,'selected':'book'}) 34 | 35 | 36 | def search(request): 37 | search_query=request.GET.get('search-query') 38 | search_by_author=request.GET.get('author') 39 | requestedbooks,issuedbooks=getmybooks(request.user) 40 | 41 | if search_by_author is not None: 42 | author_results=Author.objects.filter(name__icontains=search_query) 43 | return render(request,'library/home.html',{'author_results':author_results,'issuedbooks':issuedbooks,'requestedbooks':requestedbooks}) 44 | else: 45 | books_results=Book.objects.filter(Q(name__icontains=search_query) | Q(category__icontains=search_query)) 46 | return render(request,'library/home.html',{'books_results':books_results,'issuedbooks':issuedbooks,'requestedbooks':requestedbooks}) 47 | 48 | 49 | 50 | @login_required(login_url='/student/login/') 51 | @user_passes_test(lambda u: u.is_superuser,login_url='/student/login/') 52 | def addbook(request): 53 | authors=Author.objects.all() 54 | if request.method=="POST": 55 | name=request.POST['name'] 56 | category=request.POST['category'] 57 | author=Author.objects.get(id=request.POST['author']) 58 | image=request.FILES['book-image'] 59 | if author is not None or author != '': 60 | newbook,created=Book.objects.get_or_create(name=name,image=image,category=category,author=author) 61 | messages.success(request,'Book - {} Added succesfully '.format(newbook.name)) 62 | return render(request,'library/addbook.html',{'authors':authors,}) 63 | else: 64 | messages.error(request,'Author not found !') 65 | return render(request,'library/addbook.html',{'authors':authors,}) 66 | else: 67 | return render(request,'library/addbook.html',{'authors':authors}) 68 | 69 | 70 | 71 | @login_required(login_url='/student/login/') 72 | @user_passes_test(lambda u: u.is_superuser,login_url='/student/login/') 73 | def deletebook(request,bookID): 74 | book=Book.objects.get(id=bookID) 75 | messages.success(request,'Book - {} Deleted succesfully '.format(book.name)) 76 | book.delete() 77 | return redirect('/') 78 | 79 | 80 | 81 | # ISSUES 82 | 83 | @login_required(login_url='/student/login/') 84 | @user_passes_test(lambda u: not u.is_superuser,login_url='/student/login/') 85 | def issuerequest(request,bookID): 86 | student=Student.objects.filter(student_id=request.user) 87 | if student: 88 | book=Book.objects.get(id=bookID) 89 | issue,created=Issue.objects.get_or_create(book=book,student=student[0]) 90 | messages.success(request,'Book - {} Requested succesfully '.format(book.name)) 91 | return redirect('home') 92 | 93 | messages.error(request,'You are Not a Student !') 94 | return redirect('/') 95 | 96 | @login_required(login_url='/student/login/') 97 | @user_passes_test(lambda u: not u.is_superuser ,login_url='/student/login/') 98 | def myissues(request): 99 | if Student.objects.filter(student_id=request.user): 100 | student=Student.objects.filter(student_id=request.user)[0] 101 | 102 | if request.GET.get('issued') is not None: 103 | issues=Issue.objects.filter(student=student,issued=True) 104 | elif request.GET.get('notissued') is not None: 105 | issues=Issue.objects.filter(student=student,issued=False) 106 | else: 107 | issues=Issue.objects.filter(student=student) 108 | 109 | return render(request,'library/myissues.html',{'issues':issues}) 110 | 111 | messages.error(request,'You are Not a Student !') 112 | return redirect('/') 113 | 114 | 115 | @login_required(login_url='/admin/') 116 | @user_passes_test(lambda u: u.is_superuser ,login_url='/admin/') 117 | def requestedissues(request): 118 | if request.GET.get('studentID') is not None and request.GET.get('studentID') != '': 119 | try: 120 | user= User.objects.get(username=request.GET.get('studentID')) 121 | student=Student.objects.filter(student_id=user) 122 | if student: 123 | student=student[0] 124 | issues=Issue.objects.filter(student=student,issued=False) 125 | return render(request,'library/allissues.html',{'issues':issues}) 126 | messages.error(request,'No Student found') 127 | return redirect('/all-issues/') 128 | except User.DoesNotExist: 129 | messages.error(request,'No Student found') 130 | return redirect('/all-issues/') 131 | 132 | else: 133 | issues=Issue.objects.filter(issued=False) 134 | return render(request,'library/allissues.html',{'issues':issues}) 135 | 136 | 137 | 138 | @login_required(login_url='/admin/') 139 | @user_passes_test(lambda u: u.is_superuser ,login_url='/student/login/') 140 | def issue_book(request,issueID): 141 | issue=Issue.objects.get(id=issueID) 142 | issue.return_date=timezone.now() + datetime.timedelta(days=15) 143 | issue.issued_at=timezone.now() 144 | issue.issued=True 145 | issue.save() 146 | return redirect('/all-issues/') 147 | 148 | 149 | @login_required(login_url='/student/login/') 150 | @user_passes_test(lambda u: u.is_superuser ,login_url='/admin/') 151 | def return_book(request,issueID): 152 | issue=Issue.objects.get(id=issueID) 153 | calcFine(issue) 154 | issue.returned=True 155 | issue.save() 156 | return redirect('/all-issues/') 157 | 158 | 159 | # FINES 160 | 161 | @login_required(login_url='/student/login/') 162 | @user_passes_test(lambda u: not u.is_superuser ,login_url='/student/login/') 163 | def myfines(request): 164 | if Student.objects.filter(student_id=request.user): 165 | student=Student.objects.filter(student_id=request.user)[0] 166 | issues=Issue.objects.filter(student=student) 167 | for issue in issues: 168 | calcFine(issue) 169 | fines=Fine.objects.filter(student=student) 170 | return render(request,'library/myfines.html',{'fines':fines}) 171 | messages.error(request,'You are Not a Student !') 172 | return redirect('/') 173 | 174 | 175 | @login_required(login_url='/student/login/') 176 | @user_passes_test(lambda u: u.is_superuser ,login_url='/admin/') 177 | def allfines(request): 178 | issues=Issue.objects.all() 179 | for issue in issues: 180 | calcFine(issue) 181 | return redirect('/admin/library/fine/') 182 | 183 | @login_required(login_url='/student/login/') 184 | @user_passes_test(lambda u: u.is_superuser ,login_url='/admin/') 185 | def deletefine(request,fineID): 186 | fine=Fine.objects.get(id=fineID) 187 | fine.delete() 188 | return redirect('/all-fines/') 189 | 190 | import razorpay 191 | razorpay_client = razorpay.Client(auth=(settings.RAZORPAY_KEY_ID, settings.RAZORPAY_KEY_SECRET)) 192 | 193 | @login_required(login_url='/student/login/') 194 | @user_passes_test(lambda u: not u.is_superuser ,login_url='/student/login/') 195 | def payfine(request,fineID): 196 | fine=Fine.objects.get(id=fineID) 197 | order_amount = int(fine.amount)*100 198 | order_currency = 'INR' 199 | order_receipt = fine.order_id 200 | 201 | 202 | razorpay_order=razorpay_client.order.create(dict(amount=order_amount, currency=order_currency, receipt=order_receipt, )) 203 | print(razorpay_order) 204 | 205 | 206 | return render(request,'library/payfine.html', 207 | {'amount':order_amount,'razor_id':settings.RAZORPAY_KEY_ID, 208 | 'reciept':razorpay_order['id'], 209 | 'amount_displayed':order_amount / 100, 210 | 'address':'a custom address', 211 | 'fine':fine, 212 | }) 213 | 214 | 215 | @login_required(login_url='/student/login/') 216 | @user_passes_test(lambda u: not u.is_superuser ,login_url='/student/login/') 217 | def pay_status(request,fineID): 218 | if request.method == 'POST': 219 | params_dict={ 220 | 'razorpay_payment_id':request.POST['razorpay_payment_id'], 221 | 'razorpay_order_id':request.POST['razorpay_order_id'], 222 | 'razorpay_signature':request.POST['razorpay_signature'], 223 | } 224 | try: 225 | status=razorpay_client.utility.verify_payment_signature(params_dict) 226 | if status is None: 227 | fine=Fine.objects.get(id=fineID) 228 | fine.paid=True 229 | fine.datetime_of_payment=timezone.now() 230 | fine.razorpay_payment_id=request.POST['razorpay_payment_id'] 231 | fine.razorpay_signature=request.POST['razorpay_signature'] 232 | fine.razorpay_order_id = request.POST['razorpay_order_id'] 233 | fine.save() 234 | 235 | messages.success(request,'Payment Succesfull') 236 | except: 237 | messages.error(request,'Payment Failure') 238 | return redirect('/my-fines/') --------------------------------------------------------------------------------