├── api ├── __init__.py ├── migrations │ └── __init__.py ├── models.py ├── admin.py ├── tests.py ├── apps.py ├── serializers.py ├── urls.py ├── filters.py └── views.py ├── blogs ├── __init__.py ├── migrations │ ├── __init__.py │ ├── 0002_alter_comment_blog.py │ ├── 0003_alter_comment_blog.py │ ├── 0001_initial.py │ └── 0004_album_track.py ├── tests.py ├── views.py ├── apps.py ├── admin.py ├── paginations.py ├── serializers.py └── models.py ├── employees ├── __init__.py ├── migrations │ ├── __init__.py │ └── 0001_initial.py ├── tests.py ├── views.py ├── admin.py ├── apps.py ├── models.py └── test_data_generator.py ├── students ├── __init__.py ├── migrations │ ├── __init__.py │ └── 0001_initial.py ├── tests.py ├── admin.py ├── urls.py ├── apps.py ├── views.py └── models.py ├── django_rest_main ├── __init__.py ├── asgi.py ├── wsgi.py ├── urls.py └── settings.py ├── .DS_Store ├── README.md ├── manage.py └── .gitignore /api/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /blogs/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /employees/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /students/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /api/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /blogs/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /django_rest_main/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /employees/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /students/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /api/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | # Create your models here. 4 | -------------------------------------------------------------------------------- /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dev-rathankumar/drf-basics-course/HEAD/.DS_Store -------------------------------------------------------------------------------- /api/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /api/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /blogs/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /blogs/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render 2 | 3 | # Create your views here. 4 | -------------------------------------------------------------------------------- /employees/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /employees/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render 2 | 3 | # Create your views here. 4 | -------------------------------------------------------------------------------- /students/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /students/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from .models import Student 3 | 4 | 5 | 6 | admin.site.register(Student) -------------------------------------------------------------------------------- /employees/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from .models import Employee 3 | 4 | 5 | 6 | admin.site.register(Employee) 7 | -------------------------------------------------------------------------------- /students/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | from . import views 3 | 4 | urlpatterns = [ 5 | path('', views.students, name='students'), 6 | ] -------------------------------------------------------------------------------- /api/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class ApiConfig(AppConfig): 5 | default_auto_field = "django.db.models.BigAutoField" 6 | name = "api" 7 | -------------------------------------------------------------------------------- /blogs/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class BlogsConfig(AppConfig): 5 | default_auto_field = 'django.db.models.BigAutoField' 6 | name = 'blogs' 7 | -------------------------------------------------------------------------------- /students/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class StudentsConfig(AppConfig): 5 | default_auto_field = "django.db.models.BigAutoField" 6 | name = "students" 7 | -------------------------------------------------------------------------------- /employees/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class EmployeesConfig(AppConfig): 5 | default_auto_field = 'django.db.models.BigAutoField' 6 | name = 'employees' 7 | -------------------------------------------------------------------------------- /blogs/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from .models import Blog, Comment, Album, Track 3 | 4 | 5 | admin.site.register(Blog) 6 | admin.site.register(Comment) 7 | admin.site.register(Album) 8 | admin.site.register(Track) -------------------------------------------------------------------------------- /students/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render 2 | from django.http import HttpResponse 3 | 4 | 5 | 6 | def students(request): 7 | students = [{'id': 1, 'name': 'John Doe', 'age': 25}] 8 | return HttpResponse(students) -------------------------------------------------------------------------------- /students/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | 4 | class Student(models.Model): 5 | student_id = models.CharField(max_length=10) 6 | name = models.CharField(max_length=50) 7 | branch = models.CharField(max_length=50) 8 | 9 | def __str__(self): 10 | return self.name -------------------------------------------------------------------------------- /employees/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | 4 | class Employee(models.Model): 5 | emp_id = models.CharField(max_length=20) 6 | emp_name = models.CharField(max_length=50) 7 | designation = models.CharField(max_length=50) 8 | 9 | def __str__(self): 10 | return self.emp_name -------------------------------------------------------------------------------- /api/serializers.py: -------------------------------------------------------------------------------- 1 | from rest_framework import serializers 2 | from students.models import Student 3 | from employees.models import Employee 4 | 5 | 6 | class StudentSerializer(serializers.ModelSerializer): 7 | class Meta: 8 | model = Student 9 | fields = "__all__" 10 | 11 | 12 | class EmployeeSerializer(serializers.ModelSerializer): 13 | class Meta: 14 | model = Employee 15 | fields = '__all__' -------------------------------------------------------------------------------- /django_rest_main/asgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | ASGI config for django_rest_main 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/5.0/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", "django_rest_main.settings") 15 | 16 | application = get_asgi_application() 17 | -------------------------------------------------------------------------------- /django_rest_main/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for django_rest_main 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/5.0/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", "django_rest_main.settings") 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /blogs/migrations/0002_alter_comment_blog.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 5.0.4 on 2024-05-09 10:41 2 | 3 | import django.db.models.deletion 4 | from django.db import migrations, models 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('blogs', '0001_initial'), 11 | ] 12 | 13 | operations = [ 14 | migrations.AlterField( 15 | model_name='comment', 16 | name='blog', 17 | field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='blogs.blog'), 18 | ), 19 | ] 20 | -------------------------------------------------------------------------------- /blogs/migrations/0003_alter_comment_blog.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 5.0.4 on 2024-05-09 10:49 2 | 3 | import django.db.models.deletion 4 | from django.db import migrations, models 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('blogs', '0002_alter_comment_blog'), 11 | ] 12 | 13 | operations = [ 14 | migrations.AlterField( 15 | model_name='comment', 16 | name='blog', 17 | field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='comments', to='blogs.blog'), 18 | ), 19 | ] 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # API Development With Django REST Framework 2 | 3 | Click the link below to watch the full course for free: 4 | 5 | [![Watch Full Course](https://img.shields.io/badge/Watch%20Now-YouTube-red?style=for-the-badge&logo=youtube)](https://youtu.be/8d1HgJTEGe8?si=06wKLc1p02LXBo0d) 6 | 7 | ## 📌 Course Details 8 | This course covers everything you need to know to master API Development using Django REST Framework. Don't miss this opportunity to learn for free! 9 | 10 | --- 11 | 12 | 🎥 **Watch Now:** [https://youtu.be/8d1HgJTEGe8?si=06wKLc1p02LXBo0d](https://youtu.be/8d1HgJTEGe8?si=06wKLc1p02LXBo0d) 13 | -------------------------------------------------------------------------------- /blogs/paginations.py: -------------------------------------------------------------------------------- 1 | from rest_framework.pagination import PageNumberPagination 2 | from rest_framework.response import Response 3 | 4 | 5 | 6 | class CustomPagination(PageNumberPagination): 7 | page_size_query_param = 'page_size' 8 | page_query_param = 'page-num' 9 | max_page_size = 1 10 | 11 | def get_paginated_response(self, data): 12 | return Response({ 13 | 'next': self.get_next_link(), 14 | 'previous': self.get_previous_link(), 15 | 'count': self.page.paginator.count, 16 | 'page_size': self.page_size, 17 | 'results': data 18 | }) -------------------------------------------------------------------------------- /employees/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 5.0.4 on 2024-05-03 10:54 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | initial = True 9 | 10 | dependencies = [ 11 | ] 12 | 13 | operations = [ 14 | migrations.CreateModel( 15 | name='Employee', 16 | fields=[ 17 | ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 18 | ('emp_id', models.CharField(max_length=20)), 19 | ('emp_name', models.CharField(max_length=50)), 20 | ('designation', models.CharField(max_length=50)), 21 | ], 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", "django_rest_main.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 | -------------------------------------------------------------------------------- /employees/test_data_generator.py: -------------------------------------------------------------------------------- 1 | from faker import Faker 2 | import random 3 | from employees.models import Employee 4 | 5 | fake = Faker('en_US') 6 | 7 | 8 | def generate_employee_data(): 9 | emp_id = fake.pyint(min_value=100000, max_value=999999) 10 | emp_name = fake.name() 11 | designation = random.choice(['Software Engineer', 'Software Tester', 'Manager', 'HR', 'Marketing']) 12 | return { 13 | 'emp_id': emp_id, 14 | 'emp_name': emp_name, 15 | 'designation': designation 16 | } 17 | 18 | data_count = 50 19 | for _ in range(data_count): 20 | employee_data = generate_employee_data() 21 | employee = Employee(**employee_data) 22 | employee.save() 23 | 24 | print(f'{data_count} employee data has been created successfully!') -------------------------------------------------------------------------------- /blogs/serializers.py: -------------------------------------------------------------------------------- 1 | from rest_framework import serializers 2 | from .models import Blog, Comment, Track, Album 3 | 4 | 5 | 6 | 7 | 8 | 9 | class CommentSerializer(serializers.ModelSerializer): 10 | class Meta: 11 | model = Comment 12 | fields = '__all__' 13 | 14 | 15 | class BlogSerializer(serializers.ModelSerializer): 16 | comments = CommentSerializer(many=True, read_only=True) 17 | class Meta: 18 | model = Blog 19 | fields = '__all__' 20 | 21 | 22 | 23 | 24 | class TrackSerializer(serializers.ModelSerializer): 25 | class Meta: 26 | model = Track 27 | fields = ['order', 'title', 'duration'] 28 | 29 | class AlbumSerializer(serializers.ModelSerializer): 30 | tracks = TrackSerializer(many=True, read_only=True) 31 | 32 | class Meta: 33 | model = Album 34 | fields = ['album_name', 'artist', 'tracks'] -------------------------------------------------------------------------------- /students/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 5.0.4 on 2024-04-30 08:03 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | initial = True 8 | 9 | dependencies = [] 10 | 11 | operations = [ 12 | migrations.CreateModel( 13 | name="Student", 14 | fields=[ 15 | ( 16 | "id", 17 | models.BigAutoField( 18 | auto_created=True, 19 | primary_key=True, 20 | serialize=False, 21 | verbose_name="ID", 22 | ), 23 | ), 24 | ("student_id", models.CharField(max_length=10)), 25 | ("name", models.CharField(max_length=50)), 26 | ("branch", models.CharField(max_length=50)), 27 | ], 28 | ), 29 | ] 30 | -------------------------------------------------------------------------------- /api/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path, include 2 | from . import views 3 | from rest_framework.routers import DefaultRouter 4 | 5 | 6 | router = DefaultRouter() 7 | router.register('employees', views.EmployeeViewset, basename='employeedirectories') 8 | 9 | urlpatterns = [ 10 | path('students/', views.studentsView), 11 | path('student//', views.studentDetailView), 12 | 13 | # path('employees/', views.EmployeeList.as_view()), 14 | # path('employees//', views.EmployeeDetail.as_view()), 15 | 16 | path('', include(router.urls)), 17 | 18 | path('blogs/', views.BlogsView.as_view()), 19 | path('blogs//', views.BlogDetailView.as_view()), 20 | path('comments/', views.CommentsView.as_view()), 21 | path('comments//', views.CommentDetailView.as_view()), 22 | 23 | 24 | path('albums/', views.AlbumView.as_view()), 25 | path('tracks/', views.TrackView.as_view()), 26 | 27 | ] -------------------------------------------------------------------------------- /api/filters.py: -------------------------------------------------------------------------------- 1 | import django_filters 2 | from employees.models import Employee 3 | 4 | 5 | class EmployeeFilter(django_filters.FilterSet): 6 | designation = django_filters.CharFilter(field_name='designation', lookup_expr='iexact') 7 | emp_name = django_filters.CharFilter(field_name='emp_name', lookup_expr='icontains') 8 | # id = django_filters.RangeFilter(field_name='id') 9 | id_min = django_filters.CharFilter(method='filter_by_id_range', label='From EMP ID') 10 | id_max = django_filters.CharFilter(method='filter_by_id_range', label='To EMP ID') 11 | 12 | class Meta: 13 | model = Employee 14 | fields = ['designation', 'emp_name', 'id_min', 'id_max'] 15 | 16 | def filter_by_id_range(self, queryset, name, value): 17 | if name == 'id_min': 18 | return queryset.filter(emp_id__gte=value) 19 | elif name == 'id_max': 20 | return queryset.filter(emp_id__lte=value) 21 | return queryset -------------------------------------------------------------------------------- /blogs/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | 4 | 5 | class Blog(models.Model): 6 | blog_title = models.CharField(max_length=100) 7 | blog_body = models.TextField() 8 | 9 | def __str__(self): 10 | return self.blog_title 11 | 12 | 13 | class Comment(models.Model): 14 | blog = models.ForeignKey(Blog, on_delete=models.CASCADE, related_name='comments') 15 | comment = models.TextField() 16 | 17 | def __str__(self): 18 | return self.comment 19 | 20 | 21 | 22 | class Album(models.Model): 23 | album_name = models.CharField(max_length=100) 24 | artist = models.CharField(max_length=100) 25 | 26 | class Track(models.Model): 27 | album = models.ForeignKey(Album, related_name='tracks', on_delete=models.CASCADE) 28 | order = models.IntegerField() 29 | title = models.CharField(max_length=100) 30 | duration = models.IntegerField() 31 | 32 | def __str__(self): 33 | return '%d: %s' % (self.order, self.title) -------------------------------------------------------------------------------- /django_rest_main/urls.py: -------------------------------------------------------------------------------- 1 | """ 2 | URL configuration for django_rest_main project. 3 | 4 | The `urlpatterns` list routes URLs to views. For more information please see: 5 | https://docs.djangoproject.com/en/5.0/topics/http/urls/ 6 | Examples: 7 | Function views 8 | 1. Add an import: from my_app import views 9 | 2. Add a URL to urlpatterns: path('', views.home, name='home') 10 | Class-based views 11 | 1. Add an import: from other_app.views import Home 12 | 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') 13 | Including another URLconf 14 | 1. Import the include() function: from django.urls import include, path 15 | 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) 16 | """ 17 | from django.contrib import admin 18 | from django.urls import path, include 19 | 20 | urlpatterns = [ 21 | path("admin/", admin.site.urls), 22 | # Web application endpoints 23 | path('students', include('students.urls')), 24 | 25 | # API Endpoints 26 | path('api/v1/', include('api.urls')), 27 | 28 | ] 29 | -------------------------------------------------------------------------------- /blogs/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 5.0.4 on 2024-05-09 09:21 2 | 3 | import django.db.models.deletion 4 | from django.db import migrations, models 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | initial = True 10 | 11 | dependencies = [ 12 | ] 13 | 14 | operations = [ 15 | migrations.CreateModel( 16 | name='Blog', 17 | fields=[ 18 | ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 19 | ('blog_title', models.CharField(max_length=100)), 20 | ('blog_body', models.TextField()), 21 | ], 22 | ), 23 | migrations.CreateModel( 24 | name='Comment', 25 | fields=[ 26 | ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 27 | ('comment', models.TextField()), 28 | ('blog', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='comments', to='blogs.blog')), 29 | ], 30 | ), 31 | ] 32 | -------------------------------------------------------------------------------- /blogs/migrations/0004_album_track.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 5.0.4 on 2024-05-09 11:01 2 | 3 | import django.db.models.deletion 4 | from django.db import migrations, models 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('blogs', '0003_alter_comment_blog'), 11 | ] 12 | 13 | operations = [ 14 | migrations.CreateModel( 15 | name='Album', 16 | fields=[ 17 | ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 18 | ('album_name', models.CharField(max_length=100)), 19 | ('artist', models.CharField(max_length=100)), 20 | ], 21 | ), 22 | migrations.CreateModel( 23 | name='Track', 24 | fields=[ 25 | ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 26 | ('order', models.IntegerField()), 27 | ('title', models.CharField(max_length=100)), 28 | ('duration', models.IntegerField()), 29 | ('album', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='tracks', to='blogs.album')), 30 | ], 31 | ), 32 | ] 33 | -------------------------------------------------------------------------------- /django_rest_main/settings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Django settings for django_rest_main project. 3 | 4 | Generated by 'django-admin startproject' using Django 5.0.4. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/5.0/topics/settings/ 8 | 9 | For the full list of settings and their values, see 10 | https://docs.djangoproject.com/en/5.0/ref/settings/ 11 | """ 12 | 13 | from pathlib import Path 14 | 15 | # Build paths inside the project like this: BASE_DIR / 'subdir'. 16 | BASE_DIR = Path(__file__).resolve().parent.parent 17 | 18 | 19 | # Quick-start development settings - unsuitable for production 20 | # See https://docs.djangoproject.com/en/5.0/howto/deployment/checklist/ 21 | 22 | # SECURITY WARNING: keep the secret key used in production secret! 23 | SECRET_KEY = "django-insecure-d$*0r@(q(r#*e@0u%=p^*$xci9i*hu3#yft4ab$q(7#6ja%z17" 24 | 25 | # SECURITY WARNING: don't run with debug turned on in production! 26 | DEBUG = True 27 | 28 | ALLOWED_HOSTS = [] 29 | 30 | 31 | # Application definition 32 | 33 | INSTALLED_APPS = [ 34 | "django.contrib.admin", 35 | "django.contrib.auth", 36 | "django.contrib.contenttypes", 37 | "django.contrib.sessions", 38 | "django.contrib.messages", 39 | "django.contrib.staticfiles", 40 | "students", 41 | "rest_framework", 42 | "employees", 43 | 'blogs', 44 | 'django_filters', 45 | ] 46 | 47 | MIDDLEWARE = [ 48 | "django.middleware.security.SecurityMiddleware", 49 | "django.contrib.sessions.middleware.SessionMiddleware", 50 | "django.middleware.common.CommonMiddleware", 51 | "django.middleware.csrf.CsrfViewMiddleware", 52 | "django.contrib.auth.middleware.AuthenticationMiddleware", 53 | "django.contrib.messages.middleware.MessageMiddleware", 54 | "django.middleware.clickjacking.XFrameOptionsMiddleware", 55 | ] 56 | 57 | ROOT_URLCONF = "django_rest_main.urls" 58 | 59 | TEMPLATES = [ 60 | { 61 | "BACKEND": "django.template.backends.django.DjangoTemplates", 62 | "DIRS": [], 63 | "APP_DIRS": True, 64 | "OPTIONS": { 65 | "context_processors": [ 66 | "django.template.context_processors.debug", 67 | "django.template.context_processors.request", 68 | "django.contrib.auth.context_processors.auth", 69 | "django.contrib.messages.context_processors.messages", 70 | ], 71 | }, 72 | }, 73 | ] 74 | 75 | WSGI_APPLICATION = "django_rest_main.wsgi.application" 76 | 77 | 78 | # Database 79 | # https://docs.djangoproject.com/en/5.0/ref/settings/#databases 80 | 81 | DATABASES = { 82 | "default": { 83 | "ENGINE": "django.db.backends.sqlite3", 84 | "NAME": BASE_DIR / "db.sqlite3", 85 | } 86 | } 87 | 88 | 89 | # Password validation 90 | # https://docs.djangoproject.com/en/5.0/ref/settings/#auth-password-validators 91 | 92 | AUTH_PASSWORD_VALIDATORS = [ 93 | { 94 | "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator", 95 | }, 96 | { 97 | "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", 98 | }, 99 | { 100 | "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator", 101 | }, 102 | { 103 | "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator", 104 | }, 105 | ] 106 | 107 | 108 | # Internationalization 109 | # https://docs.djangoproject.com/en/5.0/topics/i18n/ 110 | 111 | LANGUAGE_CODE = "en-us" 112 | 113 | TIME_ZONE = "UTC" 114 | 115 | USE_I18N = True 116 | 117 | USE_TZ = True 118 | 119 | 120 | # Static files (CSS, JavaScript, Images) 121 | # https://docs.djangoproject.com/en/5.0/howto/static-files/ 122 | 123 | STATIC_URL = "static/" 124 | 125 | # Default primary key field type 126 | # https://docs.djangoproject.com/en/5.0/ref/settings/#default-auto-field 127 | 128 | DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" 129 | 130 | 131 | REST_FRAMEWORK = { 132 | 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination', 133 | 'PAGE_SIZE': 4, 134 | 'DEFAULT_FILTER_BACKENDS': ['django_filters.rest_framework.DjangoFilterBackend'], 135 | 'SEARCH_PARAM': 'q', 136 | 'ORDERING_PARAM': 'order-by' 137 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.toptal.com/developers/gitignore/api/django 2 | # Edit at https://www.toptal.com/developers/gitignore?templates=django 3 | 4 | ### Django ### 5 | *.log 6 | *.pot 7 | *.pyc 8 | __pycache__/ 9 | local_settings.py 10 | db.sqlite3 11 | db.sqlite3-journal 12 | media 13 | 14 | # If your build process includes running collectstatic, then you probably don't need or want to include staticfiles/ 15 | # in your Git repository. Update and uncomment the following line accordingly. 16 | # /staticfiles/ 17 | 18 | ### Django.Python Stack ### 19 | # Byte-compiled / optimized / DLL files 20 | *.py[cod] 21 | *$py.class 22 | 23 | # C extensions 24 | *.so 25 | 26 | # Distribution / packaging 27 | .Python 28 | build/ 29 | develop-eggs/ 30 | dist/ 31 | downloads/ 32 | eggs/ 33 | .eggs/ 34 | lib/ 35 | lib64/ 36 | parts/ 37 | sdist/ 38 | var/ 39 | wheels/ 40 | share/python-wheels/ 41 | *.egg-info/ 42 | .installed.cfg 43 | *.egg 44 | MANIFEST 45 | 46 | # PyInstaller 47 | # Usually these files are written by a python script from a template 48 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 49 | *.manifest 50 | *.spec 51 | 52 | # Installer logs 53 | pip-log.txt 54 | pip-delete-this-directory.txt 55 | 56 | # Unit test / coverage reports 57 | htmlcov/ 58 | .tox/ 59 | .nox/ 60 | .coverage 61 | .coverage.* 62 | .cache 63 | nosetests.xml 64 | coverage.xml 65 | *.cover 66 | *.py,cover 67 | .hypothesis/ 68 | .pytest_cache/ 69 | cover/ 70 | 71 | # Translations 72 | *.mo 73 | 74 | # Django stuff: 75 | 76 | # Flask stuff: 77 | instance/ 78 | .webassets-cache 79 | 80 | # Scrapy stuff: 81 | .scrapy 82 | 83 | # Sphinx documentation 84 | docs/_build/ 85 | 86 | # PyBuilder 87 | .pybuilder/ 88 | target/ 89 | 90 | # Jupyter Notebook 91 | .ipynb_checkpoints 92 | 93 | # IPython 94 | profile_default/ 95 | ipython_config.py 96 | 97 | # pyenv 98 | # For a library or package, you might want to ignore these files since the code is 99 | # intended to run in multiple environments; otherwise, check them in: 100 | # .python-version 101 | 102 | # pipenv 103 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 104 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 105 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 106 | # install all needed dependencies. 107 | #Pipfile.lock 108 | 109 | # poetry 110 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 111 | # This is especially recommended for binary packages to ensure reproducibility, and is more 112 | # commonly ignored for libraries. 113 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 114 | #poetry.lock 115 | 116 | # pdm 117 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. 118 | #pdm.lock 119 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it 120 | # in version control. 121 | # https://pdm.fming.dev/#use-with-ide 122 | .pdm.toml 123 | 124 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm 125 | __pypackages__/ 126 | 127 | # Celery stuff 128 | celerybeat-schedule 129 | celerybeat.pid 130 | 131 | # SageMath parsed files 132 | *.sage.py 133 | 134 | # Environments 135 | .env 136 | .venv 137 | env/ 138 | venv/ 139 | ENV/ 140 | env.bak/ 141 | venv.bak/ 142 | 143 | # Spyder project settings 144 | .spyderproject 145 | .spyproject 146 | 147 | # Rope project settings 148 | .ropeproject 149 | 150 | # mkdocs documentation 151 | /site 152 | 153 | # mypy 154 | .mypy_cache/ 155 | .dmypy.json 156 | dmypy.json 157 | 158 | # Pyre type checker 159 | .pyre/ 160 | 161 | # pytype static type analyzer 162 | .pytype/ 163 | 164 | # Cython debug symbols 165 | cython_debug/ 166 | 167 | # PyCharm 168 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 169 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 170 | # and can be added to the global gitignore or merged into this file. For a more nuclear 171 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 172 | #.idea/ 173 | 174 | # End of https://www.toptal.com/developers/gitignore/api/django -------------------------------------------------------------------------------- /api/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render, get_object_or_404 2 | from django.http import JsonResponse 3 | from students.models import Student 4 | from .serializers import StudentSerializer, EmployeeSerializer 5 | from rest_framework.decorators import api_view 6 | from rest_framework.response import Response 7 | from rest_framework import status 8 | from rest_framework.views import APIView 9 | from employees.models import Employee 10 | from django.http import Http404 11 | from rest_framework import generics, mixins 12 | from rest_framework import viewsets 13 | from blogs.models import Blog, Comment, Album, Track 14 | from blogs.serializers import BlogSerializer, CommentSerializer, AlbumSerializer, TrackSerializer 15 | from blogs.paginations import CustomPagination 16 | from django_filters.rest_framework import DjangoFilterBackend 17 | from .filters import EmployeeFilter 18 | from rest_framework import filters 19 | 20 | 21 | 22 | @api_view(['GET', 'POST']) 23 | def studentsView(request): 24 | if request.method == 'GET': 25 | # Get all the data from Student table 26 | students = Student.objects.all() 27 | serializer = StudentSerializer(students, many=True) 28 | return Response(serializer.data, status=status.HTTP_200_OK) 29 | elif request.method == 'POST': 30 | serializer = StudentSerializer(data=request.data) 31 | if serializer.is_valid(): 32 | serializer.save() 33 | return Response(serializer.data, status=status.HTTP_201_CREATED) 34 | return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) 35 | 36 | 37 | @api_view(['GET', 'PUT', 'DELETE']) 38 | def studentDetailView(request, pk): 39 | try: 40 | student = Student.objects.get(pk=pk) 41 | except Student.DoesNotExist: 42 | return Response(status=status.HTTP_404_NOT_FOUND) 43 | 44 | if request.method == 'GET': 45 | serializer = StudentSerializer(student) 46 | return Response(serializer.data, status=status.HTTP_200_OK) 47 | 48 | elif request.method == 'PUT': 49 | serializer = StudentSerializer(student, data=request.data) 50 | if serializer.is_valid(): 51 | serializer.save() 52 | return Response(serializer.data, status=status.HTTP_200_OK) 53 | else: 54 | return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) 55 | elif request.method == 'DELETE': 56 | student.delete() 57 | return Response(status=status.HTTP_204_NO_CONTENT) 58 | 59 | 60 | # APIView 61 | # class EmployeeList(APIView): 62 | # def get(self, request): 63 | # employees = Employee.objects.all() 64 | # serializer = EmployeeSerializer(employees, many=True) 65 | # return Response(serializer.data) 66 | 67 | # def post(self, request): 68 | # serializer = EmployeeSerializer(data=request.data) 69 | # if serializer.is_valid(): 70 | # serializer.save() 71 | # return Response(serializer.data, status=status.HTTP_201_CREATED) 72 | 73 | 74 | # class EmployeeDetail(APIView): 75 | # def get_object(self, pk): 76 | # try: 77 | # return Employee.objects.get(pk=pk) 78 | # except Employee.DoesNotExist: 79 | # raise Http404 80 | 81 | # def get(self, request, pk): 82 | # employee = self.get_object(pk) 83 | # serializer = EmployeeSerializer(employee) 84 | # return Response(serializer.data, status=status.HTTP_200_OK) 85 | 86 | # def put(self, request, pk): 87 | # employee = self.get_object(pk) 88 | # serializer = EmployeeSerializer(employee, data=request.data) 89 | # if serializer.is_valid(): 90 | # serializer.save() 91 | # return Response(serializer.data, status=status.HTTP_200_OK) 92 | # return Response(serializer.errors, status.HTTP_400_BAD_REQUEST) 93 | 94 | # def delete(self, request, pk): 95 | # employee = self.get_object(pk) 96 | # employee.delete() 97 | # return Response(status=status.HTTP_204_NO_CONTENT) 98 | 99 | 100 | 101 | """ 102 | # Mixins 103 | class EmployeeList(mixins.ListModelMixin, mixins.CreateModelMixin, generics.GenericAPIView): 104 | queryset = Employee.objects.all() 105 | serializer_class = EmployeeSerializer 106 | 107 | def get(self, request): 108 | return self.list(request) 109 | 110 | def post(self, request): 111 | return self.create(request) 112 | 113 | 114 | 115 | class EmployeeDetail(mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, generics.GenericAPIView): 116 | queryset = Employee.objects.all() 117 | serializer_class = EmployeeSerializer 118 | 119 | def get(self, request, pk): 120 | return self.retrieve(request, pk) 121 | 122 | def put(self, request, pk): 123 | return self.update(request, pk) 124 | 125 | def delete(self, request, pk): 126 | return self.destroy(request, pk) 127 | """ 128 | 129 | 130 | """ 131 | # Generics 132 | class EmployeeList(generics.ListCreateAPIView): 133 | queryset = Employee.objects.all() 134 | serializer_class = EmployeeSerializer 135 | 136 | 137 | class EmployeeDetail(generics.RetrieveUpdateDestroyAPIView): 138 | queryset = Employee.objects.all() 139 | serializer_class = EmployeeSerializer 140 | lookup_field = 'pk' 141 | 142 | """ 143 | 144 | 145 | class EmployeeViewset(viewsets.ModelViewSet): 146 | # def list(self, request): 147 | # queryset = Employee.objects.all() 148 | # serializer = EmployeeSerializer(queryset, many=True) 149 | # return Response(serializer.data) 150 | 151 | # def create(self, request): 152 | # serializer = EmployeeSerializer(data=request.data) 153 | # if serializer.is_valid(): 154 | # serializer.save() 155 | # return Response(serializer.data) 156 | # return Response(serializer.errors) 157 | 158 | # def retrieve(self, request, pk=None): 159 | # # queryset = Employee.objects.all() 160 | # employee = get_object_or_404(Employee, pk=pk) 161 | # serializer = EmployeeSerializer(employee) 162 | # return Response(serializer.data) 163 | 164 | # def update(self, request, pk=None): 165 | # employee = get_object_or_404(Employee, pk=pk) 166 | # serializer = EmployeeSerializer(employee, data=request.data) 167 | # if serializer.is_valid(): 168 | # serializer.save() 169 | # return Response(serializer.data) 170 | # return Response(serializer.errors) 171 | 172 | # def delete(self, request, pk=None): 173 | # employee = get_object_or_404(Employee, pk=pk) 174 | # employee.delete() 175 | # return Response(status=status.HTTP_204_NO_CONTENT) 176 | 177 | queryset = Employee.objects.all() 178 | serializer_class = EmployeeSerializer 179 | pagination_class = CustomPagination 180 | filterset_class = EmployeeFilter 181 | 182 | 183 | 184 | 185 | 186 | 187 | # class EmployeeViewset(viewsets.ModelViewSet): 188 | # queryset = Employee.objects.all() 189 | # serializer_class = EmployeeSerializer 190 | 191 | 192 | class BlogsView(generics.ListCreateAPIView): 193 | queryset = Blog.objects.all() 194 | serializer_class = BlogSerializer 195 | # filter_backends = [] 196 | filterset_fields = ['id', 'blog_title'] 197 | filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter] 198 | search_fields = ['^blog_title'] 199 | ordering_fields = ['blog_title'] 200 | 201 | 202 | class BlogDetailView(generics.RetrieveUpdateDestroyAPIView): 203 | queryset = Blog.objects.all() 204 | serializer_class = BlogSerializer 205 | lookup_field = 'pk' 206 | 207 | 208 | 209 | class CommentsView(generics.ListCreateAPIView): 210 | queryset = Comment.objects.all() 211 | serializer_class = CommentSerializer 212 | 213 | 214 | class CommentDetailView(generics.RetrieveUpdateDestroyAPIView): 215 | queryset = Comment.objects.all() 216 | serializer_class = CommentSerializer 217 | lookup_field = 'pk' 218 | 219 | 220 | 221 | 222 | class AlbumView(generics.ListCreateAPIView): 223 | queryset = Album.objects.all() 224 | serializer_class = AlbumSerializer 225 | 226 | 227 | 228 | class TrackView(generics.ListCreateAPIView): 229 | queryset = Track.objects.all() 230 | serializer_class = TrackSerializer --------------------------------------------------------------------------------