commit a36f93289f5c0abd09c7d6eaa84dd2a4efa8b305 Author: devfzn Date: Wed Mar 29 14:06:11 2023 -0300 init Django Rest Framework Api course Inicio de projecto Django 'drf_course' y app 'core' diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1d1a939 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.env +venv +otros/ +__pycache__/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..2d7fcf0 --- /dev/null +++ b/README.md @@ -0,0 +1,153 @@ +# Django REST API + +[Django Rest Framework](https://www.django-rest-framework.org/) + +### Requerimientos Rest Framework + +- Python (>=3.10) +- Django + +Optional: + +- PyYAML, uritemplate: Schema generation support. +- Markdown: Markdown support for the browsable API. +- Pygments: Add syntax highlighting to Markdown processing. +- django-filter: Filtering support. +- django-guardian: Object level permissions support. + +**En entorno virtual** + +```py +pip install djangorestframework +``` + +### Instalacion + +```py +pip install django-extensions djangorestframework djangorestframework-jsonapi \ +inflection python-dotenv sqlparse + +Django utiliza SQLite3 por defecto facilitar el desarrolo, en este proyecto se +utliza MariaDB, pero es opcional. + +# MariaDB +pip install mysqlclient +``` + +### Inicio del proyecto + +```sh +mkdir backend + +# Creación del proyecto Django +django-admin startproject drf_course backend +``` + +Este proyecto consta de 2 aplicaciones. + +La primera es el núcleo. Esta contendrá la lógica del contacto con el *endpoint*. +La segunda será *ecommerce*. Esta contendrá la ĺógica del endpoint de los +*items* y ordenes. + +```sh +cd backend +python manage.py startapp core +``` + +### Editar configuración del proyecto + +Archivo [./backend/drf_course/settings.py](./backend/drf_course/settings.py). + +Importar `.env` usando *python-dotenv*. + +```py +from dotenv import load_dotenv +import os + +load_dotenv() +``` + +Reemplazar `ALLOWED_HOSTS`, `SECRET_KEY` y `DEBUG`. + +```py +SECRET_KEY = os.environ.get("SECRET_KEY") +DEBUG = int(os.environ.get("DEBUG", default=0)) +ALLOWED_HOSTS = os.environ.get("DJANGO_ALLOWED_HOSTS").split(" ") +``` + +Añadir aplicaciones +```py +INSTALLED_APPS = [ + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + 'django_extensions', # <--- + 'django_filters', # <--- + 'rest_framework', # <--- + 'core', # <--- +] + +``` + +Añadir variables del framework REST al final del arhivo. + +```py +REST_FRAMEWORK = { + 'EXCEPTION_HANDLER': 'rest_framework_json_api.exceptions.exception_handler', + 'DEFAULT_PARSER_CLASSES': ( + 'rest_framework_json_api.parsers.JSONParser', + ), + 'DEFAULT_RENDERER_CLASSES': ( + 'rest_framework_json_api.renderers.JSONRenderer', + 'rest_framework.renderers.BrowsableAPIRenderer', + ), + 'DEFAULT_METADATA_CLASS': 'rest_framework_json_api.metadata.JSONAPIMetadata', + 'DEFAULT_FILTER_BACKENDS': ( + 'rest_framework_json_api.filters.QueryParameterValidationFilter', + 'rest_framework_json_api.filters.OrderingFilter', + 'rest_framework_json_api.django_filters.DjangoFilterBackend', + 'rest_framework_json_api.filters.SearchFilter', + ), + 'SEARCH_PARAM': 'filter[search]', + 'TEST_REQUEST_RENDERER_CLASSES': ( + 'rest_framework_json_api.renderers.JSONRenderer', + ), + 'TEST_REQUEST_DEFAULT_FORMAT': 'vnd.api+json' +} +``` + +En caso de utilizar MariaDB, cambiar la declaración de *DATABASES*, para usar +las variables de entorno declaradas en [./backend/env](./backend/.env) + +```py +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.mysql', + 'NAME': os.environ.get("MARIADB_DBASE"), + 'USER': os.environ.get("MARIADB_USER"), + 'PASSWORD': os.environ.get("MARIADB_PASS"), + 'HOST': os.environ.get("MARIADB_HOST"), + 'PORT': os.environ.get("MARIADB_PORT"), + } +} +``` + +Modificar [./backend/drf_course/urls.py](./backend/drf_course/urls.py) + +```py +from django.contrib import admin +from django.urls import path +from rest_framework import routers + +router = routers.DefaultRouter() + +urlpatterns = router.urls + +urlpatterns += [ + path('admin/', admin.site.urls), +] +``` + diff --git a/backend/core/__init__.py b/backend/core/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/core/admin.py b/backend/core/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/backend/core/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/backend/core/apps.py b/backend/core/apps.py new file mode 100644 index 0000000..8115ae6 --- /dev/null +++ b/backend/core/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class CoreConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'core' diff --git a/backend/core/migrations/__init__.py b/backend/core/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/core/models.py b/backend/core/models.py new file mode 100644 index 0000000..71a8362 --- /dev/null +++ b/backend/core/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/backend/core/tests.py b/backend/core/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/backend/core/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/backend/core/views.py b/backend/core/views.py new file mode 100644 index 0000000..91ea44a --- /dev/null +++ b/backend/core/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here. diff --git a/backend/drf_course/__init__.py b/backend/drf_course/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/drf_course/asgi.py b/backend/drf_course/asgi.py new file mode 100644 index 0000000..0bb087d --- /dev/null +++ b/backend/drf_course/asgi.py @@ -0,0 +1,16 @@ +""" +ASGI config for drf_course project. + +It exposes the ASGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/4.1/howto/deployment/asgi/ +""" + +import os + +from django.core.asgi import get_asgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'drf_course.settings') + +application = get_asgi_application() diff --git a/backend/drf_course/settings.py b/backend/drf_course/settings.py new file mode 100644 index 0000000..1780558 --- /dev/null +++ b/backend/drf_course/settings.py @@ -0,0 +1,135 @@ +from pathlib import Path +from dotenv import load_dotenv +import os + +load_dotenv() + +# Build paths inside the project like this: BASE_DIR / 'subdir'. +BASE_DIR = Path(__file__).resolve().parent.parent + +SECRET_KEY = os.environ.get("SECRET_KEY") +DEBUG = int(os.environ.get("DEBUG", default=0)) +ALLOWED_HOSTS = os.environ.get("DJANGO_ALLOWED_HOSTS").split(" ") + +# Application definition + +INSTALLED_APPS = [ + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + 'django_extensions', + 'django_filters', + 'rest_framework', + 'core', +] + +MIDDLEWARE = [ + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', +] + +ROOT_URLCONF = 'drf_course.urls' + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, +] + +WSGI_APPLICATION = 'drf_course.wsgi.application' + +# Database +# https://docs.djangoproject.com/en/4.1/ref/settings/#databases + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.mysql', + 'NAME': os.environ.get("MARIADB_DBASE"), + 'USER': os.environ.get("MARIADB_USER"), + 'PASSWORD': os.environ.get("MARIADB_PASS"), + 'HOST': os.environ.get("MARIADB_HOST"), + 'PORT': os.environ.get("MARIADB_PORT"), + } +} + +# Password validation +# https://docs.djangoproject.com/en/4.1/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [ + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, +] + + +# Internationalization +# https://docs.djangoproject.com/en/4.1/topics/i18n/ + +LANGUAGE_CODE = 'en-us' + +TIME_ZONE = 'America/Santiago' + +USE_I18N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/4.1/howto/static-files/ + +STATIC_URL = 'static/' + +# Default primary key field type +# https://docs.djangoproject.com/en/4.1/ref/settings/#default-auto-field + +DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' + +REST_FRAMEWORK = { + 'EXCEPTION_HANDLER': 'rest_framework_json_api.exceptions.exception_handler', + 'DEFAULT_PARSER_CLASSES': ( + 'rest_framework_json_api.parsers.JSONParser', + ), + 'DEFAULT_RENDERER_CLASSES': ( + 'rest_framework_json_api.renderers.JSONRenderer', + 'rest_framework.renderers.BrowsableAPIRenderer', + ), + 'DEFAULT_METADATA_CLASS': 'rest_framework_json_api.metadata.JSONAPIMetadata', + 'DEFAULT_FILTER_BACKENDS': ( + 'rest_framework_json_api.filters.QueryParameterValidationFilter', + 'rest_framework_json_api.filters.OrderingFilter', + 'rest_framework_json_api.django_filters.DjangoFilterBackend', + 'rest_framework.filters.SearchFilter', + ), + 'SEARCH_PARAM': 'filter[search]', + 'TEST_REQUEST_RENDERER_CLASSES': ( + 'rest_framework_json_api.renderers.JSONRenderer', + ), + 'TEST_REQUEST_DEFAULT_FORMAT': 'vnd.api+json' +} diff --git a/backend/drf_course/urls.py b/backend/drf_course/urls.py new file mode 100644 index 0000000..7e3fd92 --- /dev/null +++ b/backend/drf_course/urls.py @@ -0,0 +1,11 @@ +from django.contrib import admin +from django.urls import path +from rest_framework import routers + +router = routers.DefaultRouter() + +urlpatterns = router.urls + +urlpatterns += [ + path('admin/', admin.site.urls), +] diff --git a/backend/drf_course/wsgi.py b/backend/drf_course/wsgi.py new file mode 100644 index 0000000..66fab8d --- /dev/null +++ b/backend/drf_course/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for drf_course project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/4.1/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'drf_course.settings') + +application = get_wsgi_application() diff --git a/backend/manage.py b/backend/manage.py new file mode 100755 index 0000000..4e3ceab --- /dev/null +++ b/backend/manage.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +"""Django's command-line utility for administrative tasks.""" +import os +import sys + + +def main(): + """Run administrative tasks.""" + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'drf_course.settings') + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + execute_from_command_line(sys.argv) + + +if __name__ == '__main__': + main() diff --git a/backend/requirements.txt b/backend/requirements.txt new file mode 100644 index 0000000..eed58e7 --- /dev/null +++ b/backend/requirements.txt @@ -0,0 +1,14 @@ +asgiref==3.6.0 +Django==4.1.7 +django-extensions==3.2.1 +django-filter==23.1 +django-guardian==2.4.0 +djangorestframework==3.14.0 +djangorestframework-jsonapi==6.0.0 +inflection==0.5.1 +Markdown==3.4.3 +Pygments==2.14.0 +python-dotenv==1.0.0 +pytz==2023.2 +PyYAML==6.0 +sqlparse==0.4.3 diff --git a/env.template b/env.template new file mode 100644 index 0000000..4ff8ea5 --- /dev/null +++ b/env.template @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +export DEBUG=1 +export SECRET_KEY='rest_framework_tutorial_03-2023' +export DJANGO_ALLOWED_HOSTS=* localhost 127.0.0.1 [::1]