├── .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 |
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 |
Counter ++
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 |
35 |
36 |
37 | Change Shape!
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 | Value: {{ checked }}
32 |
33 |
34 |
35 |
36 | Rome
37 | New York
38 | Shenzen
39 | London
40 | Mumbai
41 |
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 |
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 |
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 |
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 |
66 | {{ task }}
67 |
68 | ×
69 |
70 |
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 |
--------------------------------------------------------------------------------