Showing
69 changed files
with
1373 additions
and
0 deletions
.env.-sample
0 → 100644
.gitignore
0 → 100644
| 1 | +dist/ | ||
| 2 | +downloads/ | ||
| 3 | +eggs/ | ||
| 4 | +.eggs/ | ||
| 5 | +lib/ | ||
| 6 | +lib64/ | ||
| 7 | +parts/ | ||
| 8 | +sdist/ | ||
| 9 | +var/ | ||
| 10 | +wheels/ | ||
| 11 | +share/python-wheels/ | ||
| 12 | +*.egg-info/ | ||
| 13 | +.installed.cfg | ||
| 14 | +*.egg | ||
| 15 | +MANIFEST | ||
| 16 | + | ||
| 17 | +# PyInstaller | ||
| 18 | +# Usually these files are written by a python script from a template | ||
| 19 | +# before PyInstaller builds the exe, so as to inject date/other infos into it. | ||
| 20 | +*.manifest | ||
| 21 | +*.spec | ||
| 22 | + | ||
| 23 | +# Installer logs | ||
| 24 | +pip-log.txt | ||
| 25 | +pip-delete-this-directory.txt | ||
| 26 | + | ||
| 27 | +# Unit test / coverage reports | ||
| 28 | +htmlcov/ | ||
| 29 | +.tox/ | ||
| 30 | +.nox/ | ||
| 31 | +.coverage | ||
| 32 | +.coverage.* | ||
| 33 | +.cache | ||
| 34 | +nosetests.xml | ||
| 35 | +coverage.xml | ||
| 36 | +*.cover | ||
| 37 | +*.py,cover | ||
| 38 | +.hypothesis/ | ||
| 39 | +.pytest_cache/ | ||
| 40 | +cover/ | ||
| 41 | + | ||
| 42 | +# Translations | ||
| 43 | +*.mo | ||
| 44 | +*.pot | ||
| 45 | + | ||
| 46 | +# Django stuff: | ||
| 47 | +*.log | ||
| 48 | +local_settings.py | ||
| 49 | +db.sqlite3 | ||
| 50 | +db.sqlite3-journal | ||
| 51 | + | ||
| 52 | +# Flask stuff: | ||
| 53 | +instance/ | ||
| 54 | +.webassets-cache | ||
| 55 | + | ||
| 56 | +# Scrapy stuff: | ||
| 57 | +.scrapy | ||
| 58 | + | ||
| 59 | +# Sphinx documentation | ||
| 60 | +docs/_build/ | ||
| 61 | + | ||
| 62 | +# PyBuilder | ||
| 63 | +.pybuilder/ | ||
| 64 | +target/ | ||
| 65 | + | ||
| 66 | +# Jupyter Notebook | ||
| 67 | +.ipynb_checkpoints | ||
| 68 | + | ||
| 69 | +# IPython | ||
| 70 | +profile_default/ | ||
| 71 | +ipython_config.py | ||
| 72 | + | ||
| 73 | +# pyenv | ||
| 74 | +# For a library or package, you might want to ignore these files since the code is | ||
| 75 | +# intended to run in multiple environments; otherwise, check them in: | ||
| 76 | +# .python-version | ||
| 77 | + | ||
| 78 | +# pipenv | ||
| 79 | +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. | ||
| 80 | +# However, in case of collaboration, if having platform-specific dependencies or dependencies | ||
| 81 | +# having no cross-platform support, pipenv may install dependencies that don't work, or not | ||
| 82 | +# install all needed dependencies. | ||
| 83 | +#Pipfile.lock | ||
| 84 | + | ||
| 85 | +# PEP 582; used by e.g. github.com/David-OConnor/pyflow | ||
| 86 | +__pypackages__/ | ||
| 87 | + | ||
| 88 | +# Celery stuff | ||
| 89 | +celerybeat-schedule | ||
| 90 | +celerybeat.pid | ||
| 91 | + | ||
| 92 | +# SageMath parsed files | ||
| 93 | +*.sage.py | ||
| 94 | + | ||
| 95 | +# Environments | ||
| 96 | +.env | ||
| 97 | +.venv | ||
| 98 | +env/ | ||
| 99 | +venv/ | ||
| 100 | +ENV/ | ||
| 101 | +env.bak/ | ||
| 102 | +venv.bak/ | ||
| 103 | + | ||
| 104 | +# Spyder project settings | ||
| 105 | +.spyderproject | ||
| 106 | +.spyproject | ||
| 107 | + | ||
| 108 | +# Rope project settings | ||
| 109 | +.ropeproject | ||
| 110 | + | ||
| 111 | +# mkdocs documentation | ||
| 112 | +/site | ||
| 113 | + | ||
| 114 | +# mypy | ||
| 115 | +.mypy_cache/ | ||
| 116 | +.dmypy.json | ||
| 117 | +dmypy.json | ||
| 118 | + | ||
| 119 | +# Pyre type checker | ||
| 120 | +.pyre/ | ||
| 121 | + | ||
| 122 | +# pytype static type analyzer | ||
| 123 | +.pytype/ | ||
| 124 | + | ||
| 125 | +# Cython debug symbols | ||
| 126 | +cython_debug/ | ||
| 127 | + | ||
| 128 | +# CUSTOM | ||
| 129 | +*.pyc | ||
| 130 | +__pycache | ||
| 131 | +.DS_Store | ||
| 132 | + | ||
| 133 | +.idea/ | ||
| 134 | +.vscode/ |
README.md
0 → 100644
| 1 | +# Django On Docker | ||
| 2 | + | ||
| 3 | +### Quickstart: | ||
| 4 | + | ||
| 5 | +- Local | ||
| 6 | + * docker-compose.yml | ||
| 7 | + * http://localhost:8001 | ||
| 8 | + ```sh | ||
| 9 | + $ docker-compose up -d | ||
| 10 | + ``` | ||
| 11 | +-------------------------------------------------- | ||
| 12 | + | ||
| 13 | +### Comandos: | ||
| 14 | + | ||
| 15 | +- Comandos: | ||
| 16 | + ```sh | ||
| 17 | + # Local (docker-compose.yml) | ||
| 18 | + $ docker-compose exec web python manage.py createsuperuser | ||
| 19 | + $ docker-compose exec web python manage.py makemigrations | ||
| 20 | + $ docker-compose exec web python manage.py migrate | ||
| 21 | + ``` | ||
| 22 | + Más info | ||
| 23 | + - https://docs.docker.com/compose/reference/ | ||
| 24 | + | ||
| 25 | + | ||
| 26 | +- Testing: | ||
| 27 | + ```sh | ||
| 28 | + $ docker-compose exec web python manage.py test | ||
| 29 | + $ docker-compose exec web python manage.py test apps.welcome | ||
| 30 | + $ docker-compose exec web python manage.py test apps.welcome.tests | ||
| 31 | + $ docker-compose exec web python manage.py test apps.welcome.tests.test_views | ||
| 32 | + $ docker-compose exec web python manage.py test apps.welcome.tests.test_views.WelcomeIndexTest | ||
| 33 | + $ docker-compose exec web python manage.py test apps.welcome.tests.test_views.WelcomeIndexTest.test_view_url_accessible_by_name | ||
| 34 | + | ||
| 35 | + $ docker-compose exec web python manage.py test --verbosity 2 | ||
| 36 | + # Los niveles de detalle permitidos son 0, 1, 2 y 3, siendo el valor predeterminado "1". | ||
| 37 | + ``` | ||
| 38 | + | ||
| 39 | + Más info | ||
| 40 | + - https://developer.mozilla.org/es/docs/Learn/Server-side/Django/Testing | ||
| 41 | + |
app/Dockerfile
0 → 100644
| 1 | +# pull official base image | ||
| 2 | +FROM python:3.9.1 | ||
| 3 | + | ||
| 4 | +# set work directory | ||
| 5 | +WORKDIR /usr/src/app | ||
| 6 | + | ||
| 7 | +# set environment variables | ||
| 8 | +ENV PYTHONDONTWRITEBYTECODE 1 | ||
| 9 | +ENV PYTHONUNBUFFERED 1 | ||
| 10 | + | ||
| 11 | +# install dependencies | ||
| 12 | +RUN apt-get update && apt-get install -y \ | ||
| 13 | + gettext \ | ||
| 14 | + netcat \ | ||
| 15 | + && rm -rf /var/lib/apt/lists/* | ||
| 16 | + | ||
| 17 | +# install dependencies | ||
| 18 | +RUN pip install --upgrade pip | ||
| 19 | +COPY ./requirements.txt . | ||
| 20 | +RUN pip install -r requirements.txt | ||
| 21 | + | ||
| 22 | +# copy entrypoint.sh | ||
| 23 | +COPY ./entrypoint.sh . | ||
| 24 | + | ||
| 25 | +# copy project | ||
| 26 | +COPY . . | ||
| 27 | + | ||
| 28 | +# run entrypoint.sh | ||
| 29 | +ENTRYPOINT ["/usr/src/app/entrypoint.sh"] |
app/apps/__init__.py
0 → 100644
app/apps/core/__init__.py
0 → 100644
app/apps/core/apps.py
0 → 100644
app/apps/core/templates/__init__.py
0 → 100644
app/apps/core/templates/core/__init__.py
0 → 100644
app/apps/core/templates/core/base.html
0 → 100644
| 1 | +<html lang="en"> | ||
| 2 | +<head> | ||
| 3 | + <meta charset="utf-8"> | ||
| 4 | + <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> | ||
| 5 | + <title>Welcome!</title> | ||
| 6 | + <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"> | ||
| 7 | + <link rel="stylesheet" href="https://getbootstrap.com/docs/4.0/examples/dashboard/dashboard.css"> | ||
| 8 | + | ||
| 9 | + <!-- BEGIN: Page CSS --> | ||
| 10 | + {% block css %}{% endblock %} | ||
| 11 | + <!-- END: Page CSS --> | ||
| 12 | + | ||
| 13 | +</head> | ||
| 14 | +<body> | ||
| 15 | + | ||
| 16 | + <!-- BEGIN: Navbar --> | ||
| 17 | + {% include 'core/navbar.html' %} | ||
| 18 | + <!-- END: Navbar --> | ||
| 19 | + | ||
| 20 | + <div class="container-fluid"> | ||
| 21 | + <div class="row"> | ||
| 22 | + <!-- BEGIN: Sidebar --> | ||
| 23 | + {% include 'core/sidebar.html' %} | ||
| 24 | + <!-- END: Sidebar --> | ||
| 25 | + <main role="main" class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4"> | ||
| 26 | + <!-- BEGIN: Content --> | ||
| 27 | + {% block content %}{% endblock %} | ||
| 28 | + <!-- END: Content --> | ||
| 29 | + </main> | ||
| 30 | + </div> | ||
| 31 | + </div> | ||
| 32 | + | ||
| 33 | + <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js"></script> | ||
| 34 | + <script src="https://code.jquery.com/jquery-3.4.1.slim.min.js"></script> | ||
| 35 | + <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js"></script> | ||
| 36 | + | ||
| 37 | + <!-- BEGIN: Page JS --> | ||
| 38 | + {% block javascript %}{% endblock %} | ||
| 39 | + <!-- END: Page JS --> | ||
| 40 | + | ||
| 41 | +</body> | ||
| 42 | +</html> |
app/apps/core/templates/core/navbar.html
0 → 100644
| 1 | +{% load static i18n %} | ||
| 2 | +<nav class="navbar navbar-dark sticky-top bg-dark flex-md-nowrap p-0"> | ||
| 3 | + <a class="navbar-brand col-sm-3 col-md-2 mr-0" href="/">{% trans 'Django2React' %}</a> | ||
| 4 | + <ul class="navbar-nav px-3"> | ||
| 5 | + <li class="nav-item text-nowrap"> | ||
| 6 | + <a class="nav-link" href="/admin">{% trans 'Admin' %}</a> | ||
| 7 | + </li> | ||
| 8 | + </ul> | ||
| 9 | +</nav> |
app/apps/core/templates/core/sidebar.html
0 → 100644
| 1 | +{% load static i18n %} | ||
| 2 | +{% load startswith %} | ||
| 3 | +<nav class="col-md-2 d-none d-md-block bg-light sidebar"> | ||
| 4 | + <div class="sidebar-sticky"> | ||
| 5 | + <ul class="nav flex-column"> | ||
| 6 | + <li class="nav-item"> | ||
| 7 | + {% url 'djangoapp:index' as url_djangoapp %} | ||
| 8 | + <a class="nav-link {% if request.path|startswith:url_djangoapp %} active {% endif %}" | ||
| 9 | + href="{% url 'djangoapp:index' %}"> | ||
| 10 | + {% trans 'App django' %} | ||
| 11 | + </a> | ||
| 12 | + </li> | ||
| 13 | + <li class="nav-item"> | ||
| 14 | + {% url 'reactapp:index' as url_reactapp %} | ||
| 15 | + <a class="nav-link {% if request.path|startswith:url_reactapp %} active {% endif %}" | ||
| 16 | + href="{% url 'reactapp:index' %}"> | ||
| 17 | + {% trans 'App react' %} | ||
| 18 | + </a> | ||
| 19 | + </li> | ||
| 20 | + </ul> | ||
| 21 | + </div> | ||
| 22 | +</nav> |
app/apps/core/templatetags/__init__.py
0 → 100644
app/apps/core/templatetags/startswith.py
0 → 100644
app/apps/core/views.py
0 → 100644
app/apps/djangoapp/__init__.py
0 → 100644
app/apps/djangoapp/admin.py
0 → 100644
app/apps/djangoapp/apps.py
0 → 100644
app/apps/djangoapp/forms.py
0 → 100644
| 1 | +from django.utils.translation import ugettext_lazy as _ | ||
| 2 | +from django import forms | ||
| 3 | + | ||
| 4 | +from .models import Book | ||
| 5 | + | ||
| 6 | + | ||
| 7 | +class BookForm(forms.ModelForm): | ||
| 8 | + | ||
| 9 | + title = forms.CharField( | ||
| 10 | + label=_('Titulo'), | ||
| 11 | + max_length=250, | ||
| 12 | + required=False, | ||
| 13 | + widget=forms.TextInput( | ||
| 14 | + attrs={'class': 'form-control', 'placeholder': _('Titulo')} | ||
| 15 | + ) | ||
| 16 | + ) | ||
| 17 | + | ||
| 18 | + class Meta: | ||
| 19 | + model = Book | ||
| 20 | + fields = ('title',) | ||
| 21 | + | ||
| 22 | + def clean_title(self): | ||
| 23 | + """ | ||
| 24 | + Validación de titulo. | ||
| 25 | + :return: | ||
| 26 | + """ | ||
| 27 | + title = self.cleaned_data.get('title', None) | ||
| 28 | + | ||
| 29 | + if not title: | ||
| 30 | + raise forms.ValidationError(_('Este campo es obligatorio.')) | ||
| 31 | + if title[0].islower(): | ||
| 32 | + raise forms.ValidationError(_('El título debe empezar por una mayúscula.')) | ||
| 33 | + return title | ||
| 34 | + | ||
| 35 | + def __init__(self, *args, **kwargs): | ||
| 36 | + super().__init__(*args, **kwargs) |
| 1 | +# Generated by Django 3.1.6 on 2022-03-18 10:37 | ||
| 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='Book', | ||
| 16 | + fields=[ | ||
| 17 | + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | ||
| 18 | + ('created', models.DateTimeField(auto_now_add=True, null=True, verbose_name='Created')), | ||
| 19 | + ('modified', models.DateTimeField(auto_now=True, null=True, verbose_name='Modified')), | ||
| 20 | + ('title', models.CharField(blank=True, max_length=250, null=True)), | ||
| 21 | + ], | ||
| 22 | + options={ | ||
| 23 | + 'verbose_name': 'Book', | ||
| 24 | + 'verbose_name_plural': 'Books', | ||
| 25 | + }, | ||
| 26 | + ), | ||
| 27 | + ] |
app/apps/djangoapp/migrations/__init__.py
0 → 100644
app/apps/djangoapp/models.py
0 → 100644
| 1 | +from django.utils.translation import ugettext_lazy as _ | ||
| 2 | +from django.db import models | ||
| 3 | + | ||
| 4 | + | ||
| 5 | +class Book(models.Model): | ||
| 6 | + | ||
| 7 | + created = models.DateTimeField(verbose_name=_('Created'), null=True, blank=True, auto_now_add=True) | ||
| 8 | + modified = models.DateTimeField(verbose_name=_('Modified'), null=True, blank=True, auto_now=True) | ||
| 9 | + | ||
| 10 | + title = models.CharField(max_length=250, null=True, blank=True) | ||
| 11 | + | ||
| 12 | + class Meta: | ||
| 13 | + verbose_name = _('Book') | ||
| 14 | + verbose_name_plural = _('Books') | ||
| 15 | + | ||
| 16 | + def __str__(self): | ||
| 17 | + return self.title |
| 1 | +{% extends 'core/base.html' %} | ||
| 2 | +{% load static i18n %} | ||
| 3 | + | ||
| 4 | +{% block css %} | ||
| 5 | +{% endblock %} | ||
| 6 | + | ||
| 7 | +{% block content %} | ||
| 8 | +<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pb-2 mb-3 border-bottom"> | ||
| 9 | + <h1 class="h2">{% trans 'DjangoApp!' %}</h1> | ||
| 10 | +</div> | ||
| 11 | +<div class="col"> | ||
| 12 | + <form method="POST"> | ||
| 13 | + {% csrf_token %} | ||
| 14 | + <!-- title --> | ||
| 15 | + <div class="form-group {% if form.title.errors %} has-error {% endif %}"> | ||
| 16 | + {{ form.title.label_tag }} | ||
| 17 | + {{ form.title }} | ||
| 18 | + {% if form.title.help_text %} | ||
| 19 | + <span class="help-block">{{ form.title.help_text }}</span> | ||
| 20 | + {% endif %} | ||
| 21 | + {% for error in form.title.errors %} | ||
| 22 | + <span class="help-block">{{ error }}</span> | ||
| 23 | + {% endfor %} | ||
| 24 | + </div> | ||
| 25 | + <div class="d-flex justify-content-between"> | ||
| 26 | + <a href="{%url 'djangoapp:index' %}" class="btn btn-outline-danger">{% trans 'Volver' %} </a> | ||
| 27 | + <button type="submit" class="btn btn-primary">{% trans "Crear" %}</button> | ||
| 28 | + </div> | ||
| 29 | + </form> | ||
| 30 | +</div> | ||
| 31 | +{% endblock %} | ||
| 32 | + | ||
| 33 | +{% block javascript %} | ||
| 34 | +{% endblock %} |
| 1 | +{% extends 'core/base.html' %} | ||
| 2 | +{% load static i18n %} | ||
| 3 | + | ||
| 4 | +{% block css %} | ||
| 5 | +{% endblock %} | ||
| 6 | + | ||
| 7 | +{% block content %} | ||
| 8 | +<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pb-2 mb-3 border-bottom"> | ||
| 9 | + <h1 class="h2">{% trans 'DjangoApp!' %}</h1> | ||
| 10 | + <div class="btn-toolbar mb-2 mb-md-0"> | ||
| 11 | + <a href="{% url 'djangoapp:create' %}" class="btn btn-sm btn-outline-secondary"> | ||
| 12 | + {% trans 'Crear' %} | ||
| 13 | + </a> | ||
| 14 | + </div> | ||
| 15 | +</div> | ||
| 16 | +<div class="col"> | ||
| 17 | + <table class="table table-striped table-hover"> | ||
| 18 | + <thead> | ||
| 19 | + <tr> | ||
| 20 | + <th>{% trans "ID" %}</th> | ||
| 21 | + <th>{% trans "Titulo" %}</th> | ||
| 22 | + <th></th> | ||
| 23 | + </tr> | ||
| 24 | + </thead> | ||
| 25 | + <tbody> | ||
| 26 | + {% for book in books %} | ||
| 27 | + <tr> | ||
| 28 | + <td>{{ book.id }}</td> | ||
| 29 | + <td>{{ book.title }}</td> | ||
| 30 | + <td class="text-right text-nowrap"> | ||
| 31 | + <a href="{% url 'djangoapp:read' book.id %}" | ||
| 32 | + class="btn btn-outline-info"> | ||
| 33 | + {% trans 'Ver' %} | ||
| 34 | + </a> | ||
| 35 | + <a href="{% url 'djangoapp:update' book.id %}" | ||
| 36 | + class="btn btn-outline-primary"> | ||
| 37 | + {% trans 'Editar' %} | ||
| 38 | + </a> | ||
| 39 | + <a href="{% url 'djangoapp:delete' book.id %}" | ||
| 40 | + class="btn btn-outline-secondary"> | ||
| 41 | + {% trans 'Borrar' %} | ||
| 42 | + </a> | ||
| 43 | + </td> | ||
| 44 | + </tr> | ||
| 45 | + {% endfor %} | ||
| 46 | + </tbody> | ||
| 47 | + </table> | ||
| 48 | +</div> | ||
| 49 | +{% endblock %} | ||
| 50 | + | ||
| 51 | +{% block javascript %} | ||
| 52 | +{% endblock %} |
| 1 | +{% extends 'core/base.html' %} | ||
| 2 | +{% load static i18n %} | ||
| 3 | + | ||
| 4 | +{% block css %} | ||
| 5 | +{% endblock %} | ||
| 6 | + | ||
| 7 | +{% block content %} | ||
| 8 | +<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pb-2 mb-3 border-bottom"> | ||
| 9 | + <h1 class="h2">{% trans 'DjangoApp!' %}</h1> | ||
| 10 | + <div class="btn-toolbar mb-2 mb-md-0"> | ||
| 11 | + <div class="btn-group mr-2"> | ||
| 12 | + <a href="{% url 'djangoapp:update' book.id %}" class="btn btn-sm btn-outline-secondary">{% trans 'Editar' %}</a> | ||
| 13 | + <a href="{% url 'djangoapp:delete' book.id %}" class="btn btn-sm btn-outline-secondary">{% trans 'Borrar' %}</a> | ||
| 14 | + </div> | ||
| 15 | + <a href="{% url 'djangoapp:index' %}" class="btn btn-sm btn-outline-secondary"> | ||
| 16 | + {% trans 'Listar' %} | ||
| 17 | + </a> | ||
| 18 | + </div> | ||
| 19 | +</div> | ||
| 20 | +<div class="col"> | ||
| 21 | + <p>#{{ book.id }} {{ book.title }}</p> | ||
| 22 | + | ||
| 23 | +</div> | ||
| 24 | +{% endblock %} | ||
| 25 | + | ||
| 26 | +{% block javascript %} | ||
| 27 | +{% endblock %} |
| 1 | +{% extends 'core/base.html' %} | ||
| 2 | +{% load static i18n %} | ||
| 3 | + | ||
| 4 | +{% block css %} | ||
| 5 | +{% endblock %} | ||
| 6 | + | ||
| 7 | +{% block content %} | ||
| 8 | +<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pb-2 mb-3 border-bottom"> | ||
| 9 | + <h1 class="h2">{% trans 'DjangoApp!' %}</h1> | ||
| 10 | +</div> | ||
| 11 | +<div class="col"> | ||
| 12 | + <form method="POST"> | ||
| 13 | + {% csrf_token %} | ||
| 14 | + <!-- title --> | ||
| 15 | + <div class="form-group {% if form.title.errors %} has-error {% endif %}"> | ||
| 16 | + {{ form.title.label_tag }} | ||
| 17 | + {{ form.title }} | ||
| 18 | + {% if form.title.help_text %} | ||
| 19 | + <span class="help-block">{{ form.title.help_text }}</span> | ||
| 20 | + {% endif %} | ||
| 21 | + {% for error in form.title.errors %} | ||
| 22 | + <span class="help-block">{{ error }}</span> | ||
| 23 | + {% endfor %} | ||
| 24 | + </div> | ||
| 25 | + <div class="d-flex justify-content-between"> | ||
| 26 | + <a href="{%url 'djangoapp:index' %}" class="btn btn-outline-danger">{% trans 'Volver' %} </a> | ||
| 27 | + <button type="submit" class="btn btn-primary">{% trans "Actualizar" %}</button> | ||
| 28 | + </div> | ||
| 29 | + </form> | ||
| 30 | +</div> | ||
| 31 | +{% endblock %} | ||
| 32 | + | ||
| 33 | +{% block javascript %} | ||
| 34 | +{% endblock %} |
app/apps/djangoapp/tests.py
0 → 100644
app/apps/djangoapp/urls.py
0 → 100644
| 1 | +from django.urls import path, include | ||
| 2 | + | ||
| 3 | +from . import views | ||
| 4 | + | ||
| 5 | +app_name = 'djangoapp' | ||
| 6 | +urlpatterns = [ | ||
| 7 | + | ||
| 8 | + path('djangoapp/', include(([ | ||
| 9 | + path('', views.index, name='index'), | ||
| 10 | + path('create', views.create, name='create'), | ||
| 11 | + path('read/<book_id>', views.read, name='read'), | ||
| 12 | + path('update/<book_id>', views.update, name='update'), | ||
| 13 | + path('delete/<book_id>', views.delete, name='delete'), | ||
| 14 | + ]))) | ||
| 15 | + | ||
| 16 | + | ||
| 17 | +] |
app/apps/djangoapp/views.py
0 → 100644
| 1 | +from django.shortcuts import render, redirect | ||
| 2 | + | ||
| 3 | +from .forms import BookForm | ||
| 4 | +from .models import Book | ||
| 5 | + | ||
| 6 | + | ||
| 7 | +def index(request): | ||
| 8 | + """ | ||
| 9 | + -- INDEX -- | ||
| 10 | + :param request: | ||
| 11 | + :return: | ||
| 12 | + """ | ||
| 13 | + books = Book.objects.all() | ||
| 14 | + | ||
| 15 | + return render(request, 'djangoapp/index.html', { | ||
| 16 | + 'books': books | ||
| 17 | + }) | ||
| 18 | + | ||
| 19 | + | ||
| 20 | +def create(request): | ||
| 21 | + """ | ||
| 22 | + -- CREATE -- | ||
| 23 | + :param request: | ||
| 24 | + :return: | ||
| 25 | + """ | ||
| 26 | + | ||
| 27 | + form = BookForm() | ||
| 28 | + | ||
| 29 | + if request.method == 'POST': | ||
| 30 | + form = BookForm(request.POST) | ||
| 31 | + if form.is_valid(): | ||
| 32 | + instance = form.save(commit=False) | ||
| 33 | + instance.save() | ||
| 34 | + | ||
| 35 | + return redirect('djangoapp:index') | ||
| 36 | + | ||
| 37 | + return render(request, 'djangoapp/create.html', { | ||
| 38 | + 'form': form | ||
| 39 | + }) | ||
| 40 | + | ||
| 41 | + | ||
| 42 | +def read(request, book_id): | ||
| 43 | + """ | ||
| 44 | + -- READ -- | ||
| 45 | + :param request: | ||
| 46 | + :param id: | ||
| 47 | + :return: | ||
| 48 | + """ | ||
| 49 | + book = Book.objects.get(pk=book_id) | ||
| 50 | + | ||
| 51 | + return render(request, 'djangoapp/read.html', { | ||
| 52 | + 'book': book | ||
| 53 | + }) | ||
| 54 | + | ||
| 55 | + | ||
| 56 | +def update(request, book_id): | ||
| 57 | + """ | ||
| 58 | + -- CREATE -- | ||
| 59 | + :param request: | ||
| 60 | + :return: | ||
| 61 | + """ | ||
| 62 | + | ||
| 63 | + book = Book.objects.get(pk=book_id) | ||
| 64 | + | ||
| 65 | + form = BookForm(instance=book) | ||
| 66 | + | ||
| 67 | + if request.method == 'POST': | ||
| 68 | + form = BookForm(request.POST, instance=book) | ||
| 69 | + if form.is_valid(): | ||
| 70 | + instance = form.save(commit=False) | ||
| 71 | + instance.save() | ||
| 72 | + | ||
| 73 | + return redirect('djangoapp:index') | ||
| 74 | + | ||
| 75 | + return render(request, 'djangoapp/update.html', { | ||
| 76 | + 'form': form | ||
| 77 | + }) | ||
| 78 | + | ||
| 79 | + | ||
| 80 | +def delete(request, book_id): | ||
| 81 | + """ | ||
| 82 | + -- DELETE -- | ||
| 83 | + :param request: | ||
| 84 | + :param book_id: | ||
| 85 | + :return: | ||
| 86 | + """ | ||
| 87 | + | ||
| 88 | + Book.objects.get(pk=book_id).delete() | ||
| 89 | + | ||
| 90 | + return redirect('djangoapp:index') |
app/apps/reactapp/__init__.py
0 → 100644
app/apps/reactapp/admin.py
0 → 100644
app/apps/reactapp/apps.py
0 → 100644
app/apps/reactapp/forms.py
0 → 100644
| 1 | +from django.utils.translation import ugettext_lazy as _ | ||
| 2 | +from django import forms | ||
| 3 | + | ||
| 4 | +from .models import Book | ||
| 5 | + | ||
| 6 | + | ||
| 7 | +class BookForm(forms.ModelForm): | ||
| 8 | + | ||
| 9 | + title = forms.CharField( | ||
| 10 | + label=_('Titulo'), | ||
| 11 | + max_length=250, | ||
| 12 | + required=False, | ||
| 13 | + widget=forms.TextInput( | ||
| 14 | + attrs={'class': 'form-control', 'placeholder': _('Titulo')} | ||
| 15 | + ) | ||
| 16 | + ) | ||
| 17 | + | ||
| 18 | + class Meta: | ||
| 19 | + model = Book | ||
| 20 | + fields = ('title',) | ||
| 21 | + | ||
| 22 | + def clean_title(self): | ||
| 23 | + """ | ||
| 24 | + Validación de titulo. | ||
| 25 | + :return: | ||
| 26 | + """ | ||
| 27 | + title = self.cleaned_data.get('title', None) | ||
| 28 | + | ||
| 29 | + if not title: | ||
| 30 | + raise forms.ValidationError(_('Este campo es obligatorio.')) | ||
| 31 | + if title[0].islower(): | ||
| 32 | + raise forms.ValidationError(_('El título debe empezar por una mayúscula.')) | ||
| 33 | + return title | ||
| 34 | + | ||
| 35 | + def __init__(self, *args, **kwargs): | ||
| 36 | + super().__init__(*args, **kwargs) |
app/apps/reactapp/migrations/0001_initial.py
0 → 100644
| 1 | +# Generated by Django 3.1.6 on 2022-03-18 10:37 | ||
| 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='Book', | ||
| 16 | + fields=[ | ||
| 17 | + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | ||
| 18 | + ('created', models.DateTimeField(auto_now_add=True, null=True, verbose_name='Created')), | ||
| 19 | + ('modified', models.DateTimeField(auto_now=True, null=True, verbose_name='Modified')), | ||
| 20 | + ('title', models.CharField(blank=True, max_length=250, null=True)), | ||
| 21 | + ], | ||
| 22 | + options={ | ||
| 23 | + 'verbose_name': 'Book', | ||
| 24 | + 'verbose_name_plural': 'Books', | ||
| 25 | + }, | ||
| 26 | + ), | ||
| 27 | + ] |
app/apps/reactapp/migrations/__init__.py
0 → 100644
app/apps/reactapp/models.py
0 → 100644
| 1 | +from django.utils.translation import ugettext_lazy as _ | ||
| 2 | +from django.db import models | ||
| 3 | + | ||
| 4 | + | ||
| 5 | +class Book(models.Model): | ||
| 6 | + | ||
| 7 | + created = models.DateTimeField(verbose_name=_('Created'), null=True, blank=True, auto_now_add=True) | ||
| 8 | + modified = models.DateTimeField(verbose_name=_('Modified'), null=True, blank=True, auto_now=True) | ||
| 9 | + | ||
| 10 | + title = models.CharField(max_length=250, null=True, blank=True) | ||
| 11 | + | ||
| 12 | + class Meta: | ||
| 13 | + verbose_name = _('Book') | ||
| 14 | + verbose_name_plural = _('Books') | ||
| 15 | + | ||
| 16 | + def __str__(self): | ||
| 17 | + return self.title |
| 1 | +{% extends 'core/base.html' %} | ||
| 2 | +{% load static i18n %} | ||
| 3 | + | ||
| 4 | +{% block css %} | ||
| 5 | +{% endblock %} | ||
| 6 | + | ||
| 7 | +{% block content %} | ||
| 8 | +<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pb-2 mb-3 border-bottom"> | ||
| 9 | + <h1 class="h2">{% trans 'ReactApp!' %}</h1> | ||
| 10 | +</div> | ||
| 11 | +<div class="col"> | ||
| 12 | + <form method="POST"> | ||
| 13 | + {% csrf_token %} | ||
| 14 | + <!-- title --> | ||
| 15 | + <div class="form-group {% if form.title.errors %} has-error {% endif %}"> | ||
| 16 | + {{ form.title.label_tag }} | ||
| 17 | + {{ form.title }} | ||
| 18 | + {% if form.title.help_text %} | ||
| 19 | + <span class="help-block">{{ form.title.help_text }}</span> | ||
| 20 | + {% endif %} | ||
| 21 | + {% for error in form.title.errors %} | ||
| 22 | + <span class="help-block">{{ error }}</span> | ||
| 23 | + {% endfor %} | ||
| 24 | + </div> | ||
| 25 | + <div class="d-flex justify-content-between"> | ||
| 26 | + <a href="{%url 'reactapp:index' %}" class="btn btn-outline-danger">{% trans 'Volver' %} </a> | ||
| 27 | + <button type="submit" class="btn btn-primary">{% trans "Crear" %}</button> | ||
| 28 | + </div> | ||
| 29 | + </form> | ||
| 30 | +</div> | ||
| 31 | +{% endblock %} | ||
| 32 | + | ||
| 33 | +{% block javascript %} | ||
| 34 | +{% endblock %} |
| 1 | +{% extends 'core/base.html' %} | ||
| 2 | +{% load static i18n %} | ||
| 3 | + | ||
| 4 | +{% block css %} | ||
| 5 | +{% endblock %} | ||
| 6 | + | ||
| 7 | +{% block content %} | ||
| 8 | +<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pb-2 mb-3 border-bottom"> | ||
| 9 | + <h1 class="h2">{% trans 'ReactApp!' %}</h1> | ||
| 10 | + <div class="btn-toolbar mb-2 mb-md-0"> | ||
| 11 | + <a href="{% url 'reactapp:create' %}" class="btn btn-sm btn-outline-secondary"> | ||
| 12 | + {% trans 'Crear' %} | ||
| 13 | + </a> | ||
| 14 | + </div> | ||
| 15 | +</div> | ||
| 16 | +<div class="col"> | ||
| 17 | + <table class="table table-striped table-hover"> | ||
| 18 | + <thead> | ||
| 19 | + <tr> | ||
| 20 | + <th>{% trans "ID" %}</th> | ||
| 21 | + <th>{% trans "Titulo" %}</th> | ||
| 22 | + <th></th> | ||
| 23 | + </tr> | ||
| 24 | + </thead> | ||
| 25 | + <tbody> | ||
| 26 | + {% for book in books %} | ||
| 27 | + <tr> | ||
| 28 | + <td>{{ book.id }}</td> | ||
| 29 | + <td>{{ book.title }}</td> | ||
| 30 | + <td class="text-right text-nowrap"> | ||
| 31 | + <a href="{% url 'reactapp:read' book.id %}" | ||
| 32 | + class="btn btn-outline-info"> | ||
| 33 | + {% trans 'Ver' %} | ||
| 34 | + </a> | ||
| 35 | + <a href="{% url 'reactapp:update' book.id %}" | ||
| 36 | + class="btn btn-outline-primary"> | ||
| 37 | + {% trans 'Editar' %} | ||
| 38 | + </a> | ||
| 39 | + <a href="{% url 'reactapp:delete' book.id %}" | ||
| 40 | + class="btn btn-outline-secondary"> | ||
| 41 | + {% trans 'Borrar' %} | ||
| 42 | + </a> | ||
| 43 | + </td> | ||
| 44 | + </tr> | ||
| 45 | + {% endfor %} | ||
| 46 | + </tbody> | ||
| 47 | + </table> | ||
| 48 | +</div> | ||
| 49 | +{% endblock %} | ||
| 50 | + | ||
| 51 | +{% block javascript %} | ||
| 52 | +{% endblock %} |
| 1 | +{% extends 'core/base.html' %} | ||
| 2 | +{% load static i18n %} | ||
| 3 | + | ||
| 4 | +{% block css %} | ||
| 5 | +{% endblock %} | ||
| 6 | + | ||
| 7 | +{% block content %} | ||
| 8 | +<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pb-2 mb-3 border-bottom"> | ||
| 9 | + <h1 class="h2">{% trans 'ReactApp!' %}</h1> | ||
| 10 | + <div class="btn-toolbar mb-2 mb-md-0"> | ||
| 11 | + <div class="btn-group mr-2"> | ||
| 12 | + <a href="{% url 'reactapp:update' book.id %}" class="btn btn-sm btn-outline-secondary">{% trans 'Editar' %}</a> | ||
| 13 | + <a href="{% url 'reactapp:delete' book.id %}" class="btn btn-sm btn-outline-secondary">{% trans 'Borrar' %}</a> | ||
| 14 | + </div> | ||
| 15 | + <a href="{% url 'reactapp:index' %}" class="btn btn-sm btn-outline-secondary"> | ||
| 16 | + {% trans 'Listar' %} | ||
| 17 | + </a> | ||
| 18 | + </div> | ||
| 19 | +</div> | ||
| 20 | +<div class="col"> | ||
| 21 | + <p>#{{ book.id }} {{ book.title }}</p> | ||
| 22 | + | ||
| 23 | +</div> | ||
| 24 | +{% endblock %} | ||
| 25 | + | ||
| 26 | +{% block javascript %} | ||
| 27 | +{% endblock %} |
| 1 | +{% extends 'core/base.html' %} | ||
| 2 | +{% load static i18n %} | ||
| 3 | + | ||
| 4 | +{% block css %} | ||
| 5 | +{% endblock %} | ||
| 6 | + | ||
| 7 | +{% block content %} | ||
| 8 | +<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pb-2 mb-3 border-bottom"> | ||
| 9 | + <h1 class="h2">{% trans 'ReactApp!' %}</h1> | ||
| 10 | +</div> | ||
| 11 | +<div class="col"> | ||
| 12 | + <form method="POST"> | ||
| 13 | + {% csrf_token %} | ||
| 14 | + <!-- title --> | ||
| 15 | + <div class="form-group {% if form.title.errors %} has-error {% endif %}"> | ||
| 16 | + {{ form.title.label_tag }} | ||
| 17 | + {{ form.title }} | ||
| 18 | + {% if form.title.help_text %} | ||
| 19 | + <span class="help-block">{{ form.title.help_text }}</span> | ||
| 20 | + {% endif %} | ||
| 21 | + {% for error in form.title.errors %} | ||
| 22 | + <span class="help-block">{{ error }}</span> | ||
| 23 | + {% endfor %} | ||
| 24 | + </div> | ||
| 25 | + <div class="d-flex justify-content-between"> | ||
| 26 | + <a href="{%url 'reactapp:index' %}" class="btn btn-outline-danger">{% trans 'Volver' %} </a> | ||
| 27 | + <button type="submit" class="btn btn-primary">{% trans "Actualizar" %}</button> | ||
| 28 | + </div> | ||
| 29 | + </form> | ||
| 30 | +</div> | ||
| 31 | +{% endblock %} | ||
| 32 | + | ||
| 33 | +{% block javascript %} | ||
| 34 | +{% endblock %} |
app/apps/reactapp/tests.py
0 → 100644
app/apps/reactapp/urls.py
0 → 100644
| 1 | +from django.urls import path, include | ||
| 2 | + | ||
| 3 | +from . import views | ||
| 4 | + | ||
| 5 | +app_name = 'reactapp' | ||
| 6 | +urlpatterns = [ | ||
| 7 | + | ||
| 8 | + path('reactapp/', include(([ | ||
| 9 | + path('', views.index, name='index'), | ||
| 10 | + path('create', views.create, name='create'), | ||
| 11 | + path('read/<book_id>', views.read, name='read'), | ||
| 12 | + path('update/<book_id>', views.update, name='update'), | ||
| 13 | + path('delete/<book_id>', views.delete, name='delete'), | ||
| 14 | + ]))) | ||
| 15 | + | ||
| 16 | + | ||
| 17 | +] |
app/apps/reactapp/views.py
0 → 100644
| 1 | +from django.shortcuts import render, redirect | ||
| 2 | + | ||
| 3 | +from .forms import BookForm | ||
| 4 | +from .models import Book | ||
| 5 | + | ||
| 6 | + | ||
| 7 | +def index(request): | ||
| 8 | + """ | ||
| 9 | + -- INDEX -- | ||
| 10 | + :param request: | ||
| 11 | + :return: | ||
| 12 | + """ | ||
| 13 | + books = Book.objects.all() | ||
| 14 | + | ||
| 15 | + return render(request, 'reactapp/index.html', { | ||
| 16 | + 'books': books | ||
| 17 | + }) | ||
| 18 | + | ||
| 19 | + | ||
| 20 | +def create(request): | ||
| 21 | + """ | ||
| 22 | + -- CREATE -- | ||
| 23 | + :param request: | ||
| 24 | + :return: | ||
| 25 | + """ | ||
| 26 | + | ||
| 27 | + form = BookForm() | ||
| 28 | + | ||
| 29 | + if request.method == 'POST': | ||
| 30 | + form = BookForm(request.POST) | ||
| 31 | + if form.is_valid(): | ||
| 32 | + instance = form.save(commit=False) | ||
| 33 | + instance.save() | ||
| 34 | + | ||
| 35 | + return redirect('reactapp:index') | ||
| 36 | + | ||
| 37 | + return render(request, 'reactapp/create.html', { | ||
| 38 | + 'form': form | ||
| 39 | + }) | ||
| 40 | + | ||
| 41 | + | ||
| 42 | +def read(request, book_id): | ||
| 43 | + """ | ||
| 44 | + -- READ -- | ||
| 45 | + :param request: | ||
| 46 | + :param book_id: | ||
| 47 | + :return: | ||
| 48 | + """ | ||
| 49 | + book = Book.objects.get(pk=book_id) | ||
| 50 | + | ||
| 51 | + return render(request, 'reactapp/read.html', { | ||
| 52 | + 'book': book | ||
| 53 | + }) | ||
| 54 | + | ||
| 55 | + | ||
| 56 | +def update(request, book_id): | ||
| 57 | + """ | ||
| 58 | + -- CREATE -- | ||
| 59 | + :param request: | ||
| 60 | + :param book_id: | ||
| 61 | + :return: | ||
| 62 | + """ | ||
| 63 | + | ||
| 64 | + book = Book.objects.get(pk=book_id) | ||
| 65 | + | ||
| 66 | + form = BookForm(instance=book) | ||
| 67 | + | ||
| 68 | + if request.method == 'POST': | ||
| 69 | + form = BookForm(request.POST, instance=book) | ||
| 70 | + if form.is_valid(): | ||
| 71 | + instance = form.save(commit=False) | ||
| 72 | + instance.save() | ||
| 73 | + | ||
| 74 | + return redirect('reactapp:index') | ||
| 75 | + | ||
| 76 | + return render(request, 'reactapp/update.html', { | ||
| 77 | + 'form': form | ||
| 78 | + }) | ||
| 79 | + | ||
| 80 | + | ||
| 81 | +def delete(request, book_id): | ||
| 82 | + """ | ||
| 83 | + -- DELETE -- | ||
| 84 | + :param request: | ||
| 85 | + :param book_id: | ||
| 86 | + :return: | ||
| 87 | + """ | ||
| 88 | + | ||
| 89 | + Book.objects.get(pk=book_id).delete() | ||
| 90 | + | ||
| 91 | + return redirect('reactapp:index') |
app/apps/welcome/__init__.py
0 → 100644
app/apps/welcome/admin.py
0 → 100644
app/apps/welcome/apps.py
0 → 100644
app/apps/welcome/migrations/__init__.py
0 → 100644
app/apps/welcome/models.py
0 → 100644
app/apps/welcome/static/__init__.py
0 → 100644
app/apps/welcome/static/welcome/__init__.py
0 → 100644
14.4 KB
app/apps/welcome/templates/__init__.py
0 → 100644
| 1 | +{% extends 'core/base.html' %} | ||
| 2 | +{% load static i18n %} | ||
| 3 | + | ||
| 4 | +{% block css %} | ||
| 5 | +{% endblock %} | ||
| 6 | + | ||
| 7 | +{% block content %} | ||
| 8 | +<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pb-2 mb-3 border-bottom"> | ||
| 9 | + <h1 class="h2">{% trans 'Welcome!' %}</h1> | ||
| 10 | +</div> | ||
| 11 | +<div class="d-flex justify-content-center"> | ||
| 12 | + <a href="/admin"><img src="{% static 'welcome/images/pulpo.png' %}" class="img-fluid"></a> | ||
| 13 | +</div> | ||
| 14 | +{% endblock %} | ||
| 15 | + | ||
| 16 | +{% block javascript %} | ||
| 17 | +{% endblock %} |
app/apps/welcome/tests/__init__.py
0 → 100644
app/apps/welcome/tests/test_forms.py
0 → 100644
app/apps/welcome/tests/test_models.py
0 → 100644
app/apps/welcome/tests/test_views.py
0 → 100644
| 1 | +from django.test import TestCase | ||
| 2 | + | ||
| 3 | + | ||
| 4 | +# Create your tests here. | ||
| 5 | +from django.urls import reverse | ||
| 6 | + | ||
| 7 | + | ||
| 8 | +class WelcomeIndexTest(TestCase): | ||
| 9 | + @classmethod | ||
| 10 | + def setUpTestData(cls): | ||
| 11 | + # print("setUpTestData: Run once to set up non-modified data for all class methods.") | ||
| 12 | + pass | ||
| 13 | + | ||
| 14 | + def setUp(self): | ||
| 15 | + # print("setUp: Run once for every test method to setup clean data.") | ||
| 16 | + pass | ||
| 17 | + | ||
| 18 | + def test_view_url_exists_at_desired_location(self): | ||
| 19 | + response = self.client.get('/') | ||
| 20 | + self.assertEqual(response.status_code, 200) | ||
| 21 | + | ||
| 22 | + def test_view_url_accessible_by_name(self): | ||
| 23 | + response = self.client.get(reverse('welcome:index')) | ||
| 24 | + self.assertEqual(response.status_code, 200) | ||
| 25 | + | ||
| 26 | + def test_view_uses_correct_template(self): | ||
| 27 | + response = self.client.get(reverse('welcome:index')) | ||
| 28 | + self.assertEqual(response.status_code, 200) | ||
| 29 | + self.assertTemplateUsed(response, 'welcome/index.html') |
app/apps/welcome/urls.py
0 → 100644
app/apps/welcome/views.py
0 → 100644
app/conf/__init__.py
0 → 100644
app/conf/asgi.py
0 → 100644
| 1 | +""" | ||
| 2 | +ASGI config. | ||
| 3 | + | ||
| 4 | +It exposes the ASGI callable as a module-level variable named ``application``. | ||
| 5 | + | ||
| 6 | +For more information on this file, see | ||
| 7 | +https://docs.djangoproject.com/en/3.0/howto/deployment/asgi/ | ||
| 8 | +""" | ||
| 9 | + | ||
| 10 | +import os | ||
| 11 | + | ||
| 12 | +from django.core.asgi import get_asgi_application | ||
| 13 | + | ||
| 14 | +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'conf.settings') | ||
| 15 | + | ||
| 16 | +application = get_asgi_application() |
app/conf/settings.py
0 → 100644
| 1 | +""" | ||
| 2 | +Django settings. | ||
| 3 | + | ||
| 4 | +Generated by 'django-admin startproject' using Django 3.0.5. | ||
| 5 | + | ||
| 6 | +For more information on this file, see | ||
| 7 | +https://docs.djangoproject.com/en/3.0/topics/settings/ | ||
| 8 | + | ||
| 9 | +For the full list of settings and their values, see | ||
| 10 | +https://docs.djangoproject.com/en/3.0/ref/settings/ | ||
| 11 | +""" | ||
| 12 | + | ||
| 13 | +from django.utils.translation import ugettext_lazy as _ | ||
| 14 | +import os | ||
| 15 | + | ||
| 16 | +# Build paths inside the project like this: os.path.join(BASE_DIR, ...) | ||
| 17 | +BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) | ||
| 18 | + | ||
| 19 | + | ||
| 20 | +# Quick-start development settings - unsuitable for production | ||
| 21 | +# See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/ | ||
| 22 | + | ||
| 23 | +SECRET_KEY = os.environ.get("SECRET_KEY") | ||
| 24 | + | ||
| 25 | +DEBUG = int(os.environ.get("DEBUG", default=0)) | ||
| 26 | + | ||
| 27 | +# 'DJANGO_ALLOWED_HOSTS' should be a single string of hosts with a space between each. | ||
| 28 | +# For example: 'DJANGO_ALLOWED_HOSTS=localhost 127.0.0.1 [::1]' | ||
| 29 | +ALLOWED_HOSTS = os.environ.get("DJANGO_ALLOWED_HOSTS").split(" ") | ||
| 30 | + | ||
| 31 | +SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https") | ||
| 32 | + | ||
| 33 | +# Application definition | ||
| 34 | + | ||
| 35 | +INSTALLED_APPS = [ | ||
| 36 | + "django.contrib.admin", | ||
| 37 | + "django.contrib.auth", | ||
| 38 | + "django.contrib.contenttypes", | ||
| 39 | + "django.contrib.sessions", | ||
| 40 | + "django.contrib.messages", | ||
| 41 | + "django.contrib.staticfiles", | ||
| 42 | + | ||
| 43 | + # external apps | ||
| 44 | + 'rosetta', | ||
| 45 | + | ||
| 46 | + "apps.core.apps.CoreConfig", | ||
| 47 | + "apps.welcome.apps.WelcomeConfig", | ||
| 48 | + "apps.djangoapp.apps.DjangoappConfig", | ||
| 49 | + "apps.reactapp.apps.ReactappConfig", | ||
| 50 | +] | ||
| 51 | + | ||
| 52 | +MIDDLEWARE = [ | ||
| 53 | + 'django.middleware.security.SecurityMiddleware', | ||
| 54 | + 'django.contrib.sessions.middleware.SessionMiddleware', | ||
| 55 | + 'django.middleware.locale.LocaleMiddleware', | ||
| 56 | + 'django.middleware.common.CommonMiddleware', | ||
| 57 | + 'django.middleware.csrf.CsrfViewMiddleware', | ||
| 58 | + 'django.contrib.auth.middleware.AuthenticationMiddleware', | ||
| 59 | + 'django.contrib.messages.middleware.MessageMiddleware', | ||
| 60 | + 'django.middleware.clickjacking.XFrameOptionsMiddleware', | ||
| 61 | +] | ||
| 62 | + | ||
| 63 | +ROOT_URLCONF = 'conf.urls' | ||
| 64 | + | ||
| 65 | +TEMPLATES = [ | ||
| 66 | + { | ||
| 67 | + 'BACKEND': 'django.template.backends.django.DjangoTemplates', | ||
| 68 | + 'DIRS': [], | ||
| 69 | + 'APP_DIRS': True, | ||
| 70 | + 'OPTIONS': { | ||
| 71 | + 'context_processors': [ | ||
| 72 | + 'django.template.context_processors.debug', | ||
| 73 | + 'django.template.context_processors.i18n', | ||
| 74 | + 'django.template.context_processors.request', | ||
| 75 | + 'django.contrib.auth.context_processors.auth', | ||
| 76 | + 'django.contrib.messages.context_processors.messages', | ||
| 77 | + ], | ||
| 78 | + }, | ||
| 79 | + }, | ||
| 80 | +] | ||
| 81 | + | ||
| 82 | +WSGI_APPLICATION = 'conf.wsgi.application' | ||
| 83 | + | ||
| 84 | + | ||
| 85 | +# Database | ||
| 86 | +# https://docs.djangoproject.com/en/3.0/ref/settings/#databases | ||
| 87 | + | ||
| 88 | +DATABASES = { | ||
| 89 | + "default": { | ||
| 90 | + "ENGINE": os.environ.get("SQL_ENGINE", "django.db.backends.sqlite3"), | ||
| 91 | + "NAME": os.environ.get("SQL_DATABASE", os.path.join(BASE_DIR, "db.sqlite3")), | ||
| 92 | + # "USER": os.environ.get("SQL_USER", "user"), | ||
| 93 | + # "PASSWORD": os.environ.get("SQL_PASSWORD", "password"), | ||
| 94 | + # "HOST": os.environ.get("SQL_HOST", "localhost"), | ||
| 95 | + # "PORT": os.environ.get("SQL_PORT", "5432"), | ||
| 96 | + # "OPTIONS": { | ||
| 97 | + # 'init_command': "SET sql_mode='STRICT_TRANS_TABLES'" | ||
| 98 | + # } | ||
| 99 | + } | ||
| 100 | +} | ||
| 101 | + | ||
| 102 | + | ||
| 103 | +# Password validation | ||
| 104 | +# https://docs.djangoproject.com/en/3.0/ref/settings/#auth-password-validators | ||
| 105 | + | ||
| 106 | +AUTH_PASSWORD_VALIDATORS = [ | ||
| 107 | + # { | ||
| 108 | + # 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', | ||
| 109 | + # }, | ||
| 110 | + { | ||
| 111 | + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', | ||
| 112 | + 'OPTIONS': { | ||
| 113 | + 'min_length': 4, | ||
| 114 | + } | ||
| 115 | + }, | ||
| 116 | + # { | ||
| 117 | + # 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', | ||
| 118 | + # }, | ||
| 119 | + # { | ||
| 120 | + # 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', | ||
| 121 | + # }, | ||
| 122 | +] | ||
| 123 | + | ||
| 124 | + | ||
| 125 | +# Internationalization | ||
| 126 | +# https://docs.djangoproject.com/en/3.0/topics/i18n/ | ||
| 127 | + | ||
| 128 | +PREFIX_DEFAULT_LANGUAGE = False | ||
| 129 | + | ||
| 130 | +LANGUAGE_CODE = 'es' | ||
| 131 | + | ||
| 132 | +TIME_ZONE = 'Europe/Madrid' | ||
| 133 | + | ||
| 134 | +USE_I18N = True | ||
| 135 | + | ||
| 136 | +USE_L10N = True | ||
| 137 | + | ||
| 138 | +USE_TZ = False | ||
| 139 | + | ||
| 140 | +USE_THOUSAND_SEPARATOR = True | ||
| 141 | + | ||
| 142 | +LOCALE_PATHS = ( | ||
| 143 | + os.path.join(BASE_DIR, 'locale'), | ||
| 144 | +) | ||
| 145 | + | ||
| 146 | +LANGUAGES = ( | ||
| 147 | + ('en', _('English')), | ||
| 148 | + ('es', _('Español')), | ||
| 149 | +) | ||
| 150 | + | ||
| 151 | +# Rosetta | ||
| 152 | +ROSETTA_WSGI_AUTO_RELOAD = True | ||
| 153 | +ROSETTA_SHOW_AT_ADMIN_PANEL = True | ||
| 154 | + | ||
| 155 | +# Static files (CSS, JavaScript, Images) | ||
| 156 | +# https://docs.djangoproject.com/en/3.0/howto/static-files/ | ||
| 157 | + | ||
| 158 | +MEDIA_URL = '/media/' | ||
| 159 | +MEDIA_ROOT = os.path.join(BASE_DIR, 'media') | ||
| 160 | + | ||
| 161 | +STATIC_URL = '/static/' | ||
| 162 | +STATIC_ROOT = os.path.join(BASE_DIR, 'static') | ||
| 163 | + |
app/conf/urls.py
0 → 100644
| 1 | +from django.conf.urls.i18n import i18n_patterns | ||
| 2 | +from django.contrib import admin | ||
| 3 | +from django.urls import path, include | ||
| 4 | +from django.conf import settings | ||
| 5 | +from django.conf.urls.static import static | ||
| 6 | + | ||
| 7 | + | ||
| 8 | +urlpatterns = [ | ||
| 9 | + path('admin/', admin.site.urls), | ||
| 10 | + path('i18n/', include('django.conf.urls.i18n')), | ||
| 11 | +] | ||
| 12 | + | ||
| 13 | +if bool(settings.DEBUG): | ||
| 14 | + urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) | ||
| 15 | + | ||
| 16 | +# Rosetta Plugin Translate | ||
| 17 | +if 'rosetta' in settings.INSTALLED_APPS: | ||
| 18 | + urlpatterns += [ | ||
| 19 | + path('rosetta/', include('rosetta.urls')) | ||
| 20 | + ] | ||
| 21 | + | ||
| 22 | +urlpatterns += i18n_patterns( | ||
| 23 | + # Apps: | ||
| 24 | + # Welcome | ||
| 25 | + path('', include('apps.welcome.urls', namespace='welcome')), | ||
| 26 | + # DjangoApp | ||
| 27 | + path('', include('apps.djangoapp.urls', namespace='djangoapp')), | ||
| 28 | + # ReactApp | ||
| 29 | + path('', include('apps.reactapp.urls', namespace='reactapp')), | ||
| 30 | + | ||
| 31 | + # Show hide LANGUAGE_CODE in URL | ||
| 32 | + prefix_default_language=settings.PREFIX_DEFAULT_LANGUAGE | ||
| 33 | +) |
app/conf/wsgi.py
0 → 100644
| 1 | +""" | ||
| 2 | +WSGI config. | ||
| 3 | + | ||
| 4 | +It exposes the WSGI callable as a module-level variable named ``application``. | ||
| 5 | + | ||
| 6 | +For more information on this file, see | ||
| 7 | +https://docs.djangoproject.com/en/3.0/howto/deployment/wsgi/ | ||
| 8 | +""" | ||
| 9 | + | ||
| 10 | +import os | ||
| 11 | + | ||
| 12 | +from django.core.wsgi import get_wsgi_application | ||
| 13 | + | ||
| 14 | +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'conf.settings') | ||
| 15 | + | ||
| 16 | +application = get_wsgi_application() |
app/entrypoint.sh
0 → 100644
| 1 | +#!/bin/sh | ||
| 2 | + | ||
| 3 | +if [ "$DATABASE" = "postgres" ] | ||
| 4 | +then | ||
| 5 | + echo "Waiting for postgres..." | ||
| 6 | + | ||
| 7 | + while ! nc -z $SQL_HOST $SQL_PORT; do | ||
| 8 | + sleep 0.1 | ||
| 9 | + done | ||
| 10 | + | ||
| 11 | + echo "PostgreSQL started" | ||
| 12 | +fi | ||
| 13 | + | ||
| 14 | +if [ "$DATABASE" = "mysql" ] | ||
| 15 | +then | ||
| 16 | + echo "Waiting for mysql..." | ||
| 17 | + | ||
| 18 | + while ! nc -z $SQL_HOST $SQL_PORT; do | ||
| 19 | + sleep 0.1 | ||
| 20 | + done | ||
| 21 | + | ||
| 22 | + echo "MySQL started" | ||
| 23 | +fi | ||
| 24 | + | ||
| 25 | +#python manage.py flush --no-input | ||
| 26 | +python manage.py migrate | ||
| 27 | + | ||
| 28 | +exec "$@" |
app/manage.py
0 → 100644
| 1 | +#!/usr/bin/env python | ||
| 2 | +"""Django's command-line utility for administrative tasks.""" | ||
| 3 | +import os | ||
| 4 | +import sys | ||
| 5 | + | ||
| 6 | + | ||
| 7 | +def main(): | ||
| 8 | + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'conf.settings') | ||
| 9 | + try: | ||
| 10 | + from django.core.management import execute_from_command_line | ||
| 11 | + except ImportError as exc: | ||
| 12 | + raise ImportError( | ||
| 13 | + "Couldn't import Django. Are you sure it's installed and " | ||
| 14 | + "available on your PYTHONPATH environment variable? Did you " | ||
| 15 | + "forget to activate a virtual environment?" | ||
| 16 | + ) from exc | ||
| 17 | + execute_from_command_line(sys.argv) | ||
| 18 | + | ||
| 19 | + | ||
| 20 | +if __name__ == '__main__': | ||
| 21 | + main() |
app/requirements.txt
0 → 100644
-
Please register or login to post a comment