From c4b247609a1e52c3f3969934efb021fac2aa7919 Mon Sep 17 00:00:00 2001 From: Celestino Rey Date: Fri, 9 Aug 2024 08:20:09 +0200 Subject: [PATCH] Cambios en Libros y proyectos de pruebas --- .../servicios/instance/repostajes.db | Bin 0 -> 20480 bytes Django-Auth/accounts/__init__.py | 0 Django-Auth/accounts/admin.py | 3 + Django-Auth/accounts/apps.py | 6 + Django-Auth/accounts/migrations/__init__.py | 0 Django-Auth/accounts/models.py | 3 + Django-Auth/accounts/tests.py | 3 + Django-Auth/accounts/urls.py | 9 ++ Django-Auth/accounts/views.py | 10 ++ Django-Auth/db.sqlite3 | Bin 0 -> 131072 bytes Django-Auth/django_project/__init__.py | 0 Django-Auth/django_project/asgi.py | 16 ++ Django-Auth/django_project/settings.py | 131 ++++++++++++++++ Django-Auth/django_project/urls.py | 26 ++++ Django-Auth/django_project/wsgi.py | 16 ++ Django-Auth/manage.py | 22 +++ Django-Auth/templates/base.html | 17 +++ Django-Auth/templates/home.html | 19 +++ .../templates/registration/logged_out.html | 14 ++ Django-Auth/templates/registration/login.html | 68 +++++++++ .../registration/login_tutorial.html | 13 ++ .../registration/password_change_done.html | 20 +++ .../registration/password_change_form.html | 64 ++++++++ .../registration/password_reset_complete.html | 17 +++ .../registration/password_reset_confirm.html | 47 ++++++ .../registration/password_reset_done.html | 17 +++ .../registration/password_reset_email.html | 14 ++ .../registration/password_reset_form.html | 31 ++++ .../templates/registration/signup.html | 13 ++ Libros/README.md | 13 +- Libros/biblioteca/biblioteca/settings.py | 4 +- Libros/biblioteca/biblioteca/urls.py | 2 + Libros/biblioteca/db.sqlite3 | Bin 147456 -> 147456 bytes .../gestion/templates/_branding.html | 2 +- .../gestion/templates/_cabecera.html | 40 +++-- .../gestion/templates/gestion/index.html | 27 ++++ Libros/biblioteca/gestion/urls.py | 6 +- Libros/biblioteca/gestion/views.py | 6 - django-custom-model/Pipfile | 13 ++ django-custom-model/Pipfile.lock | 141 ++++++++++++++++++ django-custom-model/README.md | 3 + django-custom-model/customuser.sqlite3 | Bin 0 -> 139264 bytes django-custom-model/db.sqlite3 | 0 django-custom-model/hola_django/__init__.py | 0 django-custom-model/hola_django/asgi.py | 16 ++ django-custom-model/hola_django/settings.py | 127 ++++++++++++++++ django-custom-model/hola_django/urls.py | 22 +++ django-custom-model/hola_django/wsgi.py | 16 ++ django-custom-model/manage.py | 22 +++ django-custom-model/profile_images/foto.jpeg | Bin 0 -> 3106 bytes django-custom-model/temp.txt | 38 +++++ django-custom-model/users/__init__.py | 0 django-custom-model/users/admin.py | 34 +++++ django-custom-model/users/apps.py | 6 + django-custom-model/users/forms.py | 17 +++ django-custom-model/users/managers.py | 34 +++++ .../users/migrations/0001_initial.py | 34 +++++ .../users/migrations/0002_customuser_foto.py | 18 +++ .../migrations/0003_alter_customuser_foto.py | 18 +++ .../users/migrations/__init__.py | 0 django-custom-model/users/models.py | 22 +++ django-custom-model/users/tests.py | 42 ++++++ django-custom-model/users/views.py | 3 + 63 files changed, 1299 insertions(+), 26 deletions(-) create mode 100644 AppsPy/RepostajesPy/servicios/instance/repostajes.db create mode 100644 Django-Auth/accounts/__init__.py create mode 100644 Django-Auth/accounts/admin.py create mode 100644 Django-Auth/accounts/apps.py create mode 100644 Django-Auth/accounts/migrations/__init__.py create mode 100644 Django-Auth/accounts/models.py create mode 100644 Django-Auth/accounts/tests.py create mode 100644 Django-Auth/accounts/urls.py create mode 100644 Django-Auth/accounts/views.py create mode 100644 Django-Auth/db.sqlite3 create mode 100644 Django-Auth/django_project/__init__.py create mode 100644 Django-Auth/django_project/asgi.py create mode 100644 Django-Auth/django_project/settings.py create mode 100644 Django-Auth/django_project/urls.py create mode 100644 Django-Auth/django_project/wsgi.py create mode 100755 Django-Auth/manage.py create mode 100644 Django-Auth/templates/base.html create mode 100644 Django-Auth/templates/home.html create mode 100644 Django-Auth/templates/registration/logged_out.html create mode 100644 Django-Auth/templates/registration/login.html create mode 100644 Django-Auth/templates/registration/login_tutorial.html create mode 100644 Django-Auth/templates/registration/password_change_done.html create mode 100644 Django-Auth/templates/registration/password_change_form.html create mode 100644 Django-Auth/templates/registration/password_reset_complete.html create mode 100644 Django-Auth/templates/registration/password_reset_confirm.html create mode 100644 Django-Auth/templates/registration/password_reset_done.html create mode 100644 Django-Auth/templates/registration/password_reset_email.html create mode 100644 Django-Auth/templates/registration/password_reset_form.html create mode 100644 Django-Auth/templates/registration/signup.html create mode 100644 Libros/biblioteca/gestion/templates/gestion/index.html create mode 100644 django-custom-model/Pipfile create mode 100644 django-custom-model/Pipfile.lock create mode 100644 django-custom-model/README.md create mode 100644 django-custom-model/customuser.sqlite3 create mode 100644 django-custom-model/db.sqlite3 create mode 100644 django-custom-model/hola_django/__init__.py create mode 100644 django-custom-model/hola_django/asgi.py create mode 100644 django-custom-model/hola_django/settings.py create mode 100644 django-custom-model/hola_django/urls.py create mode 100644 django-custom-model/hola_django/wsgi.py create mode 100755 django-custom-model/manage.py create mode 100644 django-custom-model/profile_images/foto.jpeg create mode 100644 django-custom-model/temp.txt create mode 100644 django-custom-model/users/__init__.py create mode 100644 django-custom-model/users/admin.py create mode 100644 django-custom-model/users/apps.py create mode 100644 django-custom-model/users/forms.py create mode 100644 django-custom-model/users/managers.py create mode 100644 django-custom-model/users/migrations/0001_initial.py create mode 100644 django-custom-model/users/migrations/0002_customuser_foto.py create mode 100644 django-custom-model/users/migrations/0003_alter_customuser_foto.py create mode 100644 django-custom-model/users/migrations/__init__.py create mode 100644 django-custom-model/users/models.py create mode 100644 django-custom-model/users/tests.py create mode 100644 django-custom-model/users/views.py diff --git a/AppsPy/RepostajesPy/servicios/instance/repostajes.db b/AppsPy/RepostajesPy/servicios/instance/repostajes.db new file mode 100644 index 0000000000000000000000000000000000000000..c11393ae33339325d74e8ae187561e2a576392f8 GIT binary patch literal 20480 zcmeI&O>fgk7y#gzB(0N_u8~j`0b(;nNSi1wRniS}%_+vs0NgQl< zw?*1Yt<+sYJ056%syT)(ns}Ulha$(GA|CV4 zzMEzZC?Eg=AOHd&00JNY0w4eaAn;iNySE}-VsaAijrqFKq%Q3^p0D4b-hOLjK~oDg zmDCFJWtHsrlT_zzk$9|5&4x~{1hWRa@3y?5;Z56jo#8_k z^~??0_MM>9)j9Atf1g5|V?xx~Z- z-refvwBb=VsG$Ry1U*M25e&EW7TsSib109F?s>mBu60C2c#5v*1WM;YKwm1rkXjYi*inv<+?$$q9R&G&d7@yOPY}c!BR5W49#YZ8JaiqIWw21 zhD@nN6~$C!DW~YNp!f~y+MeCMeeq6*-j1`pF#kVd8x#-#0T2KI5C8!X009sH0T2KI z5CDO%N8ngE8SDS%@ZtIYYsA0)dJ=?8KmY_l00ck)1V8`;KmY_l00cnbn-e(0{$+4t z;&gJpazhq#mMDn1rR6Jzoc|AYJgQ9h0Mm;Ar{U;M9pne9LU0T2KI5C8!X009sH z0T2KI5CDO1RbX;7h9<)pb2ugm(#*7wot8!X+nUo z=GO3=z3(4uPl`8o=w_n$f@!)(fV)i|p{aV}r literal 0 HcmV?d00001 diff --git a/Django-Auth/accounts/__init__.py b/Django-Auth/accounts/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Django-Auth/accounts/admin.py b/Django-Auth/accounts/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/Django-Auth/accounts/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/Django-Auth/accounts/apps.py b/Django-Auth/accounts/apps.py new file mode 100644 index 0000000..3e3c765 --- /dev/null +++ b/Django-Auth/accounts/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class AccountsConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'accounts' diff --git a/Django-Auth/accounts/migrations/__init__.py b/Django-Auth/accounts/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Django-Auth/accounts/models.py b/Django-Auth/accounts/models.py new file mode 100644 index 0000000..71a8362 --- /dev/null +++ b/Django-Auth/accounts/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/Django-Auth/accounts/tests.py b/Django-Auth/accounts/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/Django-Auth/accounts/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/Django-Auth/accounts/urls.py b/Django-Auth/accounts/urls.py new file mode 100644 index 0000000..a10de07 --- /dev/null +++ b/Django-Auth/accounts/urls.py @@ -0,0 +1,9 @@ +# accounts/urls.py +from django.urls import path + +from .views import SignUpView + + +urlpatterns = [ + path("signup/", SignUpView.as_view(), name="signup"), +] diff --git a/Django-Auth/accounts/views.py b/Django-Auth/accounts/views.py new file mode 100644 index 0000000..496c56e --- /dev/null +++ b/Django-Auth/accounts/views.py @@ -0,0 +1,10 @@ +# accounts/views.py +from django.contrib.auth.forms import UserCreationForm +from django.urls import reverse_lazy +from django.views.generic import CreateView + + +class SignUpView(CreateView): + form_class = UserCreationForm + success_url = reverse_lazy("login") + template_name = "registration/signup.html" diff --git a/Django-Auth/db.sqlite3 b/Django-Auth/db.sqlite3 new file mode 100644 index 0000000000000000000000000000000000000000..134d2953cef0705e3efa60963bacf4bd51ce6770 GIT binary patch literal 131072 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 literal 0 HcmV?d00001 diff --git a/Django-Auth/django_project/__init__.py b/Django-Auth/django_project/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Django-Auth/django_project/asgi.py b/Django-Auth/django_project/asgi.py new file mode 100644 index 0000000..389abd2 --- /dev/null +++ b/Django-Auth/django_project/asgi.py @@ -0,0 +1,16 @@ +""" +ASGI config for django_project 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/5.1/howto/deployment/asgi/ +""" + +import os + +from django.core.asgi import get_asgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'django_project.settings') + +application = get_asgi_application() diff --git a/Django-Auth/django_project/settings.py b/Django-Auth/django_project/settings.py new file mode 100644 index 0000000..1f32f68 --- /dev/null +++ b/Django-Auth/django_project/settings.py @@ -0,0 +1,131 @@ +""" +Django settings for django_project project. + +Generated by 'django-admin startproject' using Django 5.1. + +For more information on this file, see +https://docs.djangoproject.com/en/5.1/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/5.1/ref/settings/ +""" + +from pathlib import Path + +# Build paths inside the project like this: BASE_DIR / 'subdir'. +BASE_DIR = Path(__file__).resolve().parent.parent + + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/5.1/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = 'django-insecure-0ji$fkweyrscq+#fg73b+him8zsw26$7!iaxvy^rpy^)h#=br$' + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +ALLOWED_HOSTS = [] + + +# Application definition + +INSTALLED_APPS = [ + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + 'accounts', +] + +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 = 'django_project.urls' + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + "DIRS": [BASE_DIR / "templates"], # new + '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 = 'django_project.wsgi.application' + + +# Database +# https://docs.djangoproject.com/en/5.1/ref/settings/#databases + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': BASE_DIR / 'db.sqlite3', + } +} + + +# Password validation +# https://docs.djangoproject.com/en/5.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/5.1/topics/i18n/ + +LANGUAGE_CODE = 'en-us' + +TIME_ZONE = 'UTC' + +USE_I18N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/5.1/howto/static-files/ + +STATIC_URL = 'static/' + +# Default primary key field type +# https://docs.djangoproject.com/en/5.1/ref/settings/#default-auto-field + +DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' + +# django_project/settings.py +LOGIN_REDIRECT_URL = "home" # new +LOGOUT_REDIRECT_URL = "home" # new + +# django_project/settings.py +EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend" # new diff --git a/Django-Auth/django_project/urls.py b/Django-Auth/django_project/urls.py new file mode 100644 index 0000000..0723cb7 --- /dev/null +++ b/Django-Auth/django_project/urls.py @@ -0,0 +1,26 @@ +""" +URL configuration for django_project project. + +The `urlpatterns` list routes URLs to views. For more information please see: + https://docs.djangoproject.com/en/5.1/topics/http/urls/ +Examples: +Function views + 1. Add an import: from my_app import views + 2. Add a URL to urlpatterns: path('', views.home, name='home') +Class-based views + 1. Add an import: from other_app.views import Home + 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') +Including another URLconf + 1. Import the include() function: from django.urls import include, path + 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) +""" +from django.contrib import admin +from django.urls import path, include +from django.views.generic.base import TemplateView # new + +urlpatterns = [ + path('admin/', admin.site.urls), + path("accounts/", include("accounts.urls")), # new + path("accounts/", include("django.contrib.auth.urls")), # new + path("", TemplateView.as_view(template_name="home.html"), name="home"), # new +] diff --git a/Django-Auth/django_project/wsgi.py b/Django-Auth/django_project/wsgi.py new file mode 100644 index 0000000..a62895a --- /dev/null +++ b/Django-Auth/django_project/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for django_project 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/5.1/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'django_project.settings') + +application = get_wsgi_application() diff --git a/Django-Auth/manage.py b/Django-Auth/manage.py new file mode 100755 index 0000000..5ffd8de --- /dev/null +++ b/Django-Auth/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', 'django_project.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/Django-Auth/templates/base.html b/Django-Auth/templates/base.html new file mode 100644 index 0000000..d557f0a --- /dev/null +++ b/Django-Auth/templates/base.html @@ -0,0 +1,17 @@ + + + + + + + {% block title %}Django Auth Tutorial{% endblock %} + + + +
+ {% block content %} + {% endblock %} +
+ + + diff --git a/Django-Auth/templates/home.html b/Django-Auth/templates/home.html new file mode 100644 index 0000000..fe92216 --- /dev/null +++ b/Django-Auth/templates/home.html @@ -0,0 +1,19 @@ + +{% extends "base.html" %} + +{% block title %}Home{% endblock %} + +{% block content %} +{% if user.is_authenticated %} +

Hi {{ user.username }}!

+

Password Change

+
+ {% csrf_token %} + +
+{% else %} +

You are not logged in

+

Password Reset

+

Log In

+{% endif %} +{% endblock %} \ No newline at end of file diff --git a/Django-Auth/templates/registration/logged_out.html b/Django-Auth/templates/registration/logged_out.html new file mode 100644 index 0000000..e9a5545 --- /dev/null +++ b/Django-Auth/templates/registration/logged_out.html @@ -0,0 +1,14 @@ +{% extends "admin/base_site.html" %} +{% load i18n %} + +{% block breadcrumbs %}{% endblock %} + +{% block nav-sidebar %}{% endblock %} + +{% block content %} + +

{% translate "Thanks for spending some quality time with the web site today." %}

+ +

{% translate 'Log in again' %}

+ +{% endblock %} diff --git a/Django-Auth/templates/registration/login.html b/Django-Auth/templates/registration/login.html new file mode 100644 index 0000000..b61d9ec --- /dev/null +++ b/Django-Auth/templates/registration/login.html @@ -0,0 +1,68 @@ +{% extends "admin/base_site.html" %} +{% load i18n static %} + +{% block extrastyle %}{{ block.super }} +{{ form.media }} +{% endblock %} + +{% block bodyclass %}{{ block.super }} login{% endblock %} + +{% block usertools %}{% endblock %} + +{% block nav-global %}{% endblock %} + +{% block nav-sidebar %}{% endblock %} + +{% block content_title %}{% endblock %} + +{% block nav-breadcrumbs %}{% endblock %} + +{% block content %} +{% if form.errors and not form.non_field_errors %} +

+{% blocktranslate count counter=form.errors.items|length %}Please correct the error below.{% plural %}Please correct the errors below.{% endblocktranslate %} +

+{% endif %} + +{% if form.non_field_errors %} +{% for error in form.non_field_errors %} +

+ {{ error }} +

+{% endfor %} +{% endif %} + +
+ +{% if user.is_authenticated %} +

+{% blocktranslate trimmed %} + You are authenticated as {{ username }}, but are not authorized to + access this page. Would you like to login to a different account? +{% endblocktranslate %} +

+{% endif %} + +
{% csrf_token %} +
+ {{ form.username.errors }} + {{ form.username.label_tag }} {{ form.username }} +
+
+ {{ form.password.errors }} + {{ form.password.label_tag }} {{ form.password }} + +
+ {% url 'admin_password_reset' as password_reset_url %} + {% if password_reset_url %} + + {% endif %} +
+ +
+
+ +
+{% endblock %} diff --git a/Django-Auth/templates/registration/login_tutorial.html b/Django-Auth/templates/registration/login_tutorial.html new file mode 100644 index 0000000..785b9a5 --- /dev/null +++ b/Django-Auth/templates/registration/login_tutorial.html @@ -0,0 +1,13 @@ + +{% extends "base.html" %} + +{% block title %}Login{% endblock %} + +{% block content %} +

Log In

+
+ {% csrf_token %} + {{ form }} + +
+{% endblock %} diff --git a/Django-Auth/templates/registration/password_change_done.html b/Django-Auth/templates/registration/password_change_done.html new file mode 100644 index 0000000..784ab37 --- /dev/null +++ b/Django-Auth/templates/registration/password_change_done.html @@ -0,0 +1,20 @@ +{% extends "admin/base_site.html" %} +{% load i18n %} +{% block userlinks %} + {% url 'django-admindocs-docroot' as docsroot %}{% if docsroot %}{% translate 'Documentation' %} / {% endif %}{% translate 'Change password' %} / +
+ {% csrf_token %} + +
+ {% include "admin/color_theme_toggle.html" %} +{% endblock %} +{% block breadcrumbs %} + +{% endblock %} + +{% block content %} +

{% translate 'Your password was changed.' %}

+{% endblock %} diff --git a/Django-Auth/templates/registration/password_change_form.html b/Django-Auth/templates/registration/password_change_form.html new file mode 100644 index 0000000..fde2373 --- /dev/null +++ b/Django-Auth/templates/registration/password_change_form.html @@ -0,0 +1,64 @@ +{% extends "admin/base_site.html" %} +{% load i18n static %} +{% block extrastyle %}{{ block.super }}{% endblock %} +{% block userlinks %} + {% url 'django-admindocs-docroot' as docsroot %}{% if docsroot %}{% translate 'Documentation' %} / {% endif %} {% translate 'Change password' %} / +
+ {% csrf_token %} + +
+ {% include "admin/color_theme_toggle.html" %} +{% endblock %} +{% block breadcrumbs %} + +{% endblock %} + +{% block content %}
+ +
{% csrf_token %} +
+{% if form.errors %} +

+ {% blocktranslate count counter=form.errors.items|length %}Please correct the error below.{% plural %}Please correct the errors below.{% endblocktranslate %} +

+{% endif %} + + +

{% translate 'Please enter your old password, for security’s sake, and then enter your new password twice so we can verify you typed it in correctly.' %}

+ +
+ +
+ {{ form.old_password.errors }} +
{{ form.old_password.label_tag }} {{ form.old_password }}
+
+ +
+ {{ form.new_password1.errors }} +
{{ form.new_password1.label_tag }} {{ form.new_password1 }}
+ {% if form.new_password1.help_text %} +
{{ form.new_password1.help_text|safe }}
+ {% endif %} +
+ +
+ {{ form.new_password2.errors }} +
{{ form.new_password2.label_tag }} {{ form.new_password2 }}
+ {% if form.new_password2.help_text %} +
{{ form.new_password2.help_text|safe }}
+ {% endif %} +
+ +
+ +
+ +
+ +
+
+ +{% endblock %} diff --git a/Django-Auth/templates/registration/password_reset_complete.html b/Django-Auth/templates/registration/password_reset_complete.html new file mode 100644 index 0000000..e6a383f --- /dev/null +++ b/Django-Auth/templates/registration/password_reset_complete.html @@ -0,0 +1,17 @@ +{% extends "admin/base_site.html" %} +{% load i18n %} + +{% block breadcrumbs %} + +{% endblock %} + +{% block content %} + +

{% translate "Your password has been set. You may go ahead and log in now." %}

+ +

{% translate 'Log in' %}

+ +{% endblock %} diff --git a/Django-Auth/templates/registration/password_reset_confirm.html b/Django-Auth/templates/registration/password_reset_confirm.html new file mode 100644 index 0000000..a07645c --- /dev/null +++ b/Django-Auth/templates/registration/password_reset_confirm.html @@ -0,0 +1,47 @@ +{% extends "admin/base_site.html" %} +{% load i18n static %} + +{% block extrastyle %}{{ block.super }}{% endblock %} +{% block breadcrumbs %} + +{% endblock %} + +{% block content %} + +{% if validlink %} + +

{% translate "Please enter your new password twice so we can verify you typed it in correctly." %}

+ +
{% csrf_token %} +
+ +
+ {{ form.new_password1.errors }} +
+ + {{ form.new_password1 }} +
+
+
+ {{ form.new_password2.errors }} +
+ + {{ form.new_password2 }} +
+
+
+
+ +
+
+ +{% else %} + +

{% translate "The password reset link was invalid, possibly because it has already been used. Please request a new password reset." %}

+ +{% endif %} + +{% endblock %} diff --git a/Django-Auth/templates/registration/password_reset_done.html b/Django-Auth/templates/registration/password_reset_done.html new file mode 100644 index 0000000..8b1971a --- /dev/null +++ b/Django-Auth/templates/registration/password_reset_done.html @@ -0,0 +1,17 @@ +{% extends "admin/base_site.html" %} +{% load i18n %} + +{% block breadcrumbs %} + +{% endblock %} + +{% block content %} + +

{% translate 'We’ve emailed you instructions for setting your password, if an account exists with the email you entered. You should receive them shortly.' %}

+ +

{% translate 'If you don’t receive an email, please make sure you’ve entered the address you registered with, and check your spam folder.' %}

+ +{% endblock %} diff --git a/Django-Auth/templates/registration/password_reset_email.html b/Django-Auth/templates/registration/password_reset_email.html new file mode 100644 index 0000000..6482209 --- /dev/null +++ b/Django-Auth/templates/registration/password_reset_email.html @@ -0,0 +1,14 @@ +{% load i18n %}{% autoescape off %} +{% blocktranslate %}You're receiving this email because you requested a password reset for your user account at {{ site_name }}.{% endblocktranslate %} + +{% translate "Please go to the following page and choose a new password:" %} +{% block reset_link %} +{{ protocol }}://{{ domain }}{% url 'password_reset_confirm' uidb64=uid token=token %} +{% endblock %} +{% translate 'Your username, in case you’ve forgotten:' %} {{ user.get_username }} + +{% translate "Thanks for using our site!" %} + +{% blocktranslate %}The {{ site_name }} team{% endblocktranslate %} + +{% endautoescape %} diff --git a/Django-Auth/templates/registration/password_reset_form.html b/Django-Auth/templates/registration/password_reset_form.html new file mode 100644 index 0000000..0edfea8 --- /dev/null +++ b/Django-Auth/templates/registration/password_reset_form.html @@ -0,0 +1,31 @@ +{% extends "admin/base_site.html" %} +{% load i18n static %} + +{% block extrastyle %}{{ block.super }}{% endblock %} +{% block breadcrumbs %} + +{% endblock %} + +{% block content %} + +

{% translate 'Forgotten your password? Enter your email address below, and we’ll email instructions for setting a new one.' %}

+ +
{% csrf_token %} +
+
+ {{ form.email.errors }} +
+ + {{ form.email }} +
+
+
+
+ +
+
+ +{% endblock %} diff --git a/Django-Auth/templates/registration/signup.html b/Django-Auth/templates/registration/signup.html new file mode 100644 index 0000000..5431eac --- /dev/null +++ b/Django-Auth/templates/registration/signup.html @@ -0,0 +1,13 @@ + +{% extends "base.html" %} + +{% block title %}Sign Up{% endblock %} + +{% block content %} +

Sign up

+
+ {% csrf_token %} + {{ form }} + +
+{% endblock %} diff --git a/Libros/README.md b/Libros/README.md index 2c57502..5f1a71c 100644 --- a/Libros/README.md +++ b/Libros/README.md @@ -1 +1,12 @@ -https://learndjango.com/tutorials/django-login-and-logout-tutorial \ No newline at end of file +https://learndjango.com/tutorials/django-login-and-logout-tutorial + + +Username: {{ user.username }} + +User Full name: {{ user.get_full_name }} + +User Group: {{ user.groups.all.0 }} + +Email: {{ user.email }} + +Session Started at: {{ user.last_login }} \ No newline at end of file diff --git a/Libros/biblioteca/biblioteca/settings.py b/Libros/biblioteca/biblioteca/settings.py index 182854f..2c494ee 100644 --- a/Libros/biblioteca/biblioteca/settings.py +++ b/Libros/biblioteca/biblioteca/settings.py @@ -124,5 +124,5 @@ STATIC_URL = 'static/' DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' LOGIN_URL = '/accounts/login/' -LOGIN_REDIRECT_URL = '/gestion/libros/' -LOGOUT_REDIRECT_URL = '/accounts/login/' \ No newline at end of file +LOGIN_REDIRECT_URL = '/gestion/libros' +LOGOUT_REDIRECT_URL = 'principal' \ No newline at end of file diff --git a/Libros/biblioteca/biblioteca/urls.py b/Libros/biblioteca/biblioteca/urls.py index 6688707..7ae0424 100644 --- a/Libros/biblioteca/biblioteca/urls.py +++ b/Libros/biblioteca/biblioteca/urls.py @@ -19,6 +19,7 @@ from django.urls import path, include from django.conf import settings from django.conf.urls.static import static from django.contrib.auth import views as auth_views +from django.views.generic.base import TemplateView # new urlpatterns = [ path('obreros/', admin.site.urls), @@ -26,6 +27,7 @@ urlpatterns = [ path('accounts/login/', auth_views.LoginView.as_view(), name='login'), path('accounts/logout/', auth_views.LogoutView.as_view(), name='logout'), + path("", TemplateView.as_view(template_name="gestion/index.html"), name="principal"), # new ] diff --git a/Libros/biblioteca/db.sqlite3 b/Libros/biblioteca/db.sqlite3 index 4aa591978f89e6aa36d18fec4d5ea0b95edd3488..7449b632920dc26a0c88bd6f8bf769dad28bf958 100644 GIT binary patch delta 993 zcmaiyO=#O@7{?`99aV_^wv?Q@#h!7tLY73ImSpHbk!w4NZN+xukA#xRmSox1S1jAI zU4re7vFkz(WrtnHVB}OnV7`q(uRHEC@EG*gLn#}K9k#<1SPvT;dwAh}US1x4|Noz7 zI>n|_?9;oje)hHq>z5w}wqW#1+4=&1>jD9Lp^MAe=b_2$9V7_N?h7|pg29`Z5OnGt zMI(=0T_%}$jAL=XVmg~p?slqUHA$h-wN)-Fvhn>x zrbiyg>m$!TIFad6pA_}t&V3Rm=?$FoPlO;7bUZ;*n-tFl7=}1sw^t_+G$Y|_B@`CE zLtq#c{#PaY)s!2@kzqUPxTucKzqi*gQ8iSz*Rt#<&esl%;>##_34zz( zCHNiudUf0R0X%*E488%Q*Vl^w`w9YofZxC`;MLXb>5l+K0~mb%^Rqi&q2I!{meJ4x z0^fjBAchu~v+qI^6~!PBhDR_a5RL9%aOCK5w4uvZQ&pmg$m6KiQVqrR+oNcz)pdIj zOE%T$2a#x2e)D*Adin_cd$ztKg4?7Sf?{wk;A2*>bss}syYT_CqNvLJ=qLChvV;WZ zP-qdHFP~k`K3+!P_bz8qc=9BQ+{k@Y61qf7^YC7q>+>wr)drkxQI2DetnLZf&|G;_ z-5r+ONmugPLSb7yZlw)tLmRansU{Je%nXIRQL<8{ojxvgQh9O1tab*5xm}leJDsf< zX~mRFRy9tE+Fp`uvR<-JRaAAt^s1`7%X;>4TuN5kgA$jKSglYi7YA%rvI|X7@R(FP zUvqZ%D*Qn?YZlC8@d0z<4hlPUw;~J+Mpqx?8+uym<6M8t3#x47aW6r*_3?f!QFd&* zVHQq!veep6ianDodV9I5PSZ83xD}QaWf}Wt`l~(2CRff9j zXNLw9neE6a&uhrZ>Bw7x@Bc(DWD$UD0uh=EZ$T1|W+}6mz$VAt`0*Dk0%&iP8t&9xyERBqLj4TY3i&86d z@(WU{CSS@|W!Ez|v@|y|Zz|YUz{q02#mxVnf&V@KZ~m{F1sfjnPk+CjQ4}cniGlwQ z|9AdRK*1;c+du7R6cPZ6Iy3O^i$zuoyh<3R;BM!q`?e0MfBUgFz+hmT2v nk&Ti64g>$4&4LA&_^02IXVL%)JYwK~1QfWzzx|Oulbiqmj< - + \ No newline at end of file diff --git a/Libros/biblioteca/gestion/templates/_cabecera.html b/Libros/biblioteca/gestion/templates/_cabecera.html index 92b73b6..57b87e4 100644 --- a/Libros/biblioteca/gestion/templates/_cabecera.html +++ b/Libros/biblioteca/gestion/templates/_cabecera.html @@ -15,15 +15,37 @@
@@ -45,7 +67,7 @@
{% endif %} - - {% if user.is_authenticated %} - - {% endif %} diff --git a/Libros/biblioteca/gestion/templates/gestion/index.html b/Libros/biblioteca/gestion/templates/gestion/index.html new file mode 100644 index 0000000..f83ed47 --- /dev/null +++ b/Libros/biblioteca/gestion/templates/gestion/index.html @@ -0,0 +1,27 @@ +{% extends 'base.html' %} + +{% block content %} + +
+ +

Introducción

+ + + +
+ +{% endblock %} diff --git a/Libros/biblioteca/gestion/urls.py b/Libros/biblioteca/gestion/urls.py index 2edf7ba..f687dcc 100644 --- a/Libros/biblioteca/gestion/urls.py +++ b/Libros/biblioteca/gestion/urls.py @@ -1,16 +1,18 @@ from django.urls import path + from . import views urlpatterns = [ - path('autores/', views.lista_autores, name='lista_autores'), + path('autores', views.lista_autores, name='lista_autores'), path('autores/nuevo/', views.nuevo_autor, name='nuevo_autor'), path('autores//', views.detalle_autor, name='detalle_autor'), path('autores//editar/', views.editar_autor, name='editar_autor'), path('autores//eliminar/', views.eliminar_autor, name='eliminar_autor'), - path('libros/', views.lista_libros, name='lista_libros'), + path('libros', views.lista_libros, name='lista_libros'), path('libros/nuevo/', views.nuevo_libro, name='nuevo_libro'), path('libros//', views.detalle_libro, name='detalle_libro'), path('libros//editar/', views.editar_libro, name='editar_libro'), path('libros//eliminar/', views.eliminar_libro, name='eliminar_libro'), + ] diff --git a/Libros/biblioteca/gestion/views.py b/Libros/biblioteca/gestion/views.py index 8df04ba..45d20ce 100644 --- a/Libros/biblioteca/gestion/views.py +++ b/Libros/biblioteca/gestion/views.py @@ -84,9 +84,3 @@ def eliminar_libro(request, libro_id): libro = get_object_or_404(Libro, pk=libro_id) libro.delete() return redirect('lista_libros') - - -@login_required -def user_logout(request): - logout(request) - return render(request, 'registration/logged_out.html', {}) \ No newline at end of file diff --git a/django-custom-model/Pipfile b/django-custom-model/Pipfile new file mode 100644 index 0000000..42133fe --- /dev/null +++ b/django-custom-model/Pipfile @@ -0,0 +1,13 @@ +[[source]] +url = "https://pypi.org/simple" +verify_ssl = true +name = "pypi" + +[packages] +django = "*" +pillow = "*" + +[dev-packages] + +[requires] +python_version = "3.10" diff --git a/django-custom-model/Pipfile.lock b/django-custom-model/Pipfile.lock new file mode 100644 index 0000000..b925b6c --- /dev/null +++ b/django-custom-model/Pipfile.lock @@ -0,0 +1,141 @@ +{ + "_meta": { + "hash": { + "sha256": "f0a6b10e1349a882b824f490c90a5b0b71905386b17672678bed9a1bfabb658a" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3.10" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "asgiref": { + "hashes": [ + "sha256:3e1e3ecc849832fe52ccf2cb6686b7a55f82bb1d6aee72a58826471390335e47", + "sha256:c343bd80a0bec947a9860adb4c432ffa7db769836c64238fc34bdc3fec84d590" + ], + "markers": "python_version >= '3.8'", + "version": "==3.8.1" + }, + "django": { + "hashes": [ + "sha256:848a5980e8efb76eea70872fb0e4bc5e371619c70fffbe48e3e1b50b2c09455d", + "sha256:d3b811bf5371a26def053d7ee42a9df1267ef7622323fe70a601936725aa4557" + ], + "index": "pypi", + "markers": "python_version >= '3.10'", + "version": "==5.1" + }, + "pillow": { + "hashes": [ + "sha256:02a2be69f9c9b8c1e97cf2713e789d4e398c751ecfd9967c18d0ce304efbf885", + "sha256:030abdbe43ee02e0de642aee345efa443740aa4d828bfe8e2eb11922ea6a21ea", + "sha256:06b2f7898047ae93fad74467ec3d28fe84f7831370e3c258afa533f81ef7f3df", + "sha256:0755ffd4a0c6f267cccbae2e9903d95477ca2f77c4fcf3a3a09570001856c8a5", + "sha256:0a9ec697746f268507404647e531e92889890a087e03681a3606d9b920fbee3c", + "sha256:0ae24a547e8b711ccaaf99c9ae3cd975470e1a30caa80a6aaee9a2f19c05701d", + "sha256:134ace6dc392116566980ee7436477d844520a26a4b1bd4053f6f47d096997fd", + "sha256:166c1cd4d24309b30d61f79f4a9114b7b2313d7450912277855ff5dfd7cd4a06", + "sha256:1b5dea9831a90e9d0721ec417a80d4cbd7022093ac38a568db2dd78363b00908", + "sha256:1d846aea995ad352d4bdcc847535bd56e0fd88d36829d2c90be880ef1ee4668a", + "sha256:1ef61f5dd14c300786318482456481463b9d6b91ebe5ef12f405afbba77ed0be", + "sha256:297e388da6e248c98bc4a02e018966af0c5f92dfacf5a5ca22fa01cb3179bca0", + "sha256:298478fe4f77a4408895605f3482b6cc6222c018b2ce565c2b6b9c354ac3229b", + "sha256:29dbdc4207642ea6aad70fbde1a9338753d33fb23ed6956e706936706f52dd80", + "sha256:2db98790afc70118bd0255c2eeb465e9767ecf1f3c25f9a1abb8ffc8cfd1fe0a", + "sha256:32cda9e3d601a52baccb2856b8ea1fc213c90b340c542dcef77140dfa3278a9e", + "sha256:37fb69d905be665f68f28a8bba3c6d3223c8efe1edf14cc4cfa06c241f8c81d9", + "sha256:416d3a5d0e8cfe4f27f574362435bc9bae57f679a7158e0096ad2beb427b8696", + "sha256:43efea75eb06b95d1631cb784aa40156177bf9dd5b4b03ff38979e048258bc6b", + "sha256:4b35b21b819ac1dbd1233317adeecd63495f6babf21b7b2512d244ff6c6ce309", + "sha256:4d9667937cfa347525b319ae34375c37b9ee6b525440f3ef48542fcf66f2731e", + "sha256:5161eef006d335e46895297f642341111945e2c1c899eb406882a6c61a4357ab", + "sha256:543f3dc61c18dafb755773efc89aae60d06b6596a63914107f75459cf984164d", + "sha256:551d3fd6e9dc15e4c1eb6fc4ba2b39c0c7933fa113b220057a34f4bb3268a060", + "sha256:59291fb29317122398786c2d44427bbd1a6d7ff54017075b22be9d21aa59bd8d", + "sha256:5b001114dd152cfd6b23befeb28d7aee43553e2402c9f159807bf55f33af8a8d", + "sha256:5b4815f2e65b30f5fbae9dfffa8636d992d49705723fe86a3661806e069352d4", + "sha256:5dc6761a6efc781e6a1544206f22c80c3af4c8cf461206d46a1e6006e4429ff3", + "sha256:5e84b6cc6a4a3d76c153a6b19270b3526a5a8ed6b09501d3af891daa2a9de7d6", + "sha256:6209bb41dc692ddfee4942517c19ee81b86c864b626dbfca272ec0f7cff5d9fb", + "sha256:673655af3eadf4df6b5457033f086e90299fdd7a47983a13827acf7459c15d94", + "sha256:6c762a5b0997f5659a5ef2266abc1d8851ad7749ad9a6a5506eb23d314e4f46b", + "sha256:7086cc1d5eebb91ad24ded9f58bec6c688e9f0ed7eb3dbbf1e4800280a896496", + "sha256:73664fe514b34c8f02452ffb73b7a92c6774e39a647087f83d67f010eb9a0cf0", + "sha256:76a911dfe51a36041f2e756b00f96ed84677cdeb75d25c767f296c1c1eda1319", + "sha256:780c072c2e11c9b2c7ca37f9a2ee8ba66f44367ac3e5c7832afcfe5104fd6d1b", + "sha256:7928ecbf1ece13956b95d9cbcfc77137652b02763ba384d9ab508099a2eca856", + "sha256:7970285ab628a3779aecc35823296a7869f889b8329c16ad5a71e4901a3dc4ef", + "sha256:7a8d4bade9952ea9a77d0c3e49cbd8b2890a399422258a77f357b9cc9be8d680", + "sha256:7c1ee6f42250df403c5f103cbd2768a28fe1a0ea1f0f03fe151c8741e1469c8b", + "sha256:7dfecdbad5c301d7b5bde160150b4db4c659cee2b69589705b6f8a0c509d9f42", + "sha256:812f7342b0eee081eaec84d91423d1b4650bb9828eb53d8511bcef8ce5aecf1e", + "sha256:866b6942a92f56300012f5fbac71f2d610312ee65e22f1aa2609e491284e5597", + "sha256:86dcb5a1eb778d8b25659d5e4341269e8590ad6b4e8b44d9f4b07f8d136c414a", + "sha256:87dd88ded2e6d74d31e1e0a99a726a6765cda32d00ba72dc37f0651f306daaa8", + "sha256:8bc1a764ed8c957a2e9cacf97c8b2b053b70307cf2996aafd70e91a082e70df3", + "sha256:8d4d5063501b6dd4024b8ac2f04962d661222d120381272deea52e3fc52d3736", + "sha256:8f0aef4ef59694b12cadee839e2ba6afeab89c0f39a3adc02ed51d109117b8da", + "sha256:930044bb7679ab003b14023138b50181899da3f25de50e9dbee23b61b4de2126", + "sha256:950be4d8ba92aca4b2bb0741285a46bfae3ca699ef913ec8416c1b78eadd64cd", + "sha256:961a7293b2457b405967af9c77dcaa43cc1a8cd50d23c532e62d48ab6cdd56f5", + "sha256:9b885f89040bb8c4a1573566bbb2f44f5c505ef6e74cec7ab9068c900047f04b", + "sha256:9f4727572e2918acaa9077c919cbbeb73bd2b3ebcfe033b72f858fc9fbef0026", + "sha256:a02364621fe369e06200d4a16558e056fe2805d3468350df3aef21e00d26214b", + "sha256:a985e028fc183bf12a77a8bbf36318db4238a3ded7fa9df1b9a133f1cb79f8fc", + "sha256:ac1452d2fbe4978c2eec89fb5a23b8387aba707ac72810d9490118817d9c0b46", + "sha256:b15e02e9bb4c21e39876698abf233c8c579127986f8207200bc8a8f6bb27acf2", + "sha256:b2724fdb354a868ddf9a880cb84d102da914e99119211ef7ecbdc613b8c96b3c", + "sha256:bbc527b519bd3aa9d7f429d152fea69f9ad37c95f0b02aebddff592688998abe", + "sha256:bcd5e41a859bf2e84fdc42f4edb7d9aba0a13d29a2abadccafad99de3feff984", + "sha256:bd2880a07482090a3bcb01f4265f1936a903d70bc740bfcb1fd4e8a2ffe5cf5a", + "sha256:bee197b30783295d2eb680b311af15a20a8b24024a19c3a26431ff83eb8d1f70", + "sha256:bf2342ac639c4cf38799a44950bbc2dfcb685f052b9e262f446482afaf4bffca", + "sha256:c76e5786951e72ed3686e122d14c5d7012f16c8303a674d18cdcd6d89557fc5b", + "sha256:cbed61494057c0f83b83eb3a310f0bf774b09513307c434d4366ed64f4128a91", + "sha256:cfdd747216947628af7b259d274771d84db2268ca062dd5faf373639d00113a3", + "sha256:d7480af14364494365e89d6fddc510a13e5a2c3584cb19ef65415ca57252fb84", + "sha256:dbc6ae66518ab3c5847659e9988c3b60dc94ffb48ef9168656e0019a93dbf8a1", + "sha256:dc3e2db6ba09ffd7d02ae9141cfa0ae23393ee7687248d46a7507b75d610f4f5", + "sha256:dfe91cb65544a1321e631e696759491ae04a2ea11d36715eca01ce07284738be", + "sha256:e4d49b85c4348ea0b31ea63bc75a9f3857869174e2bf17e7aba02945cd218e6f", + "sha256:e4db64794ccdf6cb83a59d73405f63adbe2a1887012e308828596100a0b2f6cc", + "sha256:e553cad5179a66ba15bb18b353a19020e73a7921296a7979c4a2b7f6a5cd57f9", + "sha256:e88d5e6ad0d026fba7bdab8c3f225a69f063f116462c49892b0149e21b6c0a0e", + "sha256:ecd85a8d3e79cd7158dec1c9e5808e821feea088e2f69a974db5edf84dc53141", + "sha256:f5b92f4d70791b4a67157321c4e8225d60b119c5cc9aee8ecf153aace4aad4ef", + "sha256:f5f0c3e969c8f12dd2bb7e0b15d5c468b51e5017e01e2e867335c81903046a22", + "sha256:f7baece4ce06bade126fb84b8af1c33439a76d8a6fd818970215e0560ca28c27", + "sha256:ff25afb18123cea58a591ea0244b92eb1e61a1fd497bf6d6384f09bc3262ec3e", + "sha256:ff337c552345e95702c5fde3158acb0625111017d0e5f24bf3acdb9cc16b90d1" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==10.4.0" + }, + "sqlparse": { + "hashes": [ + "sha256:773dcbf9a5ab44a090f3441e2180efe2560220203dc2f8c0b0fa141e18b505e4", + "sha256:bb6b4df465655ef332548e24f08e205afc81b9ab86cb1c45657a7ff173a3a00e" + ], + "markers": "python_version >= '3.8'", + "version": "==0.5.1" + }, + "typing-extensions": { + "hashes": [ + "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", + "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8" + ], + "markers": "python_version < '3.11'", + "version": "==4.12.2" + } + }, + "develop": {} +} diff --git a/django-custom-model/README.md b/django-custom-model/README.md new file mode 100644 index 0000000..6b028e7 --- /dev/null +++ b/django-custom-model/README.md @@ -0,0 +1,3 @@ +## Fuente + +https://testdriven.io/blog/django-custom-user-model/ \ No newline at end of file diff --git a/django-custom-model/customuser.sqlite3 b/django-custom-model/customuser.sqlite3 new file mode 100644 index 0000000000000000000000000000000000000000..accc8503f9d826a77550044c40f3ce5a8782ebf1 GIT binary patch literal 139264 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 H-5L1@DM^6S literal 0 HcmV?d00001 diff --git a/django-custom-model/temp.txt b/django-custom-model/temp.txt new file mode 100644 index 0000000..a6def43 --- /dev/null +++ b/django-custom-model/temp.txt @@ -0,0 +1,38 @@ +Migrations for 'users': + users/migrations/0001_initial.py + + Create model CustomUser +Full migrations file '0001_initial.py': +# Generated by Django 5.1 on 2024-08-08 13:04 + +import django.utils.timezone +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('auth', '0012_alter_user_first_name_max_length'), + ] + + operations = [ + migrations.CreateModel( + name='CustomUser', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('password', models.CharField(max_length=128, verbose_name='password')), + ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')), + ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')), + ('email', models.EmailField(max_length=254, unique=True, verbose_name='email address')), + ('is_staff', models.BooleanField(default=False)), + ('is_active', models.BooleanField(default=True)), + ('date_joined', models.DateTimeField(default=django.utils.timezone.now)), + ('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.group', verbose_name='groups')), + ('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.permission', verbose_name='user permissions')), + ], + options={ + 'abstract': False, + }, + ), + ] diff --git a/django-custom-model/users/__init__.py b/django-custom-model/users/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/django-custom-model/users/admin.py b/django-custom-model/users/admin.py new file mode 100644 index 0000000..64b847a --- /dev/null +++ b/django-custom-model/users/admin.py @@ -0,0 +1,34 @@ +from django.contrib import admin +from django.contrib.auth.admin import UserAdmin + +from .forms import CustomUserCreationForm, CustomUserChangeForm +from .models import CustomUser + + +class CustomUserAdmin(UserAdmin): + add_form = CustomUserCreationForm + form = CustomUserChangeForm + model = CustomUser + list_display = ("email", "is_staff", "is_active","foto") + list_filter = ("email", "is_staff", "is_active",) + fieldsets = ( + (None, {"fields": ("email", "password")}), + ("Permissions", {"fields": ("is_staff", "is_active", "groups", "user_permissions")}), + ("Varios", {"fields": ("foto",)}), + ) + add_fieldsets = ( + (None, { + "classes": ("wide",), + "fields": ( + "email", "password1", "password2", "is_staff", + "is_active", "groups", "user_permissions" + )} + ), + ("Varios", {"fields": ("foto",)}), + + ) + search_fields = ("email",) + ordering = ("email",) + + +admin.site.register(CustomUser, CustomUserAdmin) diff --git a/django-custom-model/users/apps.py b/django-custom-model/users/apps.py new file mode 100644 index 0000000..72b1401 --- /dev/null +++ b/django-custom-model/users/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class UsersConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'users' diff --git a/django-custom-model/users/forms.py b/django-custom-model/users/forms.py new file mode 100644 index 0000000..2d3ceb7 --- /dev/null +++ b/django-custom-model/users/forms.py @@ -0,0 +1,17 @@ +from django.contrib.auth.forms import UserCreationForm, UserChangeForm + +from .models import CustomUser + + +class CustomUserCreationForm(UserCreationForm): + + class Meta: + model = CustomUser + fields = ("email", "foto") + + +class CustomUserChangeForm(UserChangeForm): + + class Meta: + model = CustomUser + fields = ("email", "foto") diff --git a/django-custom-model/users/managers.py b/django-custom-model/users/managers.py new file mode 100644 index 0000000..f441f74 --- /dev/null +++ b/django-custom-model/users/managers.py @@ -0,0 +1,34 @@ +from django.contrib.auth.base_user import BaseUserManager +from django.utils.translation import gettext_lazy as _ + + +class CustomUserManager(BaseUserManager): + """ + Custom user model manager where email is the unique identifiers + for authentication instead of usernames. + """ + def create_user(self, email, password, **extra_fields): + """ + Create and save a user with the given email and password. + """ + if not email: + raise ValueError(_("The Email must be set")) + email = self.normalize_email(email) + user = self.model(email=email, **extra_fields) + user.set_password(password) + user.save() + return user + + def create_superuser(self, email, password, **extra_fields): + """ + Create and save a SuperUser with the given email and password. + """ + extra_fields.setdefault("is_staff", True) + extra_fields.setdefault("is_superuser", True) + extra_fields.setdefault("is_active", True) + + if extra_fields.get("is_staff") is not True: + raise ValueError(_("Superuser must have is_staff=True.")) + if extra_fields.get("is_superuser") is not True: + raise ValueError(_("Superuser must have is_superuser=True.")) + return self.create_user(email, password, **extra_fields) diff --git a/django-custom-model/users/migrations/0001_initial.py b/django-custom-model/users/migrations/0001_initial.py new file mode 100644 index 0000000..0dadda3 --- /dev/null +++ b/django-custom-model/users/migrations/0001_initial.py @@ -0,0 +1,34 @@ +# Generated by Django 5.1 on 2024-08-08 13:05 + +import django.utils.timezone +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('auth', '0012_alter_user_first_name_max_length'), + ] + + operations = [ + migrations.CreateModel( + name='CustomUser', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('password', models.CharField(max_length=128, verbose_name='password')), + ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')), + ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')), + ('email', models.EmailField(max_length=254, unique=True, verbose_name='email address')), + ('is_staff', models.BooleanField(default=False)), + ('is_active', models.BooleanField(default=True)), + ('date_joined', models.DateTimeField(default=django.utils.timezone.now)), + ('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.group', verbose_name='groups')), + ('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.permission', verbose_name='user permissions')), + ], + options={ + 'abstract': False, + }, + ), + ] diff --git a/django-custom-model/users/migrations/0002_customuser_foto.py b/django-custom-model/users/migrations/0002_customuser_foto.py new file mode 100644 index 0000000..1464c09 --- /dev/null +++ b/django-custom-model/users/migrations/0002_customuser_foto.py @@ -0,0 +1,18 @@ +# Generated by Django 5.1 on 2024-08-08 13:07 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('users', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='customuser', + name='foto', + field=models.TextField(default=''), + ), + ] diff --git a/django-custom-model/users/migrations/0003_alter_customuser_foto.py b/django-custom-model/users/migrations/0003_alter_customuser_foto.py new file mode 100644 index 0000000..1cc1758 --- /dev/null +++ b/django-custom-model/users/migrations/0003_alter_customuser_foto.py @@ -0,0 +1,18 @@ +# Generated by Django 5.1 on 2024-08-08 13:29 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('users', '0002_customuser_foto'), + ] + + operations = [ + migrations.AlterField( + model_name='customuser', + name='foto', + field=models.ImageField(blank=True, upload_to='profile_images'), + ), + ] diff --git a/django-custom-model/users/migrations/__init__.py b/django-custom-model/users/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/django-custom-model/users/models.py b/django-custom-model/users/models.py new file mode 100644 index 0000000..47b2175 --- /dev/null +++ b/django-custom-model/users/models.py @@ -0,0 +1,22 @@ +from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin +from django.db import models +from django.utils import timezone +from django.utils.translation import gettext_lazy as _ + +from .managers import CustomUserManager + + +class CustomUser(AbstractBaseUser, PermissionsMixin): + email = models.EmailField(_("email address"), unique=True) + is_staff = models.BooleanField(default=False) + is_active = models.BooleanField(default=True) + date_joined = models.DateTimeField(default=timezone.now) + foto = models.ImageField(upload_to="profile_images", blank=True) + + USERNAME_FIELD = "email" + REQUIRED_FIELDS = [] + + objects = CustomUserManager() + + def __str__(self): + return self.email diff --git a/django-custom-model/users/tests.py b/django-custom-model/users/tests.py new file mode 100644 index 0000000..d5b2fce --- /dev/null +++ b/django-custom-model/users/tests.py @@ -0,0 +1,42 @@ +from django.contrib.auth import get_user_model +from django.test import TestCase + + +class UsersManagersTests(TestCase): + + def test_create_user(self): + User = get_user_model() + user = User.objects.create_user(email="normal@user.com", password="foo") + self.assertEqual(user.email, "normal@user.com") + self.assertTrue(user.is_active) + self.assertFalse(user.is_staff) + self.assertFalse(user.is_superuser) + try: + # username is None for the AbstractUser option + # username does not exist for the AbstractBaseUser option + self.assertIsNone(user.username) + except AttributeError: + pass + with self.assertRaises(TypeError): + User.objects.create_user() + with self.assertRaises(TypeError): + User.objects.create_user(email="") + with self.assertRaises(ValueError): + User.objects.create_user(email="", password="foo") + + def test_create_superuser(self): + User = get_user_model() + admin_user = User.objects.create_superuser(email="super@user.com", password="foo") + self.assertEqual(admin_user.email, "super@user.com") + self.assertTrue(admin_user.is_active) + self.assertTrue(admin_user.is_staff) + self.assertTrue(admin_user.is_superuser) + try: + # username is None for the AbstractUser option + # username does not exist for the AbstractBaseUser option + self.assertIsNone(admin_user.username) + except AttributeError: + pass + with self.assertRaises(ValueError): + User.objects.create_superuser( + email="super@user.com", password="foo", is_superuser=False) diff --git a/django-custom-model/users/views.py b/django-custom-model/users/views.py new file mode 100644 index 0000000..91ea44a --- /dev/null +++ b/django-custom-model/users/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here.