├── .gitignore ├── 02-WEB-APIs ├── 04-Requests │ ├── 00-requests.py │ ├── 01-requests.py │ └── 02-requests.py ├── First_API_Django │ └── onlinestore │ │ ├── manage.py │ │ ├── onlinestore │ │ ├── __init__.py │ │ ├── settings.py │ │ ├── urls.py │ │ └── wsgi.py │ │ └── products │ │ ├── __init__.py │ │ ├── admin.py │ │ ├── apps.py │ │ ├── migrations │ │ ├── 0001_initial.py │ │ └── __init__.py │ │ ├── models.py │ │ ├── templates │ │ └── products │ │ │ ├── product_detail.html │ │ │ └── product_list.html │ │ ├── tests.py │ │ ├── urls.py │ │ └── views.py └── requirements.txt ├── 03-DRF-LEVEL-ONE ├── job_board │ ├── job_board │ │ ├── __init__.py │ │ ├── settings.py │ │ ├── urls.py │ │ └── wsgi.py │ ├── jobs │ │ ├── __init__.py │ │ ├── admin.py │ │ ├── api │ │ │ ├── serializers.py │ │ │ ├── urls.py │ │ │ └── views.py │ │ ├── apps.py │ │ ├── migrations │ │ │ ├── 0001_initial.py │ │ │ └── __init__.py │ │ ├── models.py │ │ ├── tests.py │ │ └── views.py │ └── manage.py ├── newsapi │ ├── manage.py │ ├── news │ │ ├── __init__.py │ │ ├── admin.py │ │ ├── api │ │ │ ├── serializers.py │ │ │ ├── urls.py │ │ │ └── views.py │ │ ├── apps.py │ │ ├── migrations │ │ │ ├── 0001_initial.py │ │ │ ├── 0002_auto_20190226_1543.py │ │ │ └── __init__.py │ │ ├── models.py │ │ ├── tests.py │ │ └── views.py │ └── newsapi │ │ ├── __init__.py │ │ ├── settings.py │ │ ├── urls.py │ │ └── wsgi.py └── requirements.txt ├── 04-DRF-LEVEL-TWO ├── ebooksapi │ ├── ebooks │ │ ├── __init__.py │ │ ├── admin.py │ │ ├── api │ │ │ ├── pagination.py │ │ │ ├── permissions.py │ │ │ ├── serializers.py │ │ │ ├── urls.py │ │ │ └── views.py │ │ ├── apps.py │ │ ├── migrations │ │ │ ├── 0001_initial.py │ │ │ ├── 0002_auto_20190305_1721.py │ │ │ └── __init__.py │ │ ├── models.py │ │ ├── tests.py │ │ └── views.py │ ├── ebooksapi │ │ ├── __init__.py │ │ ├── settings.py │ │ ├── urls.py │ │ └── wsgi.py │ └── manage.py ├── quotesapi │ ├── manage.py │ ├── quotes │ │ ├── __init__.py │ │ ├── admin.py │ │ ├── api │ │ │ ├── permissions.py │ │ │ ├── serializers.py │ │ │ ├── urls.py │ │ │ └── views.py │ │ ├── apps.py │ │ ├── migrations │ │ │ ├── 0001_initial.py │ │ │ └── __init__.py │ │ ├── models.py │ │ ├── tests.py │ │ └── views.py │ └── quotesapi │ │ ├── __init__.py │ │ ├── settings.py │ │ ├── urls.py │ │ └── wsgi.py └── requirements.txt ├── 05-DRF-LEVEL-THREE ├── profilesapi │ ├── clients │ │ └── client_app.py │ ├── manage.py │ ├── profiles │ │ ├── __init__.py │ │ ├── admin.py │ │ ├── api │ │ │ ├── permissions.py │ │ │ ├── serializers.py │ │ │ ├── urls.py │ │ │ └── views.py │ │ ├── apps.py │ │ ├── migrations │ │ │ ├── 0001_initial.py │ │ │ ├── 0002_alter_profile_id_alter_profilestatus_id.py │ │ │ └── __init__.py │ │ ├── models.py │ │ ├── signals.py │ │ ├── tests.py │ │ └── views.py │ └── profilesapi │ │ ├── __init__.py │ │ ├── settings.py │ │ ├── urls.py │ │ └── wsgi.py └── requirements.txt ├── 06-Vue-JS ├── 03_First_Vue_Instance │ ├── hello_vue.html │ └── main.js ├── 04_Events_and_Methods │ ├── events_and_methods.html │ └── main.js ├── 05_Conditional_Rendering │ ├── conditional_rendering-1.html │ ├── conditional_rendering-2.html │ ├── main-1.js │ └── main-2.js ├── 06_Class_and_Style_Binding │ ├── class_and_style_binding.html │ └── main.js ├── 07_List_Rendering │ ├── list_rendering.html │ └── main.js ├── 08_Computed_Properties │ ├── computed_properties.html │ └── main.js ├── 09_Forms_and_User_Input │ ├── forms_and_user_input-0.html │ ├── forms_and_user_input.html │ ├── main-0.js │ └── main.js ├── 10_Components_and_Props │ ├── components_and_props.html │ └── main.js ├── 11_How_To_Use_Emit │ ├── components_and_emit.html │ └── main.js └── 12-13_Competency_Assessment │ ├── to_do_application.html │ └── todo.js └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | .pytest_cache/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | db.sqlite3 58 | 59 | # Flask stuff: 60 | instance/ 61 | .webassets-cache 62 | 63 | # Scrapy stuff: 64 | .scrapy 65 | 66 | # Sphinx documentation 67 | docs/_build/ 68 | 69 | # PyBuilder 70 | target/ 71 | 72 | # Jupyter Notebook 73 | .ipynb_checkpoints 74 | 75 | # pyenv 76 | .python-version 77 | 78 | # celery beat schedule file 79 | celerybeat-schedule 80 | 81 | # SageMath parsed files 82 | *.sage.py 83 | 84 | # Environments 85 | .env 86 | .venv 87 | env/ 88 | venv/ 89 | ENV/ 90 | env.bak/ 91 | venv.bak/ 92 | 93 | # Spyder project settings 94 | .spyderproject 95 | .spyproject 96 | 97 | # Rope project settings 98 | .ropeproject 99 | 100 | # mkdocs documentation 101 | /site 102 | 103 | # mypy 104 | .mypy_cache/ 105 | 106 | .vscode/ 107 | 108 | uploads/ 109 | -------------------------------------------------------------------------------- /02-WEB-APIs/04-Requests/00-requests.py: -------------------------------------------------------------------------------- 1 | import requests 2 | 3 | 4 | def main(): 5 | response = requests.get("https://www.google.com") 6 | # response = requests.get("https://www.google.com/random-address/") 7 | print("Status Code: ", response.status_code) 8 | # print("Headers: ", response.headers) 9 | # print("'Content-Type': ", response.headers['Content-Type']) 10 | print("Content: ", response.text) 11 | 12 | 13 | if __name__ == "__main__": 14 | main() 15 | -------------------------------------------------------------------------------- /02-WEB-APIs/04-Requests/01-requests.py: -------------------------------------------------------------------------------- 1 | """ 2 | Note: we are using a free API that provides data on the exchange rates of different currencies. 3 | Access to this API might be limited in the future, and providing a valid API key might be required to access the API. 4 | We are in no way affiliated with the API provider, and we are not responsible for any changes to the API. 5 | 6 | Keeping the code up to date with a working hardcoded API endpoint goes beyond the scope of this code and the course itself. 7 | You can find a list of public APIs here: https://github.com/public-apis/public-apis 8 | """ 9 | 10 | import requests 11 | 12 | 13 | def main(): 14 | response = requests.get("https://api.frankfurter.app/latest") 15 | 16 | if response.status_code != 200: 17 | print("Status Code: ", response.status_code) 18 | raise Exception("There was an error!") 19 | 20 | data = response.json() 21 | print("JSON data: ", data) 22 | 23 | 24 | if __name__ == "__main__": 25 | main() 26 | -------------------------------------------------------------------------------- /02-WEB-APIs/04-Requests/02-requests.py: -------------------------------------------------------------------------------- 1 | """ 2 | Note: we are using a free API that provides data on the exchange rates of different currencies. 3 | Access to this API might be limited in the future, and providing a valid API key might be required to access the API. 4 | We are in no way affiliated with the API provider, and we are not responsible for any changes to the API. 5 | 6 | Keeping the code up to date with a working hardcoded API endpoint goes beyond the scope of this code and the course itself. 7 | You can find a list of public APIs here: https://github.com/public-apis/public-apis 8 | """ 9 | 10 | import requests 11 | 12 | 13 | def main(): 14 | # response = requests.get("https://api.frankfurter.app/latest?from=USD&to=GBP") 15 | 16 | payload = {"base": "USD", "symbols": "EUR"} 17 | response = requests.get("https://api.frankfurter.app/latest", params=payload) 18 | 19 | if response.status_code != 200: 20 | print("Status Code: ", response.status_code) 21 | raise Exception("There was an error!") 22 | 23 | data = response.json() 24 | print("JSON data: ", data) 25 | 26 | 27 | if __name__ == "__main__": 28 | main() 29 | -------------------------------------------------------------------------------- /02-WEB-APIs/First_API_Django/onlinestore/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == '__main__': 6 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'onlinestore.settings') 7 | try: 8 | from django.core.management import execute_from_command_line 9 | except ImportError as exc: 10 | raise ImportError( 11 | "Couldn't import Django. Are you sure it's installed and " 12 | "available on your PYTHONPATH environment variable? Did you " 13 | "forget to activate a virtual environment?" 14 | ) from exc 15 | execute_from_command_line(sys.argv) 16 | -------------------------------------------------------------------------------- /02-WEB-APIs/First_API_Django/onlinestore/onlinestore/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pymike00/The-Complete-Guide-To-DRF-and-VueJS/1b995ce757d7bd1b4df7b5e37f9d6fc51f1ca4eb/02-WEB-APIs/First_API_Django/onlinestore/onlinestore/__init__.py -------------------------------------------------------------------------------- /02-WEB-APIs/First_API_Django/onlinestore/onlinestore/settings.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...) 4 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 5 | 6 | # Quick-start development settings - unsuitable for production 7 | # See https://docs.djangoproject.com/en/4.1/howto/deployment/checklist/ 8 | 9 | # SECURITY WARNING: keep the secret key used in production secret! 10 | SECRET_KEY = '^g05o)w1eeb9sf#=o2%nh8l((&nmhwr(2rvj$ep0&js=q6!na+' 11 | 12 | # SECURITY WARNING: don't run with debug turned on in production! 13 | DEBUG = True 14 | 15 | ALLOWED_HOSTS = [] 16 | 17 | 18 | # Application definition 19 | 20 | INSTALLED_APPS = [ 21 | 'django.contrib.admin', 22 | 'django.contrib.auth', 23 | 'django.contrib.contenttypes', 24 | 'django.contrib.sessions', 25 | 'django.contrib.messages', 26 | 'django.contrib.staticfiles', 27 | 28 | 'products' 29 | ] 30 | 31 | MIDDLEWARE = [ 32 | 'django.middleware.security.SecurityMiddleware', 33 | 'django.contrib.sessions.middleware.SessionMiddleware', 34 | 'django.middleware.common.CommonMiddleware', 35 | 'django.middleware.csrf.CsrfViewMiddleware', 36 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 37 | 'django.contrib.messages.middleware.MessageMiddleware', 38 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 39 | ] 40 | 41 | ROOT_URLCONF = 'onlinestore.urls' 42 | 43 | TEMPLATES = [ 44 | { 45 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 46 | 'DIRS': [], 47 | 'APP_DIRS': True, 48 | 'OPTIONS': { 49 | 'context_processors': [ 50 | 'django.template.context_processors.debug', 51 | 'django.template.context_processors.request', 52 | 'django.contrib.auth.context_processors.auth', 53 | 'django.contrib.messages.context_processors.messages', 54 | ], 55 | }, 56 | }, 57 | ] 58 | 59 | WSGI_APPLICATION = 'onlinestore.wsgi.application' 60 | 61 | DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' 62 | 63 | # Database 64 | # https://docs.djangoproject.com/en/4.1/ref/settings/#databases 65 | 66 | DATABASES = { 67 | 'default': { 68 | 'ENGINE': 'django.db.backends.sqlite3', 69 | 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 70 | } 71 | } 72 | 73 | 74 | # Password validation 75 | # https://docs.djangoproject.com/en/4.1/ref/settings/#auth-password-validators 76 | 77 | AUTH_PASSWORD_VALIDATORS = [ 78 | { 79 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 80 | }, 81 | { 82 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 83 | }, 84 | { 85 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 86 | }, 87 | { 88 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 89 | }, 90 | ] 91 | 92 | 93 | # Internationalization 94 | # https://docs.djangoproject.com/en/4.1/topics/i18n/ 95 | 96 | LANGUAGE_CODE = 'en-us' 97 | 98 | TIME_ZONE = 'UTC' 99 | 100 | USE_I18N = True 101 | 102 | USE_L10N = True 103 | 104 | USE_TZ = True 105 | 106 | 107 | # Static files (CSS, JavaScript, Images) 108 | # https://docs.djangoproject.com/en/4.1/howto/static-files/ 109 | 110 | STATIC_URL = '/static/' 111 | 112 | MEDIA_ROOT = "uploads" 113 | MEDIA_URL = "/media/" 114 | -------------------------------------------------------------------------------- /02-WEB-APIs/First_API_Django/onlinestore/onlinestore/urls.py: -------------------------------------------------------------------------------- 1 | """onlinestore URL Configuration 2 | 3 | The `urlpatterns` list routes URLs to views. For more information please see: 4 | https://docs.djangoproject.com/en/4.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.conf.urls.static import static 17 | from django.conf import settings 18 | from django.contrib import admin 19 | from django.urls import include, path 20 | 21 | 22 | urlpatterns = [ 23 | path('admin/', admin.site.urls), 24 | path("api/", include("products.urls")) 25 | ] 26 | 27 | if settings.DEBUG: 28 | urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) 29 | -------------------------------------------------------------------------------- /02-WEB-APIs/First_API_Django/onlinestore/onlinestore/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for onlinestore 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/4.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', 'onlinestore.settings') 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /02-WEB-APIs/First_API_Django/onlinestore/products/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pymike00/The-Complete-Guide-To-DRF-and-VueJS/1b995ce757d7bd1b4df7b5e37f9d6fc51f1ca4eb/02-WEB-APIs/First_API_Django/onlinestore/products/__init__.py -------------------------------------------------------------------------------- /02-WEB-APIs/First_API_Django/onlinestore/products/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | from .models import Product, Manufacturer 4 | 5 | admin.site.register(Product) 6 | admin.site.register(Manufacturer) -------------------------------------------------------------------------------- /02-WEB-APIs/First_API_Django/onlinestore/products/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class ProductsConfig(AppConfig): 5 | name = 'products' 6 | -------------------------------------------------------------------------------- /02-WEB-APIs/First_API_Django/onlinestore/products/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.1.7 on 2019-02-13 14:47 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='Manufacturer', 17 | fields=[ 18 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 19 | ('name', models.CharField(max_length=120)), 20 | ('location', models.CharField(max_length=120)), 21 | ('active', models.BooleanField(default=True)), 22 | ], 23 | ), 24 | migrations.CreateModel( 25 | name='Product', 26 | fields=[ 27 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 28 | ('name', models.CharField(max_length=120)), 29 | ('description', models.TextField(blank=True, null=True)), 30 | ('photo', models.ImageField(blank=True, null=True, upload_to='')), 31 | ('price', models.FloatField()), 32 | ('shipping_cost', models.FloatField()), 33 | ('quantity', models.PositiveSmallIntegerField()), 34 | ('manufacturer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='products', to='products.Manufacturer')), 35 | ], 36 | ), 37 | ] 38 | -------------------------------------------------------------------------------- /02-WEB-APIs/First_API_Django/onlinestore/products/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pymike00/The-Complete-Guide-To-DRF-and-VueJS/1b995ce757d7bd1b4df7b5e37f9d6fc51f1ca4eb/02-WEB-APIs/First_API_Django/onlinestore/products/migrations/__init__.py -------------------------------------------------------------------------------- /02-WEB-APIs/First_API_Django/onlinestore/products/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | class Manufacturer(models.Model): 4 | name = models.CharField(max_length=120) 5 | location = models.CharField(max_length=120) 6 | active = models.BooleanField(default=True) 7 | 8 | def __str__(self): 9 | return self.name 10 | 11 | 12 | class Product(models.Model): 13 | manufacturer = models.ForeignKey(Manufacturer, 14 | on_delete=models.CASCADE, 15 | related_name="products") 16 | name = models.CharField(max_length=120) 17 | description = models.TextField(blank=True, null=True) 18 | photo = models.ImageField(blank=True, null=True) 19 | price = models.FloatField() 20 | shipping_cost = models.FloatField() 21 | quantity = models.PositiveSmallIntegerField() 22 | 23 | def __str__(self): 24 | return self.name 25 | -------------------------------------------------------------------------------- /02-WEB-APIs/First_API_Django/onlinestore/products/templates/products/product_detail.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | {{ object.name }} 8 | 9 | 10 |

Product: {{ object.name }}

11 |

Manufacturer: {{ object.manufacturer }}

12 |

Quantity: {{ object.quantity }}

13 |

Description: {{ object.description }}

14 |

Price: {{ object.price }}

15 |

Shipping Cost: {{ object.shipping_cost }} Dollars

16 | 17 | product photo 18 | 19 | -------------------------------------------------------------------------------- /02-WEB-APIs/First_API_Django/onlinestore/products/templates/products/product_list.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Product List 8 | 9 | 10 | 11 | {% for object in object_list %} 12 |

Product: {{ object.name }}

13 |

Manufacturer: {{ object.manufacturer }}

14 |

Price: {{ object.price }}

15 | {% endfor %} 16 | 17 | 18 | -------------------------------------------------------------------------------- /02-WEB-APIs/First_API_Django/onlinestore/products/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /02-WEB-APIs/First_API_Django/onlinestore/products/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | from .views import (manufacturer_detail, manufacturer_list, 3 | product_detail, product_list) 4 | 5 | urlpatterns = [ 6 | path("products/", product_list, name="product-list"), 7 | path("products//", product_detail, name="product-detail"), 8 | 9 | path("manufacturers/", manufacturer_list, name="manufacturer-list"), 10 | path("manufacturers//", manufacturer_detail, name="manufacturer-detail") 11 | ] -------------------------------------------------------------------------------- /02-WEB-APIs/First_API_Django/onlinestore/products/views.py: -------------------------------------------------------------------------------- 1 | from django.http import JsonResponse 2 | 3 | from .models import Manufacturer, Product 4 | 5 | 6 | def product_list(request): 7 | products = Product.objects.all() # [:30] 8 | data = {"products": list(products.values())} # .values("pk", "name") 9 | response = JsonResponse(data) 10 | return response 11 | 12 | 13 | def product_detail(request, pk): 14 | try: 15 | product = Product.objects.get(pk=pk) 16 | except Product.DoesNotExist: 17 | response = JsonResponse( 18 | {"error": {"code": 404, "message": "product not found!"}}, status=404 19 | ) 20 | else: 21 | data = { 22 | "product": { 23 | "name": product.name, 24 | "manufacturer": product.manufacturer.name, 25 | "description": product.description, 26 | "photo": product.photo.url, 27 | "price": product.price, 28 | "shipping_cost": product.shipping_cost, 29 | "quantity": product.quantity, 30 | } 31 | } 32 | response = JsonResponse(data) 33 | return response 34 | 35 | 36 | def manufacturer_list(request): 37 | manufacturers = Manufacturer.objects.filter(active=True) 38 | data = {"manufacturers": list(manufacturers.values())} 39 | response = JsonResponse(data) 40 | return response 41 | 42 | 43 | def manufacturer_detail(request, pk): 44 | try: 45 | manufacturer = Manufacturer.objects.get(pk=pk) 46 | except Manufacturer.DoesNotExist: 47 | response = JsonResponse( 48 | {"error": {"code": 404, "message": "manufacturer not found!"}}, status=404 49 | ) 50 | else: 51 | manufacturer_products = manufacturer.products.all() 52 | data = { 53 | "manufacturer": { 54 | "name": manufacturer.name, 55 | "location": manufacturer.location, 56 | "active": manufacturer.active, 57 | "products": list(manufacturer_products.values()), 58 | } 59 | } 60 | response = JsonResponse(data) 61 | return response 62 | 63 | 64 | # from django.views.generic.detail import DetailView 65 | # from django.views.generic.list import ListView 66 | 67 | # class ProductDetailView(DetailView): 68 | # model = Product 69 | # template_name = "products/product_detail.html" 70 | 71 | 72 | # class ProductListView(ListView): 73 | # model = Product 74 | # template_name = "products/product_list.html" -------------------------------------------------------------------------------- /02-WEB-APIs/requirements.txt: -------------------------------------------------------------------------------- 1 | django>=4.2,<4.3 2 | pillow>=9.5.0,<9.6.0 -------------------------------------------------------------------------------- /03-DRF-LEVEL-ONE/job_board/job_board/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pymike00/The-Complete-Guide-To-DRF-and-VueJS/1b995ce757d7bd1b4df7b5e37f9d6fc51f1ca4eb/03-DRF-LEVEL-ONE/job_board/job_board/__init__.py -------------------------------------------------------------------------------- /03-DRF-LEVEL-ONE/job_board/job_board/settings.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...) 4 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 5 | 6 | 7 | # Quick-start development settings - unsuitable for production 8 | # See https://docs.djangoproject.com/en/4.1/howto/deployment/checklist/ 9 | 10 | # SECURITY WARNING: keep the secret key used in production secret! 11 | SECRET_KEY = 'pk-s!px6$qa8d74!_vl$ddqj#=&+-wf^@n6&5fybcth+u%q4mp' 12 | 13 | # SECURITY WARNING: don't run with debug turned on in production! 14 | DEBUG = True 15 | 16 | ALLOWED_HOSTS = [] 17 | 18 | 19 | # Application definition 20 | 21 | INSTALLED_APPS = [ 22 | 'django.contrib.admin', 23 | 'django.contrib.auth', 24 | 'django.contrib.contenttypes', 25 | 'django.contrib.sessions', 26 | 'django.contrib.messages', 27 | 'django.contrib.staticfiles', 28 | 29 | 'rest_framework', 30 | 31 | 'jobs' 32 | ] 33 | 34 | MIDDLEWARE = [ 35 | 'django.middleware.security.SecurityMiddleware', 36 | 'django.contrib.sessions.middleware.SessionMiddleware', 37 | 'django.middleware.common.CommonMiddleware', 38 | 'django.middleware.csrf.CsrfViewMiddleware', 39 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 40 | 'django.contrib.messages.middleware.MessageMiddleware', 41 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 42 | ] 43 | 44 | ROOT_URLCONF = 'job_board.urls' 45 | 46 | TEMPLATES = [ 47 | { 48 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 49 | 'DIRS': [], 50 | 'APP_DIRS': True, 51 | 'OPTIONS': { 52 | 'context_processors': [ 53 | 'django.template.context_processors.debug', 54 | 'django.template.context_processors.request', 55 | 'django.contrib.auth.context_processors.auth', 56 | 'django.contrib.messages.context_processors.messages', 57 | ], 58 | }, 59 | }, 60 | ] 61 | 62 | WSGI_APPLICATION = 'job_board.wsgi.application' 63 | 64 | DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' 65 | 66 | # Database 67 | # https://docs.djangoproject.com/en/4.1/ref/settings/#databases 68 | 69 | DATABASES = { 70 | 'default': { 71 | 'ENGINE': 'django.db.backends.sqlite3', 72 | 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 73 | } 74 | } 75 | 76 | 77 | # Password validation 78 | # https://docs.djangoproject.com/en/4.1/ref/settings/#auth-password-validators 79 | 80 | AUTH_PASSWORD_VALIDATORS = [ 81 | { 82 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 83 | }, 84 | { 85 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 86 | }, 87 | { 88 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 89 | }, 90 | { 91 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 92 | }, 93 | ] 94 | 95 | 96 | # Internationalization 97 | # https://docs.djangoproject.com/en/4.1/topics/i18n/ 98 | 99 | LANGUAGE_CODE = 'en-us' 100 | 101 | TIME_ZONE = 'UTC' 102 | 103 | USE_I18N = True 104 | 105 | USE_L10N = True 106 | 107 | USE_TZ = True 108 | 109 | 110 | # Static files (CSS, JavaScript, Images) 111 | # https://docs.djangoproject.com/en/4.1/howto/static-files/ 112 | 113 | STATIC_URL = '/static/' 114 | -------------------------------------------------------------------------------- /03-DRF-LEVEL-ONE/job_board/job_board/urls.py: -------------------------------------------------------------------------------- 1 | """job_board URL Configuration 2 | 3 | The `urlpatterns` list routes URLs to views. For more information please see: 4 | https://docs.djangoproject.com/en/4.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 include, path 18 | 19 | urlpatterns = [ 20 | path('admin/', admin.site.urls), 21 | path("api/", include("jobs.api.urls")) 22 | ] 23 | -------------------------------------------------------------------------------- /03-DRF-LEVEL-ONE/job_board/job_board/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for job_board 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/4.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', 'job_board.settings') 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /03-DRF-LEVEL-ONE/job_board/jobs/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pymike00/The-Complete-Guide-To-DRF-and-VueJS/1b995ce757d7bd1b4df7b5e37f9d6fc51f1ca4eb/03-DRF-LEVEL-ONE/job_board/jobs/__init__.py -------------------------------------------------------------------------------- /03-DRF-LEVEL-ONE/job_board/jobs/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from jobs.models import JobOffer 3 | 4 | admin.site.register(JobOffer) 5 | -------------------------------------------------------------------------------- /03-DRF-LEVEL-ONE/job_board/jobs/api/serializers.py: -------------------------------------------------------------------------------- 1 | from rest_framework import serializers 2 | from jobs.models import JobOffer 3 | 4 | 5 | class JobOfferSerializer(serializers.ModelSerializer): 6 | 7 | class Meta: 8 | model = JobOffer 9 | fields = "__all__" -------------------------------------------------------------------------------- /03-DRF-LEVEL-ONE/job_board/jobs/api/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | from jobs.api.views import (JobOfferDetailAPIView, 3 | JobOfferListCreateAPIView) 4 | 5 | urlpatterns = [ 6 | path("jobs/", 7 | JobOfferListCreateAPIView.as_view(), 8 | name="job-list"), 9 | 10 | path("jobs//", 11 | JobOfferDetailAPIView.as_view(), 12 | name="job-detail"), 13 | ] -------------------------------------------------------------------------------- /03-DRF-LEVEL-ONE/job_board/jobs/api/views.py: -------------------------------------------------------------------------------- 1 | from rest_framework import status 2 | from rest_framework.generics import get_object_or_404 3 | from rest_framework.response import Response 4 | from rest_framework.views import APIView 5 | 6 | from jobs.models import JobOffer 7 | from jobs.api.serializers import JobOfferSerializer 8 | 9 | 10 | class JobOfferListCreateAPIView(APIView): 11 | 12 | def get(self, request): 13 | jobs = JobOffer.objects.filter(available=True) 14 | serializer = JobOfferSerializer(jobs, many=True) 15 | return Response(serializer.data) 16 | 17 | def post(self, request): 18 | serializer = JobOfferSerializer(data=request.data) 19 | if serializer.is_valid(): 20 | serializer.save() 21 | return Response(serializer.data, status=status.HTTP_201_CREATED) 22 | return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) 23 | 24 | 25 | class JobOfferDetailAPIView(APIView): 26 | 27 | def get_object(self, pk): 28 | job = get_object_or_404(JobOffer, pk=pk) 29 | return job 30 | 31 | def get(self, request, pk): 32 | job = self.get_object(pk) 33 | serializer = JobOfferSerializer(job) 34 | return Response(serializer.data) 35 | 36 | def put(self, request, pk): 37 | job = self.get_object(pk) 38 | serializer = JobOfferSerializer(job, data=request.data) 39 | if serializer.is_valid(): 40 | serializer.save() 41 | return Response(serializer.data) 42 | return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) 43 | 44 | def delete(self, request, pk): 45 | job = self.get_object(pk) 46 | job.delete() 47 | return Response(status=status.HTTP_204_NO_CONTENT) -------------------------------------------------------------------------------- /03-DRF-LEVEL-ONE/job_board/jobs/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class JobsConfig(AppConfig): 5 | name = 'jobs' 6 | -------------------------------------------------------------------------------- /03-DRF-LEVEL-ONE/job_board/jobs/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.1.7 on 2019-02-26 18:52 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='JobOffer', 16 | fields=[ 17 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 18 | ('company_name', models.CharField(max_length=50)), 19 | ('company_email', models.EmailField(max_length=254)), 20 | ('job_title', models.CharField(max_length=60)), 21 | ('job_description', models.TextField()), 22 | ('salary', models.PositiveIntegerField()), 23 | ('city', models.CharField(max_length=35)), 24 | ('state', models.CharField(max_length=35)), 25 | ('created_at', models.DateField(auto_now_add=True)), 26 | ('available', models.BooleanField(default=True)), 27 | ], 28 | ), 29 | ] 30 | -------------------------------------------------------------------------------- /03-DRF-LEVEL-ONE/job_board/jobs/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pymike00/The-Complete-Guide-To-DRF-and-VueJS/1b995ce757d7bd1b4df7b5e37f9d6fc51f1ca4eb/03-DRF-LEVEL-ONE/job_board/jobs/migrations/__init__.py -------------------------------------------------------------------------------- /03-DRF-LEVEL-ONE/job_board/jobs/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | 4 | class JobOffer(models.Model): 5 | company_name = models.CharField(max_length=50) 6 | company_email = models.EmailField() 7 | job_title = models.CharField(max_length=60) 8 | job_description = models.TextField() 9 | salary = models.PositiveIntegerField() 10 | city = models.CharField(max_length=35) 11 | state = models.CharField(max_length=35) 12 | created_at = models.DateField(auto_now_add=True) 13 | available = models.BooleanField(default=True) 14 | 15 | def __str__(self): 16 | return self.company_name 17 | -------------------------------------------------------------------------------- /03-DRF-LEVEL-ONE/job_board/jobs/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /03-DRF-LEVEL-ONE/job_board/jobs/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render 2 | 3 | # Create your views here. 4 | -------------------------------------------------------------------------------- /03-DRF-LEVEL-ONE/job_board/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == '__main__': 6 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'job_board.settings') 7 | try: 8 | from django.core.management import execute_from_command_line 9 | except ImportError as exc: 10 | raise ImportError( 11 | "Couldn't import Django. Are you sure it's installed and " 12 | "available on your PYTHONPATH environment variable? Did you " 13 | "forget to activate a virtual environment?" 14 | ) from exc 15 | execute_from_command_line(sys.argv) 16 | -------------------------------------------------------------------------------- /03-DRF-LEVEL-ONE/newsapi/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == '__main__': 6 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'newsapi.settings') 7 | try: 8 | from django.core.management import execute_from_command_line 9 | except ImportError as exc: 10 | raise ImportError( 11 | "Couldn't import Django. Are you sure it's installed and " 12 | "available on your PYTHONPATH environment variable? Did you " 13 | "forget to activate a virtual environment?" 14 | ) from exc 15 | execute_from_command_line(sys.argv) 16 | -------------------------------------------------------------------------------- /03-DRF-LEVEL-ONE/newsapi/news/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pymike00/The-Complete-Guide-To-DRF-and-VueJS/1b995ce757d7bd1b4df7b5e37f9d6fc51f1ca4eb/03-DRF-LEVEL-ONE/newsapi/news/__init__.py -------------------------------------------------------------------------------- /03-DRF-LEVEL-ONE/newsapi/news/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from news.models import Article, Journalist 3 | 4 | admin.site.register(Article) 5 | admin.site.register(Journalist) 6 | -------------------------------------------------------------------------------- /03-DRF-LEVEL-ONE/newsapi/news/api/serializers.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | from django.utils.timesince import timesince 3 | from rest_framework import serializers 4 | from news.models import Article, Journalist 5 | 6 | 7 | class ArticleSerializer(serializers.ModelSerializer): 8 | 9 | time_since_publication = serializers.SerializerMethodField() 10 | # author = JournalistSerializer(read_only=True) 11 | # author = serializers.StringRelatedField() 12 | 13 | class Meta: 14 | model = Article 15 | exclude = ("id",) 16 | # fields = "__all__" # we want all the fields of our model 17 | # fields = ("title", "description", "body") # we want to choose a couple of fields! 18 | 19 | def get_time_since_publication(self, object): 20 | publication_date = object.publication_date 21 | now = datetime.now() 22 | time_delta = timesince(publication_date, now) 23 | return time_delta 24 | 25 | def validate(self, data): 26 | """ check that description and title are different 27 | https://www.django-rest-framework.org/api-guide/serializers/#object-level-validation 28 | """ 29 | if data["title"] == data["description"]: 30 | raise serializers.ValidationError("Title and Description must be different from one another!") 31 | return data 32 | 33 | def validate_title(self, value): 34 | """ check that title is at least 30 chars long 35 | https://www.django-rest-framework.org/api-guide/serializers/#field-level-validation 36 | """ 37 | if len(value) < 30: 38 | raise serializers.ValidationError("The title has to be at least 30 chars long!") 39 | return value 40 | 41 | 42 | class JournalistSerializer(serializers.ModelSerializer): 43 | articles = serializers.HyperlinkedRelatedField(many=True, 44 | read_only=True, 45 | view_name="article-detail") 46 | # articles = ArticleSerializer(many=True, read_only=True) 47 | 48 | class Meta: 49 | model = Journalist 50 | fields = "__all__" 51 | 52 | 53 | # class ArticleSerializer(serializers.Serializer): 54 | # id = serializers.IntegerField(read_only=True) 55 | # author = serializers.CharField() 56 | # title = serializers.CharField() 57 | # description = serializers.CharField() 58 | # body = serializers.CharField() 59 | # location = serializers.CharField() 60 | # publication_date = serializers.DateField() 61 | # active = serializers.BooleanField() 62 | # created_at = serializers.DateTimeField(read_only=True) 63 | # updated_at = serializers.DateTimeField(read_only=True) 64 | 65 | # def create(self, validated_data): 66 | # print(validated_data) 67 | # return Article.objects.create(**validated_data) 68 | 69 | # def update(self, instance, validated_data): 70 | # instance.author = validated_data.get('author', instance.author) 71 | # instance.title = validated_data.get('title', instance.title) 72 | # instance.description = validated_data.get('description', 73 | # instance.description) 74 | # instance.body = validated_data.get('body', instance.body) 75 | # instance.location = validated_data.get('location', instance.location) 76 | # instance.publication_date = validated_data.get('publication_data', 77 | # instance.publication_date) 78 | # instance.active = validated_data.get('active', instance.active) 79 | # instance.save() 80 | # return instance 81 | 82 | # def validate(self, data): 83 | # """ check that description and title are different 84 | # https://www.django-rest-framework.org/api-guide/serializers/#object-level-validation 85 | # """ 86 | # if data["title"] == data["description"]: 87 | # raise serializers.ValidationError("Title and Description must be different from one another!") 88 | # return data 89 | 90 | # def validate_title(self, value): 91 | # """ check that title is at least 60 chars long 92 | # https://www.django-rest-framework.org/api-guide/serializers/#field-level-validation 93 | # """ 94 | # if len(value) < 60: 95 | # raise serializers.ValidationError("The title has to be at least 60 chars long!") 96 | # return value 97 | -------------------------------------------------------------------------------- /03-DRF-LEVEL-ONE/newsapi/news/api/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | from news.api.views import (ArticleDetailAPIView, ArticleListCreateAPIView, 3 | JournalistListCreateAPIView) 4 | # from news.api.views import (article_detail_api_view, 5 | # article_list_create_api_view) 6 | 7 | urlpatterns = [ 8 | path("articles/", 9 | ArticleListCreateAPIView.as_view(), 10 | name="article-list"), 11 | 12 | path("articles//", 13 | ArticleDetailAPIView.as_view(), 14 | name="article-detail"), 15 | 16 | path("journalists/", 17 | JournalistListCreateAPIView.as_view(), 18 | name="journalist-list") 19 | # path("articles/", article_list_create_api_view, name="article-list"), 20 | # path("articles//", article_detail_api_view, name="article-detail") 21 | ] -------------------------------------------------------------------------------- /03-DRF-LEVEL-ONE/newsapi/news/api/views.py: -------------------------------------------------------------------------------- 1 | from rest_framework import status 2 | from rest_framework.decorators import api_view 3 | from rest_framework.views import APIView 4 | from rest_framework.response import Response 5 | from rest_framework.generics import get_object_or_404 6 | 7 | from news.models import Article, Journalist 8 | from news.api.serializers import ArticleSerializer, JournalistSerializer 9 | 10 | 11 | class ArticleListCreateAPIView(APIView): 12 | 13 | def get(self, request): 14 | articles = Article.objects.filter(active=True) 15 | serializer = ArticleSerializer(articles, many=True) 16 | return Response(serializer.data) 17 | 18 | def post(self, request): 19 | serializer = ArticleSerializer(data=request.data) 20 | if serializer.is_valid(): 21 | serializer.save() 22 | return Response(serializer.data, status=status.HTTP_201_CREATED) 23 | return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) 24 | 25 | 26 | class ArticleDetailAPIView(APIView): 27 | 28 | def get_object(self, pk): 29 | article = get_object_or_404(Article, pk=pk) 30 | return article 31 | 32 | def get(self, request, pk): 33 | article = self.get_object(pk) 34 | serializer = ArticleSerializer(article) 35 | return Response(serializer.data) 36 | 37 | def put(self, request, pk): 38 | article = self.get_object(pk) 39 | serializer = ArticleSerializer(article, data=request.data) 40 | if serializer.is_valid(): 41 | serializer.save() 42 | return Response(serializer.data) 43 | return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) 44 | 45 | def delete(self, request, pk): 46 | article = self.get_object(pk) 47 | article.delete() 48 | return Response(status=status.HTTP_204_NO_CONTENT) 49 | 50 | 51 | class JournalistListCreateAPIView(APIView): 52 | 53 | def get(self, request): 54 | journalists = Journalist.objects.all() 55 | serializer = JournalistSerializer(journalists, 56 | many=True, 57 | context={'request': request}) 58 | return Response(serializer.data) 59 | 60 | def post(self, request): 61 | serializer = JournalistSerializer(data=request.data) 62 | if serializer.is_valid(): 63 | serializer.save() 64 | return Response(serializer.data, status=status.HTTP_201_CREATED) 65 | return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) 66 | 67 | 68 | # @api_view(["GET", "POST"]) 69 | # def article_list_create_api_view(request): 70 | 71 | # if request.method == "GET": 72 | # articles = Article.objects.filter(active=True) 73 | # serializer = ArticleSerializer(articles, many=True) 74 | # return Response(serializer.data) 75 | 76 | # elif request.method == "POST": 77 | # serializer = ArticleSerializer(data=request.data) 78 | # if serializer.is_valid(): 79 | # serializer.save() 80 | # return Response(serializer.data, status=status.HTTP_201_CREATED) 81 | # return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) 82 | 83 | # @api_view(["GET", "PUT", "DELETE"]) 84 | # def article_detail_api_view(request, pk): 85 | # try: 86 | # article = Article.objects.get(pk=pk) 87 | # except Article.DoesNotExist: 88 | # return Response({"error": { 89 | # "code": 404, 90 | # "message": "Article not found!" 91 | # }}, status=status.HTTP_404_NOT_FOUND) 92 | 93 | # if request.method == "GET": 94 | # serializer = ArticleSerializer(article) 95 | # return Response(serializer.data) 96 | 97 | # elif request.method == "PUT": 98 | # serializer = ArticleSerializer(article, data=request.data) 99 | # if serializer.is_valid(): 100 | # serializer.save() 101 | # return Response(serializer.data) 102 | # return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) 103 | 104 | # elif request.method == "DELETE": 105 | # article.delete() 106 | # return Response(status=status.HTTP_204_NO_CONTENT) -------------------------------------------------------------------------------- /03-DRF-LEVEL-ONE/newsapi/news/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class NewsConfig(AppConfig): 5 | name = 'news' 6 | -------------------------------------------------------------------------------- /03-DRF-LEVEL-ONE/newsapi/news/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.1.7 on 2019-02-21 12:03 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='Article', 16 | fields=[ 17 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 18 | ('author', models.CharField(max_length=50)), 19 | ('title', models.CharField(max_length=120)), 20 | ('description', models.CharField(max_length=200)), 21 | ('body', models.TextField()), 22 | ('location', models.CharField(max_length=120)), 23 | ('publication_date', models.DateField()), 24 | ('active', models.BooleanField(default=True)), 25 | ('created_at', models.DateTimeField(auto_now_add=True)), 26 | ('updated_at', models.DateTimeField(auto_now=True)), 27 | ], 28 | ), 29 | ] 30 | -------------------------------------------------------------------------------- /03-DRF-LEVEL-ONE/newsapi/news/migrations/0002_auto_20190226_1543.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.1.7 on 2019-02-26 15:43 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 | ('news', '0001_initial'), 11 | ] 12 | 13 | operations = [ 14 | migrations.CreateModel( 15 | name='Journalist', 16 | fields=[ 17 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 18 | ('first_name', models.CharField(max_length=60)), 19 | ('last_name', models.CharField(max_length=60)), 20 | ('biography', models.TextField(blank=True)), 21 | ], 22 | ), 23 | migrations.AlterField( 24 | model_name='article', 25 | name='author', 26 | field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='articles', to='news.Journalist'), 27 | ), 28 | ] 29 | -------------------------------------------------------------------------------- /03-DRF-LEVEL-ONE/newsapi/news/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pymike00/The-Complete-Guide-To-DRF-and-VueJS/1b995ce757d7bd1b4df7b5e37f9d6fc51f1ca4eb/03-DRF-LEVEL-ONE/newsapi/news/migrations/__init__.py -------------------------------------------------------------------------------- /03-DRF-LEVEL-ONE/newsapi/news/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | 4 | class Journalist(models.Model): 5 | first_name = models.CharField(max_length=60) 6 | last_name = models.CharField(max_length=60) 7 | biography = models.TextField(blank=True) 8 | 9 | def __str__(self): 10 | return f"{ self.first_name } { self.last_name }" 11 | 12 | 13 | class Article(models.Model): 14 | author = models.ForeignKey(Journalist, 15 | on_delete=models.CASCADE, 16 | related_name="articles") 17 | title = models.CharField(max_length=120) 18 | description = models.CharField(max_length=200) 19 | body = models.TextField() 20 | location = models.CharField(max_length=120) 21 | publication_date = models.DateField() 22 | active = models.BooleanField(default=True) 23 | created_at = models.DateTimeField(auto_now_add=True) 24 | updated_at = models.DateTimeField(auto_now=True) 25 | 26 | def __str__(self): 27 | return f"{ self.author } { self.title }" 28 | -------------------------------------------------------------------------------- /03-DRF-LEVEL-ONE/newsapi/news/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /03-DRF-LEVEL-ONE/newsapi/news/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render 2 | 3 | # Create your views here. 4 | -------------------------------------------------------------------------------- /03-DRF-LEVEL-ONE/newsapi/newsapi/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pymike00/The-Complete-Guide-To-DRF-and-VueJS/1b995ce757d7bd1b4df7b5e37f9d6fc51f1ca4eb/03-DRF-LEVEL-ONE/newsapi/newsapi/__init__.py -------------------------------------------------------------------------------- /03-DRF-LEVEL-ONE/newsapi/newsapi/settings.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...) 4 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 5 | 6 | 7 | # Quick-start development settings - unsuitable for production 8 | # See https://docs.djangoproject.com/en/4.1/howto/deployment/checklist/ 9 | 10 | # SECURITY WARNING: keep the secret key used in production secret! 11 | SECRET_KEY = 'a!^#hmmv$9j20hfvi^wer*jd@ufcvb4m6h9%6l6m_l)4_g=c(&' 12 | 13 | # SECURITY WARNING: don't run with debug turned on in production! 14 | DEBUG = True 15 | 16 | ALLOWED_HOSTS = [] 17 | 18 | 19 | # Application definition 20 | 21 | INSTALLED_APPS = [ 22 | 'django.contrib.admin', 23 | 'django.contrib.auth', 24 | 'django.contrib.contenttypes', 25 | 'django.contrib.sessions', 26 | 'django.contrib.messages', 27 | 'django.contrib.staticfiles', 28 | 29 | 'rest_framework', 30 | 31 | 'news' 32 | ] 33 | 34 | MIDDLEWARE = [ 35 | 'django.middleware.security.SecurityMiddleware', 36 | 'django.contrib.sessions.middleware.SessionMiddleware', 37 | 'django.middleware.common.CommonMiddleware', 38 | 'django.middleware.csrf.CsrfViewMiddleware', 39 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 40 | 'django.contrib.messages.middleware.MessageMiddleware', 41 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 42 | ] 43 | 44 | ROOT_URLCONF = 'newsapi.urls' 45 | 46 | TEMPLATES = [ 47 | { 48 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 49 | 'DIRS': [], 50 | 'APP_DIRS': True, 51 | 'OPTIONS': { 52 | 'context_processors': [ 53 | 'django.template.context_processors.debug', 54 | 'django.template.context_processors.request', 55 | 'django.contrib.auth.context_processors.auth', 56 | 'django.contrib.messages.context_processors.messages', 57 | ], 58 | }, 59 | }, 60 | ] 61 | 62 | WSGI_APPLICATION = 'newsapi.wsgi.application' 63 | 64 | DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' 65 | 66 | # Database 67 | # https://docs.djangoproject.com/en/4.1/ref/settings/#databases 68 | 69 | DATABASES = { 70 | 'default': { 71 | 'ENGINE': 'django.db.backends.sqlite3', 72 | 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 73 | } 74 | } 75 | 76 | 77 | # Password validation 78 | # https://docs.djangoproject.com/en/4.1/ref/settings/#auth-password-validators 79 | 80 | AUTH_PASSWORD_VALIDATORS = [ 81 | { 82 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 83 | }, 84 | { 85 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 86 | }, 87 | { 88 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 89 | }, 90 | { 91 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 92 | }, 93 | ] 94 | 95 | 96 | # Internationalization 97 | # https://docs.djangoproject.com/en/4.1/topics/i18n/ 98 | 99 | LANGUAGE_CODE = 'en-us' 100 | 101 | TIME_ZONE = 'UTC' 102 | 103 | USE_I18N = True 104 | 105 | USE_L10N = True 106 | 107 | USE_TZ = True 108 | 109 | 110 | # Static files (CSS, JavaScript, Images) 111 | # https://docs.djangoproject.com/en/4.1/howto/static-files/ 112 | 113 | STATIC_URL = '/static/' 114 | -------------------------------------------------------------------------------- /03-DRF-LEVEL-ONE/newsapi/newsapi/urls.py: -------------------------------------------------------------------------------- 1 | """newsapi URL Configuration 2 | 3 | The `urlpatterns` list routes URLs to views. For more information please see: 4 | https://docs.djangoproject.com/en/4.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 | 19 | urlpatterns = [ 20 | path('admin/', admin.site.urls), 21 | path("api/", include("news.api.urls")) 22 | ] 23 | -------------------------------------------------------------------------------- /03-DRF-LEVEL-ONE/newsapi/newsapi/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for newsapi 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/4.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', 'newsapi.settings') 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /03-DRF-LEVEL-ONE/requirements.txt: -------------------------------------------------------------------------------- 1 | django>=4.1,<4.2 2 | djangorestframework>=3.14,<3.15 -------------------------------------------------------------------------------- /04-DRF-LEVEL-TWO/ebooksapi/ebooks/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pymike00/The-Complete-Guide-To-DRF-and-VueJS/1b995ce757d7bd1b4df7b5e37f9d6fc51f1ca4eb/04-DRF-LEVEL-TWO/ebooksapi/ebooks/__init__.py -------------------------------------------------------------------------------- /04-DRF-LEVEL-TWO/ebooksapi/ebooks/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from ebooks.models import Ebook, Review 3 | 4 | admin.site.register(Ebook) 5 | admin.site.register(Review) 6 | -------------------------------------------------------------------------------- /04-DRF-LEVEL-TWO/ebooksapi/ebooks/api/pagination.py: -------------------------------------------------------------------------------- 1 | from rest_framework.pagination import PageNumberPagination 2 | 3 | 4 | class SmallSetPagination(PageNumberPagination): 5 | page_size = 3 -------------------------------------------------------------------------------- /04-DRF-LEVEL-TWO/ebooksapi/ebooks/api/permissions.py: -------------------------------------------------------------------------------- 1 | from rest_framework import permissions 2 | 3 | 4 | class IsAdminUserOrReadOnly(permissions.IsAdminUser): 5 | 6 | def has_permission(self, request, view): 7 | is_admin = super().has_permission(request, view) 8 | return request.method in permissions.SAFE_METHODS or is_admin 9 | 10 | 11 | class IsReviewAuthorOrReadOnly(permissions.BasePermission): 12 | 13 | def has_object_permission(self, request, view, obj): 14 | if request.method in permissions.SAFE_METHODS: 15 | return True 16 | 17 | return obj.review_author == request.user -------------------------------------------------------------------------------- /04-DRF-LEVEL-TWO/ebooksapi/ebooks/api/serializers.py: -------------------------------------------------------------------------------- 1 | from rest_framework import serializers 2 | from ebooks.models import Ebook, Review 3 | 4 | 5 | class ReviewSerializer(serializers.ModelSerializer): 6 | 7 | review_author = serializers.StringRelatedField(read_only=True) 8 | 9 | class Meta: 10 | model = Review 11 | exclude = ("ebook",) 12 | # fields = "__all__" 13 | 14 | 15 | class EbookSerializer(serializers.ModelSerializer): 16 | reviews = ReviewSerializer(many=True, read_only=True) 17 | 18 | class Meta: 19 | model = Ebook 20 | fields = "__all__" -------------------------------------------------------------------------------- /04-DRF-LEVEL-TWO/ebooksapi/ebooks/api/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | from ebooks.api.views import (EbookDetailAPIView, EbookListCreateAPIView, 3 | ReviewCreateAPIView, ReviewDetailAPIView) 4 | 5 | urlpatterns = [ 6 | path("ebooks/", 7 | EbookListCreateAPIView.as_view(), 8 | name="ebook-list"), 9 | 10 | path("ebooks//", 11 | EbookDetailAPIView.as_view(), 12 | name="ebook-detail"), 13 | 14 | path("ebooks//review/", 15 | ReviewCreateAPIView.as_view(), 16 | name="ebook-review"), 17 | 18 | path("reviews//", 19 | ReviewDetailAPIView.as_view(), 20 | name="review-detail") 21 | ] -------------------------------------------------------------------------------- /04-DRF-LEVEL-TWO/ebooksapi/ebooks/api/views.py: -------------------------------------------------------------------------------- 1 | from rest_framework import generics 2 | from rest_framework import permissions 3 | from rest_framework.exceptions import ValidationError 4 | from rest_framework.generics import get_object_or_404 5 | 6 | from ebooks.models import Ebook, Review 7 | from ebooks.api.pagination import SmallSetPagination 8 | from ebooks.api.permissions import IsAdminUserOrReadOnly, IsReviewAuthorOrReadOnly 9 | from ebooks.api.serializers import EbookSerializer, ReviewSerializer 10 | 11 | 12 | class EbookListCreateAPIView(generics.ListCreateAPIView): 13 | queryset = Ebook.objects.all().order_by("id") 14 | serializer_class = EbookSerializer 15 | permission_classes = [IsAdminUserOrReadOnly] 16 | pagination_class = SmallSetPagination 17 | 18 | 19 | class EbookDetailAPIView(generics.RetrieveUpdateDestroyAPIView): 20 | queryset = Ebook.objects.all() 21 | serializer_class = EbookSerializer 22 | permission_classes = [IsAdminUserOrReadOnly] 23 | 24 | 25 | class ReviewCreateAPIView(generics.CreateAPIView): 26 | queryset = Review.objects.all() 27 | serializer_class = ReviewSerializer 28 | permission_classes = [permissions.IsAuthenticatedOrReadOnly] 29 | 30 | def perform_create(self, serializer): 31 | ebook_pk = self.kwargs.get("ebook_pk") 32 | ebook = get_object_or_404(Ebook, pk=ebook_pk) 33 | 34 | review_author = self.request.user 35 | 36 | review_queryset = Review.objects.filter(ebook=ebook, 37 | review_author=review_author) 38 | 39 | if review_queryset.exists(): 40 | raise ValidationError("You Have Already Reviewed this Ebook!") 41 | 42 | serializer.save(ebook=ebook, review_author=review_author) 43 | 44 | 45 | class ReviewDetailAPIView(generics.RetrieveUpdateDestroyAPIView): 46 | queryset = Review.objects.all() 47 | serializer_class = ReviewSerializer 48 | permission_classes = [IsReviewAuthorOrReadOnly] 49 | 50 | 51 | # class EbookListCreateAPIView(mixins.ListModelMixin, 52 | # mixins.CreateModelMixin, 53 | # generics.GenericAPIView): 54 | 55 | # queryset = Ebook.objects.all() 56 | # serializer_class = EbookSerializer 57 | 58 | # def get(self, request, *args, **kwargs): 59 | # return self.list(request, *args, **kwargs) 60 | 61 | # def post(self, request, *args, **kwargs): 62 | # return self.create(request, *args, **kwargs) -------------------------------------------------------------------------------- /04-DRF-LEVEL-TWO/ebooksapi/ebooks/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class EbooksConfig(AppConfig): 5 | name = 'ebooks' 6 | -------------------------------------------------------------------------------- /04-DRF-LEVEL-TWO/ebooksapi/ebooks/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.1.7 on 2019-02-27 13:08 2 | 3 | import django.core.validators 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 | ] 14 | 15 | operations = [ 16 | migrations.CreateModel( 17 | name='Ebook', 18 | fields=[ 19 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 20 | ('title', models.CharField(max_length=140)), 21 | ('author', models.CharField(max_length=60)), 22 | ('description', models.TextField()), 23 | ('publication_date', models.DateField()), 24 | ], 25 | ), 26 | migrations.CreateModel( 27 | name='Review', 28 | fields=[ 29 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 30 | ('created_at', models.DateTimeField(auto_now_add=True)), 31 | ('updated_at', models.DateTimeField(auto_now=True)), 32 | ('review_author', models.CharField(blank=True, max_length=8, null=True)), 33 | ('review', models.TextField(blank=True, null=True)), 34 | ('rating', models.PositiveIntegerField(validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxValueValidator(5)])), 35 | ('ebook', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='reviews', to='ebooks.Ebook')), 36 | ], 37 | ), 38 | ] 39 | -------------------------------------------------------------------------------- /04-DRF-LEVEL-TWO/ebooksapi/ebooks/migrations/0002_auto_20190305_1721.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.1.7 on 2019-03-05 17:21 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 | dependencies = [ 11 | ('ebooks', '0001_initial'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterField( 16 | model_name='review', 17 | name='review_author', 18 | field=models.ForeignKey(default=None, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), 19 | preserve_default=False, 20 | ), 21 | ] 22 | -------------------------------------------------------------------------------- /04-DRF-LEVEL-TWO/ebooksapi/ebooks/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pymike00/The-Complete-Guide-To-DRF-and-VueJS/1b995ce757d7bd1b4df7b5e37f9d6fc51f1ca4eb/04-DRF-LEVEL-TWO/ebooksapi/ebooks/migrations/__init__.py -------------------------------------------------------------------------------- /04-DRF-LEVEL-TWO/ebooksapi/ebooks/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | from django.core.validators import MinValueValidator, MaxValueValidator 3 | 4 | from django.contrib.auth.models import User 5 | 6 | 7 | class Ebook(models.Model): 8 | title = models.CharField(max_length=140) 9 | author = models.CharField(max_length=60) 10 | description = models.TextField() 11 | publication_date = models.DateField() 12 | 13 | def __str__(self): 14 | return self.title 15 | 16 | 17 | class Review(models.Model): 18 | created_at = models.DateTimeField(auto_now_add=True) 19 | updated_at = models.DateTimeField(auto_now=True) 20 | review_author = models.ForeignKey(User, on_delete=models.CASCADE) 21 | review = models.TextField(blank=True, null=True) 22 | rating = models.PositiveIntegerField(validators=[MinValueValidator(1), 23 | MaxValueValidator(5)]) 24 | ebook = models.ForeignKey(Ebook, 25 | on_delete=models.CASCADE, 26 | related_name="reviews") 27 | 28 | def __str__(self): 29 | return str(self.rating) 30 | -------------------------------------------------------------------------------- /04-DRF-LEVEL-TWO/ebooksapi/ebooks/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /04-DRF-LEVEL-TWO/ebooksapi/ebooks/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render 2 | 3 | # Create your views here. 4 | -------------------------------------------------------------------------------- /04-DRF-LEVEL-TWO/ebooksapi/ebooksapi/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pymike00/The-Complete-Guide-To-DRF-and-VueJS/1b995ce757d7bd1b4df7b5e37f9d6fc51f1ca4eb/04-DRF-LEVEL-TWO/ebooksapi/ebooksapi/__init__.py -------------------------------------------------------------------------------- /04-DRF-LEVEL-TWO/ebooksapi/ebooksapi/settings.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...) 4 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 5 | 6 | 7 | # Quick-start development settings - unsuitable for production 8 | # See https://docs.djangoproject.com/en/4.1/howto/deployment/checklist/ 9 | 10 | # SECURITY WARNING: keep the secret key used in production secret! 11 | SECRET_KEY = '-f2(p4z&=)-te2p(k548d31y5*5z399-z(b05p*z!chniw!1_a' 12 | 13 | # SECURITY WARNING: don't run with debug turned on in production! 14 | DEBUG = True 15 | 16 | ALLOWED_HOSTS = [] 17 | 18 | 19 | # Application definition 20 | 21 | INSTALLED_APPS = [ 22 | 'django.contrib.admin', 23 | 'django.contrib.auth', 24 | 'django.contrib.contenttypes', 25 | 'django.contrib.sessions', 26 | 'django.contrib.messages', 27 | 'django.contrib.staticfiles', 28 | 29 | 'rest_framework', 30 | 31 | 'ebooks' 32 | ] 33 | 34 | MIDDLEWARE = [ 35 | 'django.middleware.security.SecurityMiddleware', 36 | 'django.contrib.sessions.middleware.SessionMiddleware', 37 | 'django.middleware.common.CommonMiddleware', 38 | 'django.middleware.csrf.CsrfViewMiddleware', 39 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 40 | 'django.contrib.messages.middleware.MessageMiddleware', 41 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 42 | ] 43 | 44 | ROOT_URLCONF = 'ebooksapi.urls' 45 | 46 | TEMPLATES = [ 47 | { 48 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 49 | 'DIRS': [], 50 | 'APP_DIRS': True, 51 | 'OPTIONS': { 52 | 'context_processors': [ 53 | 'django.template.context_processors.debug', 54 | 'django.template.context_processors.request', 55 | 'django.contrib.auth.context_processors.auth', 56 | 'django.contrib.messages.context_processors.messages', 57 | ], 58 | }, 59 | }, 60 | ] 61 | 62 | WSGI_APPLICATION = 'ebooksapi.wsgi.application' 63 | 64 | DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' 65 | 66 | # Database 67 | # https://docs.djangoproject.com/en/4.1/ref/settings/#databases 68 | 69 | DATABASES = { 70 | 'default': { 71 | 'ENGINE': 'django.db.backends.sqlite3', 72 | 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 73 | } 74 | } 75 | 76 | 77 | # Password validation 78 | # https://docs.djangoproject.com/en/4.1/ref/settings/#auth-password-validators 79 | 80 | AUTH_PASSWORD_VALIDATORS = [ 81 | { 82 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 83 | }, 84 | { 85 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 86 | }, 87 | { 88 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 89 | }, 90 | { 91 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 92 | }, 93 | ] 94 | 95 | 96 | # Internationalization 97 | # https://docs.djangoproject.com/en/4.1/topics/i18n/ 98 | 99 | LANGUAGE_CODE = 'en-us' 100 | 101 | TIME_ZONE = 'UTC' 102 | 103 | USE_I18N = True 104 | 105 | USE_L10N = True 106 | 107 | USE_TZ = True 108 | 109 | 110 | # Static files (CSS, JavaScript, Images) 111 | # https://docs.djangoproject.com/en/4.1/howto/static-files/ 112 | 113 | STATIC_URL = '/static/' 114 | 115 | # REST_FRAMEWORK = { 116 | # 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination', 117 | # 'PAGE_SIZE': 3 118 | # } -------------------------------------------------------------------------------- /04-DRF-LEVEL-TWO/ebooksapi/ebooksapi/urls.py: -------------------------------------------------------------------------------- 1 | """ebooksapi URL Configuration 2 | 3 | The `urlpatterns` list routes URLs to views. For more information please see: 4 | https://docs.djangoproject.com/en/4.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 include, path 18 | 19 | urlpatterns = [ 20 | path('admin/', admin.site.urls), 21 | path('api-auth/', include("rest_framework.urls")), 22 | path("api/", include("ebooks.api.urls")) 23 | ] 24 | -------------------------------------------------------------------------------- /04-DRF-LEVEL-TWO/ebooksapi/ebooksapi/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for ebooksapi 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/4.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', 'ebooksapi.settings') 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /04-DRF-LEVEL-TWO/ebooksapi/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == '__main__': 6 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'ebooksapi.settings') 7 | try: 8 | from django.core.management import execute_from_command_line 9 | except ImportError as exc: 10 | raise ImportError( 11 | "Couldn't import Django. Are you sure it's installed and " 12 | "available on your PYTHONPATH environment variable? Did you " 13 | "forget to activate a virtual environment?" 14 | ) from exc 15 | execute_from_command_line(sys.argv) 16 | -------------------------------------------------------------------------------- /04-DRF-LEVEL-TWO/quotesapi/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == '__main__': 6 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'quotesapi.settings') 7 | try: 8 | from django.core.management import execute_from_command_line 9 | except ImportError as exc: 10 | raise ImportError( 11 | "Couldn't import Django. Are you sure it's installed and " 12 | "available on your PYTHONPATH environment variable? Did you " 13 | "forget to activate a virtual environment?" 14 | ) from exc 15 | execute_from_command_line(sys.argv) 16 | -------------------------------------------------------------------------------- /04-DRF-LEVEL-TWO/quotesapi/quotes/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pymike00/The-Complete-Guide-To-DRF-and-VueJS/1b995ce757d7bd1b4df7b5e37f9d6fc51f1ca4eb/04-DRF-LEVEL-TWO/quotesapi/quotes/__init__.py -------------------------------------------------------------------------------- /04-DRF-LEVEL-TWO/quotesapi/quotes/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /04-DRF-LEVEL-TWO/quotesapi/quotes/api/permissions.py: -------------------------------------------------------------------------------- 1 | from rest_framework import permissions 2 | 3 | 4 | class IsAdminUserOrReadOnly(permissions.IsAdminUser): 5 | 6 | def has_permission(self, request, view): 7 | is_admin = super().has_permission(request, view) 8 | 9 | return request.method in permissions.SAFE_METHODS or is_admin -------------------------------------------------------------------------------- /04-DRF-LEVEL-TWO/quotesapi/quotes/api/serializers.py: -------------------------------------------------------------------------------- 1 | from rest_framework import serializers 2 | from quotes.models import Quote 3 | 4 | 5 | class QuoteSerializer(serializers.ModelSerializer): 6 | 7 | class Meta: 8 | model = Quote 9 | fields = "__all__" 10 | -------------------------------------------------------------------------------- /04-DRF-LEVEL-TWO/quotesapi/quotes/api/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | from quotes.api.views import QuoteDetailAPIview, QuoteListCreateAPIView 3 | 4 | urlpatterns = [ 5 | path("quotes/", QuoteListCreateAPIView.as_view(), name="quote-list"), 6 | path("quotes//", QuoteDetailAPIview.as_view(), name="quote-detail") 7 | ] -------------------------------------------------------------------------------- /04-DRF-LEVEL-TWO/quotesapi/quotes/api/views.py: -------------------------------------------------------------------------------- 1 | from rest_framework import generics 2 | 3 | from quotes.models import Quote 4 | from quotes.api.permissions import IsAdminUserOrReadOnly 5 | from quotes.api.serializers import QuoteSerializer 6 | 7 | 8 | class QuoteListCreateAPIView(generics.ListCreateAPIView): 9 | queryset = Quote.objects.all().order_by("-id") 10 | serializer_class = QuoteSerializer 11 | permission_classes = [IsAdminUserOrReadOnly] 12 | 13 | 14 | class QuoteDetailAPIview(generics.RetrieveUpdateDestroyAPIView): 15 | queryset = Quote.objects.all() 16 | serializer_class = QuoteSerializer 17 | permission_classes = [IsAdminUserOrReadOnly] -------------------------------------------------------------------------------- /04-DRF-LEVEL-TWO/quotesapi/quotes/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class QuotesConfig(AppConfig): 5 | name = 'quotes' 6 | -------------------------------------------------------------------------------- /04-DRF-LEVEL-TWO/quotesapi/quotes/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.1.7 on 2019-03-07 10:22 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='Quote', 16 | fields=[ 17 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 18 | ('quote_author', models.CharField(max_length=50)), 19 | ('quote_body', models.TextField()), 20 | ('context', models.CharField(blank=True, max_length=240)), 21 | ('source', models.CharField(blank=True, max_length=120)), 22 | ('created_at', models.DateTimeField(auto_now_add=True)), 23 | ], 24 | ), 25 | ] 26 | -------------------------------------------------------------------------------- /04-DRF-LEVEL-TWO/quotesapi/quotes/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pymike00/The-Complete-Guide-To-DRF-and-VueJS/1b995ce757d7bd1b4df7b5e37f9d6fc51f1ca4eb/04-DRF-LEVEL-TWO/quotesapi/quotes/migrations/__init__.py -------------------------------------------------------------------------------- /04-DRF-LEVEL-TWO/quotesapi/quotes/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | 4 | class Quote(models.Model): 5 | quote_author = models.CharField(max_length=50) 6 | quote_body = models.TextField() 7 | context = models.CharField(max_length=240, blank=True) 8 | source = models.CharField(max_length=120, blank=True) 9 | created_at = models.DateTimeField(auto_now_add=True) 10 | 11 | def __str__(self): 12 | return self.quote_author 13 | -------------------------------------------------------------------------------- /04-DRF-LEVEL-TWO/quotesapi/quotes/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /04-DRF-LEVEL-TWO/quotesapi/quotes/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render 2 | 3 | # Create your views here. 4 | -------------------------------------------------------------------------------- /04-DRF-LEVEL-TWO/quotesapi/quotesapi/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pymike00/The-Complete-Guide-To-DRF-and-VueJS/1b995ce757d7bd1b4df7b5e37f9d6fc51f1ca4eb/04-DRF-LEVEL-TWO/quotesapi/quotesapi/__init__.py -------------------------------------------------------------------------------- /04-DRF-LEVEL-TWO/quotesapi/quotesapi/settings.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...) 4 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 5 | 6 | 7 | # Quick-start development settings - unsuitable for production 8 | # See https://docs.djangoproject.com/en/4.1/howto/deployment/checklist/ 9 | 10 | # SECURITY WARNING: keep the secret key used in production secret! 11 | SECRET_KEY = 'jh012i-1rehi+vsmgbzc5kant^-6(sk_!n+a5lj(_k3@g2@)*!' 12 | 13 | # SECURITY WARNING: don't run with debug turned on in production! 14 | DEBUG = True 15 | 16 | ALLOWED_HOSTS = [] 17 | 18 | 19 | # Application definition 20 | 21 | INSTALLED_APPS = [ 22 | 'django.contrib.admin', 23 | 'django.contrib.auth', 24 | 'django.contrib.contenttypes', 25 | 'django.contrib.sessions', 26 | 'django.contrib.messages', 27 | 'django.contrib.staticfiles', 28 | 29 | 'rest_framework', 30 | 31 | 'quotes' 32 | ] 33 | 34 | MIDDLEWARE = [ 35 | 'django.middleware.security.SecurityMiddleware', 36 | 'django.contrib.sessions.middleware.SessionMiddleware', 37 | 'django.middleware.common.CommonMiddleware', 38 | 'django.middleware.csrf.CsrfViewMiddleware', 39 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 40 | 'django.contrib.messages.middleware.MessageMiddleware', 41 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 42 | ] 43 | 44 | ROOT_URLCONF = 'quotesapi.urls' 45 | 46 | TEMPLATES = [ 47 | { 48 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 49 | 'DIRS': [], 50 | 'APP_DIRS': True, 51 | 'OPTIONS': { 52 | 'context_processors': [ 53 | 'django.template.context_processors.debug', 54 | 'django.template.context_processors.request', 55 | 'django.contrib.auth.context_processors.auth', 56 | 'django.contrib.messages.context_processors.messages', 57 | ], 58 | }, 59 | }, 60 | ] 61 | 62 | WSGI_APPLICATION = 'quotesapi.wsgi.application' 63 | 64 | DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' 65 | 66 | 67 | # Database 68 | # https://docs.djangoproject.com/en/4.1/ref/settings/#databases 69 | 70 | DATABASES = { 71 | 'default': { 72 | 'ENGINE': 'django.db.backends.sqlite3', 73 | 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 74 | } 75 | } 76 | 77 | 78 | # Password validation 79 | # https://docs.djangoproject.com/en/4.1/ref/settings/#auth-password-validators 80 | 81 | AUTH_PASSWORD_VALIDATORS = [ 82 | { 83 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 84 | }, 85 | { 86 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 87 | }, 88 | { 89 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 90 | }, 91 | { 92 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 93 | }, 94 | ] 95 | 96 | 97 | # Internationalization 98 | # https://docs.djangoproject.com/en/4.1/topics/i18n/ 99 | 100 | LANGUAGE_CODE = 'en-us' 101 | 102 | TIME_ZONE = 'UTC' 103 | 104 | USE_I18N = True 105 | 106 | USE_L10N = True 107 | 108 | USE_TZ = True 109 | 110 | 111 | # Static files (CSS, JavaScript, Images) 112 | # https://docs.djangoproject.com/en/4.1/howto/static-files/ 113 | 114 | STATIC_URL = '/static/' 115 | 116 | 117 | REST_FRAMEWORK = { 118 | 'PAGE_SIZE': 30, 119 | 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination' 120 | } -------------------------------------------------------------------------------- /04-DRF-LEVEL-TWO/quotesapi/quotesapi/urls.py: -------------------------------------------------------------------------------- 1 | """quotesapi URL Configuration 2 | 3 | The `urlpatterns` list routes URLs to views. For more information please see: 4 | https://docs.djangoproject.com/en/4.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 include, path 18 | 19 | urlpatterns = [ 20 | path('admin/', admin.site.urls), 21 | path("api/", include("quotes.api.urls")) 22 | ] 23 | -------------------------------------------------------------------------------- /04-DRF-LEVEL-TWO/quotesapi/quotesapi/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for quotesapi 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/4.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', 'quotesapi.settings') 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /04-DRF-LEVEL-TWO/requirements.txt: -------------------------------------------------------------------------------- 1 | django>=4.1,<4.2 2 | djangorestframework>=3.14,<3.15 -------------------------------------------------------------------------------- /05-DRF-LEVEL-THREE/profilesapi/clients/client_app.py: -------------------------------------------------------------------------------- 1 | import requests 2 | 3 | 4 | def registration(account_data: dict) -> None: 5 | registration_endpoint = "http://127.0.0.1:8000/auth/users/" 6 | response = requests.post(registration_endpoint, data=account_data) 7 | print(response) 8 | 9 | 10 | def login(login_credentials: dict) -> str: 11 | login_endpoint = "http://127.0.0.1:8000/auth/token/login/" 12 | response = requests.post(login_endpoint, data=login_credentials) 13 | status_code = response.status_code 14 | print(f"Status Code: {response.status_code}") 15 | if status_code == 200: 16 | auth_token = response.json()["auth_token"] 17 | print(f"Auth Token: {auth_token}") 18 | return auth_token 19 | 20 | 21 | def client(auth_token: str, endpoint: str) -> None: 22 | token_h = f"Token {auth_token}" 23 | headers = {"Authorization": token_h} 24 | response = requests.get(endpoint, headers=headers) 25 | status_code = response.status_code 26 | print(f"Status Code: {response.status_code}") 27 | if status_code == 200: 28 | response_data = response.json() 29 | print(response_data) 30 | 31 | 32 | if __name__ == "__main__": 33 | # account_data = { 34 | # "username": "mytestuserx", 35 | # "email": "test@myrest.comx", 36 | # "password": "verystrongpassword", 37 | # "re_password": "verystrongpassword", 38 | # } 39 | # registration(account_data) 40 | 41 | login_credentials = {"username": "mytestuserx", "password": "verystrongpassword"} 42 | auth_token = login(login_credentials) 43 | 44 | data_endpoint = "http://127.0.0.1:8000/api/profiles/" 45 | client(auth_token, data_endpoint) 46 | -------------------------------------------------------------------------------- /05-DRF-LEVEL-THREE/profilesapi/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == '__main__': 6 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'profilesapi.settings') 7 | try: 8 | from django.core.management import execute_from_command_line 9 | except ImportError as exc: 10 | raise ImportError( 11 | "Couldn't import Django. Are you sure it's installed and " 12 | "available on your PYTHONPATH environment variable? Did you " 13 | "forget to activate a virtual environment?" 14 | ) from exc 15 | execute_from_command_line(sys.argv) 16 | -------------------------------------------------------------------------------- /05-DRF-LEVEL-THREE/profilesapi/profiles/__init__.py: -------------------------------------------------------------------------------- 1 | default_app_config = "profiles.apps.ProfilesConfig" -------------------------------------------------------------------------------- /05-DRF-LEVEL-THREE/profilesapi/profiles/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from profiles.models import Profile, ProfileStatus 3 | 4 | admin.site.register(Profile) 5 | admin.site.register(ProfileStatus) 6 | -------------------------------------------------------------------------------- /05-DRF-LEVEL-THREE/profilesapi/profiles/api/permissions.py: -------------------------------------------------------------------------------- 1 | from rest_framework import permissions 2 | 3 | 4 | class IsOwnProfileOrReadOnly(permissions.BasePermission): 5 | 6 | def has_object_permission(self, request, view, obj): 7 | if request.method in permissions.SAFE_METHODS: 8 | return True 9 | 10 | return obj.user == request.user 11 | 12 | 13 | class IsOwnerOrReadOnly(permissions.BasePermission): 14 | 15 | def has_object_permission(self, request, view, obj): 16 | if request.method in permissions.SAFE_METHODS: 17 | return True 18 | 19 | return obj.user_profile == request.user.profile -------------------------------------------------------------------------------- /05-DRF-LEVEL-THREE/profilesapi/profiles/api/serializers.py: -------------------------------------------------------------------------------- 1 | from rest_framework import serializers 2 | from profiles.models import Profile, ProfileStatus 3 | 4 | 5 | class ProfileSerializer(serializers.ModelSerializer): 6 | 7 | user = serializers.StringRelatedField(read_only=True) 8 | avatar = serializers.ImageField(read_only=True) 9 | 10 | class Meta: 11 | model = Profile 12 | fields = "__all__" 13 | 14 | 15 | class ProfileAvatarSerializer(serializers.ModelSerializer): 16 | 17 | class Meta: 18 | model = Profile 19 | fields = ("avatar",) 20 | 21 | 22 | class ProfileStatusSerializer(serializers.ModelSerializer): 23 | 24 | user_profile = serializers.StringRelatedField(read_only=True) 25 | 26 | class Meta: 27 | model = ProfileStatus 28 | fields = "__all__" 29 | -------------------------------------------------------------------------------- /05-DRF-LEVEL-THREE/profilesapi/profiles/api/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import include, path 2 | from rest_framework.routers import DefaultRouter 3 | from profiles.api.views import (AvatarUpdateView, ProfileViewSet, 4 | ProfileStatusViewSet) 5 | 6 | router = DefaultRouter() 7 | router.register(r"profiles", ProfileViewSet) 8 | router.register(r"status", ProfileStatusViewSet, basename="status") 9 | 10 | urlpatterns = [ 11 | path("", include(router.urls)), 12 | path("avatar/", AvatarUpdateView.as_view(), name="avatar-update") 13 | ] -------------------------------------------------------------------------------- /05-DRF-LEVEL-THREE/profilesapi/profiles/api/views.py: -------------------------------------------------------------------------------- 1 | from rest_framework import generics, mixins, viewsets 2 | from rest_framework.filters import SearchFilter 3 | from rest_framework.permissions import IsAuthenticated 4 | from rest_framework.viewsets import ModelViewSet 5 | 6 | from profiles.api.permissions import IsOwnerOrReadOnly, IsOwnProfileOrReadOnly 7 | from profiles.api.serializers import (ProfileAvatarSerializer, 8 | ProfileSerializer, 9 | ProfileStatusSerializer) 10 | from profiles.models import Profile, ProfileStatus 11 | 12 | 13 | class AvatarUpdateView(generics.UpdateAPIView): 14 | serializer_class = ProfileAvatarSerializer 15 | permission_classes = [IsAuthenticated] 16 | 17 | def get_object(self): 18 | profile_object = self.request.user.profile 19 | return profile_object 20 | 21 | 22 | class ProfileViewSet(mixins.UpdateModelMixin, 23 | mixins.ListModelMixin, 24 | mixins.RetrieveModelMixin, 25 | viewsets.GenericViewSet): 26 | queryset = Profile.objects.all() 27 | serializer_class = ProfileSerializer 28 | permission_classes = [IsAuthenticated, IsOwnProfileOrReadOnly] 29 | filter_backends = [SearchFilter] 30 | search_fields = ["city"] 31 | 32 | 33 | class ProfileStatusViewSet(ModelViewSet): 34 | serializer_class = ProfileStatusSerializer 35 | permission_classes = [IsAuthenticated, IsOwnerOrReadOnly] 36 | 37 | def get_queryset(self): 38 | queryset = ProfileStatus.objects.all() 39 | username = self.request.query_params.get("username", None) 40 | if username is not None: 41 | queryset = queryset.filter(user_profile__user__username=username) 42 | return queryset 43 | 44 | 45 | def perform_create(self, serializer): 46 | user_profile = self.request.user.profile 47 | serializer.save(user_profile=user_profile) 48 | -------------------------------------------------------------------------------- /05-DRF-LEVEL-THREE/profilesapi/profiles/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class ProfilesConfig(AppConfig): 5 | name = 'profiles' 6 | 7 | def ready(self): 8 | import profiles.signals 9 | -------------------------------------------------------------------------------- /05-DRF-LEVEL-THREE/profilesapi/profiles/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.1.7 on 2019-03-07 16:22 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='Profile', 19 | fields=[ 20 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 21 | ('bio', models.CharField(blank=True, max_length=240)), 22 | ('city', models.CharField(blank=True, max_length=30)), 23 | ('avatar', models.ImageField(blank=True, null=True, upload_to='')), 24 | ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), 25 | ], 26 | ), 27 | migrations.CreateModel( 28 | name='ProfileStatus', 29 | fields=[ 30 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 31 | ('status_content', models.CharField(max_length=240)), 32 | ('created_at', models.DateTimeField(auto_now_add=True)), 33 | ('updated_at', models.DateTimeField(auto_now=True)), 34 | ('user_profile', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='profiles.Profile')), 35 | ], 36 | options={ 37 | 'verbose_name_plural': 'statuses', 38 | }, 39 | ), 40 | ] 41 | -------------------------------------------------------------------------------- /05-DRF-LEVEL-THREE/profilesapi/profiles/migrations/0002_alter_profile_id_alter_profilestatus_id.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.1.8 on 2023-04-11 17:25 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | dependencies = [ 8 | ("profiles", "0001_initial"), 9 | ] 10 | 11 | operations = [ 12 | migrations.AlterField( 13 | model_name="profile", 14 | name="id", 15 | field=models.BigAutoField( 16 | auto_created=True, primary_key=True, serialize=False, verbose_name="ID" 17 | ), 18 | ), 19 | migrations.AlterField( 20 | model_name="profilestatus", 21 | name="id", 22 | field=models.BigAutoField( 23 | auto_created=True, primary_key=True, serialize=False, verbose_name="ID" 24 | ), 25 | ), 26 | ] 27 | -------------------------------------------------------------------------------- /05-DRF-LEVEL-THREE/profilesapi/profiles/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pymike00/The-Complete-Guide-To-DRF-and-VueJS/1b995ce757d7bd1b4df7b5e37f9d6fc51f1ca4eb/05-DRF-LEVEL-THREE/profilesapi/profiles/migrations/__init__.py -------------------------------------------------------------------------------- /05-DRF-LEVEL-THREE/profilesapi/profiles/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | from django.contrib.auth.models import User 3 | 4 | 5 | class Profile(models.Model): 6 | user = models.OneToOneField(User, on_delete=models.CASCADE) 7 | bio = models.CharField(max_length=240, blank=True) 8 | city = models.CharField(max_length=30, blank=True) 9 | avatar = models.ImageField(null=True, blank=True) 10 | 11 | def __str__(self): 12 | return self.user.username 13 | 14 | 15 | class ProfileStatus(models.Model): 16 | user_profile = models.ForeignKey(Profile, on_delete=models.CASCADE) 17 | status_content = models.CharField(max_length=240) 18 | created_at = models.DateTimeField(auto_now_add=True) 19 | updated_at = models.DateTimeField(auto_now=True) 20 | 21 | class Meta: 22 | verbose_name_plural = "statuses" 23 | 24 | def __str__(self): 25 | return str(self.user_profile) 26 | 27 | -------------------------------------------------------------------------------- /05-DRF-LEVEL-THREE/profilesapi/profiles/signals.py: -------------------------------------------------------------------------------- 1 | from django.contrib.auth.models import User 2 | from django.db.models.signals import post_save 3 | from django.dispatch import receiver 4 | from profiles.models import Profile 5 | 6 | @receiver(post_save, sender=User) 7 | def create_profile(sender, instance, created, **kwargs): 8 | # print("Created: ", created) 9 | if created: 10 | Profile.objects.create(user=instance) -------------------------------------------------------------------------------- /05-DRF-LEVEL-THREE/profilesapi/profiles/tests.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | from django.contrib.auth.models import User 4 | from django.urls import reverse 5 | from rest_framework import status 6 | from rest_framework.authtoken.models import Token 7 | from rest_framework.test import APITestCase 8 | 9 | from profiles.api.serializers import ProfileStatusSerializer 10 | from profiles.models import ProfileStatus 11 | 12 | 13 | class RegistrationTestCase(APITestCase): 14 | def test_registration(self): 15 | data = { 16 | "username": "testcase", 17 | "email": "test@localhost.app", 18 | "password": "some_strong_psw", 19 | "re_password": "some_strong_psw", 20 | } 21 | response = self.client.post("/auth/users/", data) 22 | self.assertEqual(response.status_code, status.HTTP_201_CREATED) 23 | 24 | 25 | class ProfileViewSetTestCase(APITestCase): 26 | list_url = reverse("profile-list") 27 | 28 | def setUp(self): 29 | self.user = User.objects.create_user( 30 | username="davinci", password="some-very-strong-psw" 31 | ) 32 | self.token = Token.objects.create(user=self.user) 33 | self.api_authentication() 34 | 35 | def api_authentication(self): 36 | self.client.credentials(HTTP_AUTHORIZATION="Token " + self.token.key) 37 | 38 | def test_profile_list_authenticated(self): 39 | response = self.client.get(self.list_url) 40 | self.assertEqual(response.status_code, status.HTTP_200_OK) 41 | 42 | def test_profile_list_un_authenticated(self): 43 | self.client.force_authenticate(user=None) 44 | response = self.client.get(self.list_url) 45 | self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) 46 | 47 | def test_profile_detail_retrieve(self): 48 | response = self.client.get(reverse("profile-detail", kwargs={"pk": 1})) 49 | self.assertEqual(response.status_code, status.HTTP_200_OK) 50 | self.assertEqual(response.data["user"], "davinci") 51 | 52 | def test_profile_update_by_owner(self): 53 | response = self.client.put( 54 | reverse("profile-detail", kwargs={"pk": 1}), 55 | {"city": "Anchiano", "bio": "Renaissance Genius"}, 56 | ) 57 | self.assertEqual(response.status_code, status.HTTP_200_OK) 58 | self.assertEqual( 59 | json.loads(response.content), 60 | { 61 | "id": 1, 62 | "user": "davinci", 63 | "bio": "Renaissance Genius", 64 | "city": "Anchiano", 65 | "avatar": None, 66 | }, 67 | ) 68 | 69 | def test_profile_update_by_random_user(self): 70 | random_user = User.objects.create_user( 71 | username="random", password="psw123123123" 72 | ) 73 | self.client.force_authenticate(user=random_user) 74 | response = self.client.put( 75 | reverse("profile-detail", kwargs={"pk": 1}), {"bio": "hacked!!!"} 76 | ) 77 | self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) 78 | 79 | 80 | class ProfileStatusViewSetTestCase(APITestCase): 81 | url = reverse("status-list") 82 | 83 | def setUp(self): 84 | self.user = User.objects.create_user( 85 | username="davinci", password="some-very-strong-psw" 86 | ) 87 | self.status = ProfileStatus.objects.create( 88 | user_profile=self.user.profile, status_content="status test" 89 | ) 90 | self.token = Token.objects.create(user=self.user) 91 | self.api_authentication() 92 | 93 | def api_authentication(self): 94 | self.client.credentials(HTTP_AUTHORIZATION="Token " + self.token.key) 95 | 96 | def test_status_list_authenticated(self): 97 | response = self.client.get(self.url) 98 | self.assertEqual(response.status_code, status.HTTP_200_OK) 99 | 100 | def test_status_list_un_authenticated(self): 101 | self.client.force_authenticate(user=None) 102 | response = self.client.get(self.url) 103 | self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) 104 | 105 | def test_status_create(self): 106 | data = {"status_content": "a new status!"} 107 | response = self.client.post(self.url, data) 108 | self.assertEqual(response.status_code, status.HTTP_201_CREATED) 109 | self.assertEqual(response.data["user_profile"], "davinci") 110 | self.assertEqual(response.data["status_content"], "a new status!") 111 | 112 | def test_single_status_retrieve(self): 113 | serializer_data = ProfileStatusSerializer(instance=self.status).data 114 | response = self.client.get(reverse("status-detail", kwargs={"pk": 1})) 115 | self.assertEqual(response.status_code, status.HTTP_200_OK) 116 | response_data = json.loads(response.content) 117 | self.assertEqual(serializer_data, response_data) 118 | 119 | def test_status_update_owner(self): 120 | data = {"status_content": "content updated"} 121 | response = self.client.put( 122 | reverse("status-detail", kwargs={"pk": 1}), data=data 123 | ) 124 | self.assertEqual(response.status_code, status.HTTP_200_OK) 125 | self.assertEqual(response.data["status_content"], "content updated") 126 | 127 | def test_status_update_random_user(self): 128 | random_user = User.objects.create_user( 129 | username="random", password="psw123123123" 130 | ) 131 | self.client.force_authenticate(user=random_user) 132 | data = {"status_content": "You Have Been Hacked!"} 133 | response = self.client.put( 134 | reverse("status-detail", kwargs={"pk": 1}), data=data 135 | ) 136 | self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) 137 | -------------------------------------------------------------------------------- /05-DRF-LEVEL-THREE/profilesapi/profiles/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render 2 | 3 | # Create your views here. 4 | -------------------------------------------------------------------------------- /05-DRF-LEVEL-THREE/profilesapi/profilesapi/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pymike00/The-Complete-Guide-To-DRF-and-VueJS/1b995ce757d7bd1b4df7b5e37f9d6fc51f1ca4eb/05-DRF-LEVEL-THREE/profilesapi/profilesapi/__init__.py -------------------------------------------------------------------------------- /05-DRF-LEVEL-THREE/profilesapi/profilesapi/settings.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...) 4 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 5 | 6 | 7 | # Quick-start development settings - unsuitable for production 8 | # See https://docs.djangoproject.com/en/4.1/howto/deployment/checklist/ 9 | 10 | # SECURITY WARNING: keep the secret key used in production secret! 11 | SECRET_KEY = 'rz+ehi(9^91x1vqmv40o+)&6pcci)0_#!$^7t604na17%q*8js' 12 | 13 | # SECURITY WARNING: don't run with debug turned on in production! 14 | DEBUG = True 15 | 16 | ALLOWED_HOSTS = [] 17 | 18 | 19 | # Application definition 20 | 21 | INSTALLED_APPS = [ 22 | 'django.contrib.admin', 23 | 'django.contrib.auth', 24 | 'django.contrib.contenttypes', 25 | 'django.contrib.sessions', 26 | 'django.contrib.messages', 27 | 'django.contrib.staticfiles', 28 | 29 | 'rest_framework', 30 | 'rest_framework.authtoken', 31 | 32 | 'djoser', 33 | 34 | 'profiles' 35 | ] 36 | 37 | MIDDLEWARE = [ 38 | 'django.middleware.security.SecurityMiddleware', 39 | 'django.contrib.sessions.middleware.SessionMiddleware', 40 | 'django.middleware.common.CommonMiddleware', 41 | 'django.middleware.csrf.CsrfViewMiddleware', 42 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 43 | 'django.contrib.messages.middleware.MessageMiddleware', 44 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 45 | ] 46 | 47 | ROOT_URLCONF = 'profilesapi.urls' 48 | 49 | TEMPLATES = [ 50 | { 51 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 52 | 'DIRS': [], 53 | 'APP_DIRS': True, 54 | 'OPTIONS': { 55 | 'context_processors': [ 56 | 'django.template.context_processors.debug', 57 | 'django.template.context_processors.request', 58 | 'django.contrib.auth.context_processors.auth', 59 | 'django.contrib.messages.context_processors.messages', 60 | ], 61 | }, 62 | }, 63 | ] 64 | 65 | WSGI_APPLICATION = 'profilesapi.wsgi.application' 66 | 67 | DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' 68 | 69 | 70 | # Database 71 | # https://docs.djangoproject.com/en/4.1/ref/settings/#databases 72 | 73 | DATABASES = { 74 | 'default': { 75 | 'ENGINE': 'django.db.backends.sqlite3', 76 | 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 77 | } 78 | } 79 | 80 | 81 | # Password validation 82 | # https://docs.djangoproject.com/en/4.1/ref/settings/#auth-password-validators 83 | 84 | AUTH_PASSWORD_VALIDATORS = [ 85 | { 86 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 87 | }, 88 | { 89 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 90 | }, 91 | { 92 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 93 | }, 94 | { 95 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 96 | }, 97 | ] 98 | 99 | 100 | # Internationalization 101 | # https://docs.djangoproject.com/en/4.1/topics/i18n/ 102 | 103 | LANGUAGE_CODE = 'en-us' 104 | 105 | TIME_ZONE = 'UTC' 106 | 107 | USE_I18N = True 108 | 109 | USE_L10N = True 110 | 111 | USE_TZ = True 112 | 113 | 114 | # Static files (CSS, JavaScript, Images) 115 | # https://docs.djangoproject.com/en/4.1/howto/static-files/ 116 | 117 | STATIC_URL = '/static/' 118 | 119 | MEDIA_URL = "/media/" 120 | MEDIA_ROOT = "uploads" 121 | 122 | REST_FRAMEWORK = { 123 | 'DEFAULT_AUTHENTICATION_CLASSES': ( 124 | 'rest_framework.authentication.SessionAuthentication', 125 | 'rest_framework.authentication.TokenAuthentication', 126 | ) 127 | } -------------------------------------------------------------------------------- /05-DRF-LEVEL-THREE/profilesapi/profilesapi/urls.py: -------------------------------------------------------------------------------- 1 | """profilesapi URL Configuration 2 | 3 | The `urlpatterns` list routes URLs to views. For more information please see: 4 | https://docs.djangoproject.com/en/4.2/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 include, path 18 | 19 | 20 | urlpatterns = [ 21 | path("admin/", admin.site.urls), 22 | path("api/", include("profiles.api.urls")), 23 | path("api-auth/", include("rest_framework.urls")), 24 | path("auth/", include("djoser.urls")), 25 | path("auth/", include("djoser.urls.authtoken")), 26 | ] 27 | 28 | from django.conf.urls.static import static 29 | from django.conf import settings 30 | 31 | if settings.DEBUG: 32 | urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) 33 | -------------------------------------------------------------------------------- /05-DRF-LEVEL-THREE/profilesapi/profilesapi/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for profilesapi 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/4.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', 'profilesapi.settings') 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /05-DRF-LEVEL-THREE/requirements.txt: -------------------------------------------------------------------------------- 1 | django>=4.1,<4.2 2 | djangorestframework>=3.14,<3.15 3 | djoser>=2.2.0, <2.3.0 4 | requests==2.31.0 5 | pillow>=9.5.0,<9.6.0 -------------------------------------------------------------------------------- /06-Vue-JS/03_First_Vue_Instance/hello_vue.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Hello Vue 7 | 8 | 9 |
10 |

{{ message }}

11 |

{{ num }}

12 |

{{ num * 5 }}

13 |

{{ "Hello" + " Vue!" }}

14 |

{{ (33/11) * 5 }}

15 |
{{ Math.random() }}
16 |
{{ message.split("").reverse().join("") }}
17 | Official Documentation 18 |
19 | 20 |
21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /06-Vue-JS/03_First_Vue_Instance/main.js: -------------------------------------------------------------------------------- 1 | const app = Vue.createApp({ 2 | data() { 3 | return { 4 | message: "Hello World!", 5 | num: 5, 6 | img: 7 | "https://cdn.pixabay.com/photo/2016/11/29/03/36/beautiful-1867093_1280.jpg", 8 | link: "https://vuejs.org", 9 | }; 10 | }, 11 | }); 12 | 13 | const mountedApp = app.mount("#app"); 14 | -------------------------------------------------------------------------------- /06-Vue-JS/04_Events_and_Methods/events_and_methods.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Events and Methods 7 | 14 | 15 | 16 |
17 |

{{ lesson }}

18 |
19 |

{{ counter }}

20 | 21 |

22 |
23 |
24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /06-Vue-JS/04_Events_and_Methods/main.js: -------------------------------------------------------------------------------- 1 | const app = Vue.createApp({ 2 | data() { 3 | return { 4 | lesson: "Events and Methods", 5 | counter: 0, 6 | }; 7 | }, 8 | methods: { 9 | incrementCounter() { 10 | this.counter += 1; 11 | console.log(this.counter); 12 | if (this.counter === 10) { 13 | alert("Counter is at 10!"); 14 | } 15 | }, 16 | overTheBox() { 17 | console.log("Over The Green Box!!!"); 18 | }, 19 | }, 20 | }); 21 | 22 | const mountedApp = app.mount("#app"); 23 | -------------------------------------------------------------------------------- /06-Vue-JS/05_Conditional_Rendering/conditional_rendering-1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Conditional Rendering 7 | 8 | 9 | 10 |
11 |

Your User Profile

12 |

Please Login to access your Profile!

13 |
14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /06-Vue-JS/05_Conditional_Rendering/conditional_rendering-2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Conditional Rendering 7 | 8 | 9 | 10 |
11 |

Product: {{ product }}

12 |

Avilable

13 |

Limited Availability

14 |

Sold Out!

15 |
16 |

On Sale!!!

17 |
18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /06-Vue-JS/05_Conditional_Rendering/main-1.js: -------------------------------------------------------------------------------- 1 | const app = Vue.createApp({ 2 | data() { 3 | return { 4 | auth: false, 5 | }; 6 | }, 7 | }); 8 | 9 | const mountedApp = app.mount("#app"); 10 | -------------------------------------------------------------------------------- /06-Vue-JS/05_Conditional_Rendering/main-2.js: -------------------------------------------------------------------------------- 1 | const app = Vue.createApp({ 2 | data() { 3 | return { 4 | product: "sunglasses", 5 | quantity: 150, 6 | sale: true, 7 | }; 8 | }, 9 | }); 10 | 11 | const mountedApp = app.mount("#app"); 12 | -------------------------------------------------------------------------------- /06-Vue-JS/06_Class_and_Style_Binding/class_and_style_binding.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Class and Style Binding 7 | 25 | 26 | 27 | 28 |
29 |
30 |
33 |
34 |
35 |
36 |
37 | 38 |
39 |
40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /06-Vue-JS/06_Class_and_Style_Binding/main.js: -------------------------------------------------------------------------------- 1 | const app = Vue.createApp({ 2 | data() { 3 | return { 4 | flag: true, 5 | styleObject: { 6 | backgroundColor: "green", 7 | border: "5px solid orange", 8 | }, 9 | }; 10 | }, 11 | methods: { 12 | changeShape() { 13 | this.flag = !this.flag; 14 | }, 15 | }, 16 | }); 17 | 18 | const mountedApp = app.mount("#app"); 19 | -------------------------------------------------------------------------------- /06-Vue-JS/07_List_Rendering/list_rendering.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | List Rendering 7 | 12 | 13 | 14 | 15 |
16 |
17 |

List of Users

18 |
21 |
22 |

User: {{ user.name }}

23 |

Profession: {{ user.profession }}

24 |
25 |
26 |
27 |
28 |
29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /06-Vue-JS/07_List_Rendering/main.js: -------------------------------------------------------------------------------- 1 | const app = Vue.createApp({ 2 | data() { 3 | return { 4 | users: [ 5 | { 6 | id: 567, 7 | name: "alice", 8 | profession: "developer", 9 | }, 10 | { 11 | id: 568, 12 | name: "bob", 13 | profession: "developer", 14 | }, 15 | { 16 | id: 569, 17 | name: "batman", 18 | profession: "manager", 19 | }, 20 | { 21 | id: 570, 22 | name: "jane", 23 | profession: "designer", 24 | }, 25 | { 26 | id: 571, 27 | name: "superman", 28 | profession: "developer", 29 | }, 30 | ], 31 | }; 32 | }, 33 | }); 34 | 35 | const mountedApp = app.mount("#app"); 36 | -------------------------------------------------------------------------------- /06-Vue-JS/08_Computed_Properties/computed_properties.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Computed Properties 7 | 12 | 13 | 14 | 15 |
16 |
17 |

Method - 1: {{ getRandomNumber() }}

18 |

Method - 2: {{ getRandomNumber() }}

19 |

Method - 3: {{ getRandomNumber() }}

20 |
21 |

Computed - 1: {{ getRandomComputed }}

22 |

Computed - 2: {{ getRandomComputed }}

23 |

Computed - 3: {{ getRandomComputed }}

24 |
25 |

Full Name: {{ fullName }}

26 |
27 |

Full Name - Reversed: {{ reversedFullName }}

28 |
29 |
30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /06-Vue-JS/08_Computed_Properties/main.js: -------------------------------------------------------------------------------- 1 | const app = Vue.createApp({ 2 | data() { 3 | return { 4 | first_name: "John", 5 | last_name: "Doe" 6 | } 7 | }, 8 | computed: { 9 | getRandomComputed() { 10 | return Math.random(); 11 | }, 12 | fullName() { 13 | return `${this.first_name} ${this.last_name}`; 14 | }, 15 | reversedFullName() { 16 | let first = this.first_name.split("").reverse().join(""); 17 | let last = this.last_name.split("").reverse().join(""); 18 | return `${ first } ${ last }`; 19 | } 20 | }, 21 | methods: { 22 | getRandomNumber() { 23 | return Math.random(); 24 | } 25 | } 26 | }); 27 | 28 | 29 | const mountedApp = app.mount('#app'); -------------------------------------------------------------------------------- /06-Vue-JS/09_Forms_and_User_Input/forms_and_user_input-0.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Forms and User Input 8 | 9 | 10 | 11 |
12 |
13 |
14 |

Write a message!

15 | 22 |
23 |
24 |

Message

25 |

{{ text }}

26 |
27 |
28 | 29 |
30 | 31 | 32 |
33 | 34 |
35 | 42 |   City: {{ city }} 43 |
44 |
45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /06-Vue-JS/09_Forms_and_User_Input/forms_and_user_input.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Forms and User Input 8 | 9 | 10 | 11 |
12 | 13 |

{{ error }}

14 | 15 |
16 |
17 |
18 |
19 | 20 | 27 |
28 | 29 |
30 |
31 |
32 |
33 | 34 |
35 |
36 |
37 |
38 | {{ comment }} 39 |
40 |
41 |
42 |
43 | 44 |
45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /06-Vue-JS/09_Forms_and_User_Input/main-0.js: -------------------------------------------------------------------------------- 1 | const app = Vue.createApp({ 2 | data() { 3 | return { 4 | text: "", 5 | checked: true, 6 | city: "" 7 | } 8 | } 9 | }); 10 | 11 | const mountedApp = app.mount("#app"); 12 | -------------------------------------------------------------------------------- /06-Vue-JS/09_Forms_and_User_Input/main.js: -------------------------------------------------------------------------------- 1 | const app = Vue.createApp({ 2 | data() { 3 | return { 4 | comment: null, 5 | comments: [], 6 | error: null, 7 | }; 8 | }, 9 | methods: { 10 | onSubmit() { 11 | if (this.comment) { 12 | let newComment = this.comment; 13 | this.comments.push(newComment); 14 | this.comment = null; 15 | 16 | if (this.error) { 17 | this.error = null; 18 | } 19 | } else { 20 | this.error = "The comment field can't be empty!"; 21 | } 22 | }, 23 | }, 24 | }); 25 | 26 | const mountedApp = app.mount("#app"); 27 | -------------------------------------------------------------------------------- /06-Vue-JS/10_Components_and_Props/components_and_props.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Components and Props 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /06-Vue-JS/10_Components_and_Props/main.js: -------------------------------------------------------------------------------- 1 | const app = Vue.createApp({ 2 | data() { 3 | return { 4 | comments: [ 5 | { 6 | username: "alice", 7 | content: "First Comment!" 8 | }, 9 | { 10 | username: "bob", 11 | content: "Hello World!" 12 | }, 13 | { 14 | username: "ironman", 15 | content: "New Armor Coming Soon!" 16 | }, 17 | { 18 | username: "superman", 19 | content: "Kryptonite is Bad!" 20 | }, 21 | ] 22 | } 23 | } 24 | }); 25 | 26 | 27 | app.component("comment", { 28 | props: { 29 | comment: { 30 | type: Object, 31 | required: true 32 | } 33 | }, 34 | template: ` 35 |
36 |
37 |

{{ comment.username }}

38 |

{{ comment.content }}

39 |
40 |
41 |
42 | ` 43 | }); 44 | 45 | 46 | const mountedApp = app.mount('#app'); -------------------------------------------------------------------------------- /06-Vue-JS/11_How_To_Use_Emit/components_and_emit.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Components and $emit 7 | 8 | 9 | 10 | 11 |
12 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /06-Vue-JS/11_How_To_Use_Emit/main.js: -------------------------------------------------------------------------------- 1 | const app = Vue.createApp({ 2 | data() { 3 | return { 4 | comments: [ 5 | { 6 | username: "alice", 7 | content: "First Comment!", 8 | }, 9 | { 10 | username: "bob", 11 | content: "Hello World!", 12 | }, 13 | { 14 | username: "ironman", 15 | content: "New Armor Coming Soon!", 16 | }, 17 | { 18 | username: "superman", 19 | content: "Kryptonite is Bad!", 20 | }, 21 | ], 22 | }; 23 | }, 24 | methods: { 25 | addNewComment(newComment) { 26 | this.comments.push(newComment); 27 | }, 28 | }, 29 | }); 30 | 31 | 32 | // comment list component 33 | app.component("comment-list", { 34 | emits: ["submit-comment"], 35 | props: { 36 | comments: { 37 | type: Array, 38 | required: true, 39 | }, 40 | }, 41 | data() { 42 | return { 43 | commentAuthor: null, 44 | commentBody: null, 45 | error: null, 46 | }; 47 | }, 48 | methods: { 49 | onSubmit() { 50 | if (this.commentAuthor && this.commentBody) { 51 | const newComment = { 52 | username: this.commentAuthor, 53 | content: this.commentBody, 54 | }; 55 | this.$emit("submit-comment", newComment); 56 | 57 | this.commentAuthor = null; 58 | this.commentBody = null; 59 | 60 | if (this.error) { 61 | this.error = null; 62 | } 63 | } else { 64 | this.error = "Please fill out both fields!"; 65 | } 66 | }, 67 | }, 68 | template: ` 69 |
70 | 75 | 76 |
77 |

{{ error }}

78 |
79 |
80 | 81 | 82 |
83 |
84 | 85 | 92 |
93 | 94 |
95 |
96 | `, 97 | }); 98 | 99 | 100 | // single comment component 101 | app.component("single-comment", { 102 | props: { 103 | comment: { 104 | type: Object, 105 | required: true, 106 | }, 107 | }, 108 | template: ` 109 |
110 |
111 |
112 |

Published by: {{ comment.username }}

113 |
114 |
115 |

{{ comment.content }}

116 |
117 |
118 |
119 | `, 120 | }); 121 | 122 | const mountedApp = app.mount("#app"); 123 | -------------------------------------------------------------------------------- /06-Vue-JS/12-13_Competency_Assessment/to_do_application.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | To Do Application 7 | 8 | 17 | 18 | 19 | 20 |
21 | 26 | 27 |
28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /06-Vue-JS/12-13_Competency_Assessment/todo.js: -------------------------------------------------------------------------------- 1 | const app = Vue.createApp({ 2 | data() { 3 | return { 4 | tasks: [], 5 | }; 6 | }, 7 | computed: { 8 | taskCount() { 9 | return this.tasks.length; 10 | }, 11 | }, 12 | methods: { 13 | addNewTask(newTask) { 14 | this.tasks.push(newTask); 15 | }, 16 | removeTask(task) { 17 | this.tasks.splice(this.tasks.indexOf(task), 1); 18 | }, 19 | }, 20 | }); 21 | 22 | app.component("to-do", { 23 | props: { 24 | tasks: { 25 | type: Array, 26 | required: true, 27 | }, 28 | remaining: { 29 | type: Number, 30 | required: true, 31 | }, 32 | }, 33 | data() { 34 | return { 35 | error: null, 36 | newTask: null, 37 | }; 38 | }, 39 | methods: { 40 | submitTask() { 41 | if (this.newTask) { 42 | this.$emit("add-task", this.newTask); 43 | this.newTask = null; 44 | if (this.error) { 45 | this.error = null; 46 | } 47 | } else { 48 | this.error = "The input field can't be empty!"; 49 | } 50 | }, 51 | removeTask(task) { 52 | this.$emit("remove-task", task); 53 | }, 54 | }, 55 | template: ` 56 |
57 |

Remaining Tasks: {{ remaining }}

58 | 63 |
64 |
65 | 71 |
72 |

{{ error }}

73 |

To add a new task, write something and press enter!

74 |
75 | `, 76 | }); 77 | 78 | const mountedApp = app.mount("#app"); 79 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## The Complete Guide to Django REST Framework and Vue JS 2 | 3 | The source code of my course *The Complete Guide to Django REST Framework and Vue JS*, where you can learn how to build professional Single Page Applications with Django and Vue JS. 4 | 5 | This is an intermediate/advanced level course, therefore knowledge of Python, Django, HTML, CSS and JavaScript is assumed. 6 | 7 | Enroll now if you want to learn how to build professional REST APIs with Django REST Framework, powerful Reactive Components with Vue JS and Single Page Applications using both Django and Vue JS. 8 | 9 | The course is available in English on Udemy: 10 | 11 | English Version: [ENROLL NOW](https://www.udemy.com/course/the-complete-guide-to-django-rest-framework-and-vue-js/?referralCode=A2FA0F6C1C4BE66A3B3E) 12 | 13 | And in Italian in the Academy section of my Website ProgrammareInPython.it 14 | 15 | VERSIONE ITALIANA: [ISCRIVITI ORA](https://www.programmareinpython.it/programmare-in-python/) 16 | 17 | Are you looking for the Source Code of the end of the course project? You can find it in a dedicated repo here: https://github.com/pymike00/QuestionTime 18 | --------------------------------------------------------------------------------