Lucas
12 months ago
commit
c602d0bf8d
32 changed files with 1193 additions and 0 deletions
@ -0,0 +1,11 @@ |
|||||
|
venv |
||||
|
.venv |
||||
|
.env |
||||
|
*.sqlite3 |
||||
|
media |
||||
|
*__pycache__ |
||||
|
.idea |
||||
|
*.code-workspace |
||||
|
.report.json |
||||
|
report.json |
||||
|
.vscode |
@ -0,0 +1,26 @@ |
|||||
|
Copyright (c) Lucas F. All rights reserved. |
||||
|
|
||||
|
Redistribution and use in source and binary forms, with or without modification, |
||||
|
are permitted provided that the following conditions are met: |
||||
|
|
||||
|
1. Redistributions of source code must retain the above copyright notice, |
||||
|
this list of conditions and the following disclaimer. |
||||
|
|
||||
|
2. Redistributions in binary form must reproduce the above copyright |
||||
|
notice, this list of conditions and the following disclaimer in the |
||||
|
documentation and/or other materials provided with the distribution. |
||||
|
|
||||
|
3. Neither the name of the copyright holder nor the names of its contributors may be used |
||||
|
to endorse or promote products derived from this software without |
||||
|
specific prior written permission. |
||||
|
|
||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
||||
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR |
||||
|
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
||||
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON |
||||
|
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
@ -0,0 +1,40 @@ |
|||||
|
.DEFAULT_GOAL = default |
||||
|
SCRIPT = contrib/scripts/make_scripts.sh |
||||
|
|
||||
|
## @ env
|
||||
|
.PHONY: env |
||||
|
env: ## creates a .env file
|
||||
|
@./${SCRIPT} make_env_file |
||||
|
|
||||
|
## @ task
|
||||
|
.PHONY: check run shell_plus clear_migrations show_migrations migrations migrate elements |
||||
|
check: ## same as manage.py check
|
||||
|
@./${SCRIPT} check |
||||
|
|
||||
|
run: ## same as manage.py run server
|
||||
|
@./${SCRIPT} run |
||||
|
|
||||
|
shell_plus: ## same as .manage.py shell_plus
|
||||
|
@./${SCRIPT} shell_plus |
||||
|
|
||||
|
clear_migrations: ## same as manage.py showmigrations
|
||||
|
@./${SCRIPT} show_migrations |
||||
|
|
||||
|
show_migrations: ## same as manage.py showmigrations
|
||||
|
@./${SCRIPT} show_migrations |
||||
|
|
||||
|
migrations: ## same as manage.py makemigrations
|
||||
|
@./${SCRIPT} migrations |
||||
|
|
||||
|
migrate: ## same as manage.py migrate
|
||||
|
@./${SCRIPT} migrate |
||||
|
|
||||
|
elements: ## create initial app elements
|
||||
|
@./${SCRIPT} elements |
||||
|
|
||||
|
## @ help
|
||||
|
.PHONY: help |
||||
|
help: ## display all make commands
|
||||
|
@./${SCRIPT} help $(MAKEFILE_LIST) |
||||
|
|
||||
|
default: help |
@ -0,0 +1,53 @@ |
|||||
|
# Form User |
||||
|
|
||||
|
É um exemplo de aplicação Django para criação de modelo, tendo em vista salvar dois modelos ao mesmo tempo, |
||||
|
sendo que um deles possui relação do tipo muitos para muitos. |
||||
|
|
||||
|
|
||||
|
## Instalação |
||||
|
|
||||
|
via `pip` |
||||
|
|
||||
|
```bash |
||||
|
git clone https://git.lucasf.dev/public/form_user.git |
||||
|
cd form_user |
||||
|
python -m venv .venv |
||||
|
. ./.venv/bin/activate |
||||
|
pip install -r requirements.txt |
||||
|
``` |
||||
|
|
||||
|
|
||||
|
via `poetry` |
||||
|
|
||||
|
```bash |
||||
|
git clone https://git.lucasf.dev/public/form_user.git |
||||
|
cd form_user |
||||
|
poetry shell |
||||
|
poetry install |
||||
|
``` |
||||
|
|
||||
|
|
||||
|
## Criando arquivo .env |
||||
|
|
||||
|
```bash |
||||
|
make env |
||||
|
``` |
||||
|
|
||||
|
## Criando elementos para aplicação |
||||
|
|
||||
|
primeiro informe no arquivo `.env` gerado os valores para as seguintes variáveis: |
||||
|
|
||||
|
ADMIN_USERNAME |
||||
|
ADMIN_EMAIL |
||||
|
ADMIN_PASSWORD |
||||
|
|
||||
|
```bash |
||||
|
make elements |
||||
|
``` |
||||
|
|
||||
|
## Iniciar a aplicação |
||||
|
|
||||
|
```bash |
||||
|
make run |
||||
|
``` |
||||
|
|
@ -0,0 +1,122 @@ |
|||||
|
#!/usr/bin/env bash |
||||
|
|
||||
|
HERE="$(cd "$(dirname "$0")" && pwd)" |
||||
|
BASEDIR="$(cd "$(dirname "$1")" && pwd)" |
||||
|
CHARS="abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*(-_=+)" |
||||
|
for ((i=0;i<${#CHARS};i++)); do ARRAY[$i]="${CHARS:i:1}"; done |
||||
|
MSG_SUCCESS="DONE!" |
||||
|
POETRY=0 |
||||
|
PYTHON=0 |
||||
|
|
||||
|
key_gen() { |
||||
|
for ((c=1; c<=50; c++)); do |
||||
|
KEY="$KEY${ARRAY[$((RANDOM % 50))]}" |
||||
|
done |
||||
|
echo $KEY |
||||
|
} |
||||
|
|
||||
|
make_env_file() { |
||||
|
if [[ ! -f ".env" ]]; then |
||||
|
ENV="SECRET_KEY='$(key_gen)'\n |
||||
|
ALLOWED_HOSTS=localhost, 10.0.2.2, 127.0.0.1\n |
||||
|
DEBUG=True\n\n |
||||
|
#DATABASE_URL=postgres://postgres:postgres@127.0.0.1:5433/db\n\n |
||||
|
ADMIN_USERNAME=\n |
||||
|
ADMIN_EMAIL=\n |
||||
|
ADMIN_PASSWORD=\n\n |
||||
|
EMAIL_HOST=\n |
||||
|
EMAIL_PORT=\n |
||||
|
EMAIL_HOST_USER=\n |
||||
|
EMAIL_HOST_PASSWORD=\n |
||||
|
EMAIL_USE_TLS=True\n |
||||
|
DEFAULT_FROM_EMAIL= |
||||
|
" |
||||
|
|
||||
|
$(echo -e $ENV | sed -e 's/^[ \t]*//' > .env) |
||||
|
echo "ENV FILE - $MSG_SUCCESS" |
||||
|
fi |
||||
|
} |
||||
|
|
||||
|
verify_poetry() { |
||||
|
if command -v poetry &> /dev/null; then |
||||
|
POETRY=1 |
||||
|
fi |
||||
|
} |
||||
|
|
||||
|
verify_python() { |
||||
|
if command -v python3 &> /dev/null; then |
||||
|
PYTHON=1 |
||||
|
fi |
||||
|
} |
||||
|
|
||||
|
venv_name() { |
||||
|
if [[ -d "$BASEDIR/.venv" ]]; then |
||||
|
echo ".venv" |
||||
|
fi |
||||
|
if [[ -d "$BASEDIR/venv" ]]; then |
||||
|
echo "venv" |
||||
|
fi |
||||
|
} |
||||
|
|
||||
|
python_name() { |
||||
|
if [[ PYTHON -eq 1 ]]; then |
||||
|
echo "python3" |
||||
|
else |
||||
|
echo "python" |
||||
|
fi |
||||
|
} |
||||
|
|
||||
|
help() { |
||||
|
awk 'BEGIN {FS="## @ "; print "Usage: make";} /^## @ / { printf "\033[31m\n" substr($1, 5) "\n";} {FS=" ## ";} /^[a-zA-Z_-]+:.*? ##/ { print "\033[33m -", $1 "\033[37m", $2}' $ARG |
||||
|
} |
||||
|
|
||||
|
run() { |
||||
|
$(venv_name)/bin/$(python_name) manage.py runserver 0.0.0.0:8000 |
||||
|
} |
||||
|
|
||||
|
shell_plus() { |
||||
|
$(venv_name)/bin/$(python_name) manage.py shell_plus |
||||
|
} |
||||
|
|
||||
|
check() { |
||||
|
$(venv_name)/bin/$(python_name) manage.py check |
||||
|
IS_OK=$? |
||||
|
} |
||||
|
|
||||
|
show_migrations() { |
||||
|
$(venv_name)/bin/$(python_name) manage.py showmigrations |
||||
|
} |
||||
|
|
||||
|
migrations() { |
||||
|
$(venv_name)/bin/$(python_name) manage.py makemigrations |
||||
|
} |
||||
|
|
||||
|
migrate() { |
||||
|
$(venv_name)/bin/$(python_name) manage.py migrate |
||||
|
} |
||||
|
|
||||
|
check() { |
||||
|
$(venv_name)/bin/$(python_name) manage.py check |
||||
|
} |
||||
|
|
||||
|
elements() { |
||||
|
$(venv_name)/bin/$(python_name) manage.py elements |
||||
|
} |
||||
|
|
||||
|
clear_migrations() { |
||||
|
find $BASEDIR -path '*/migrations/*.py' -not -name '__init__.py' -not -path '*/.venv/*' -delete |
||||
|
find $BASEDIR -path '*/migrations/*.pyc' -not -name '__init__.py' -not -path '*/.venv/*' -delete |
||||
|
if [[ -f $BASEDIR/media/ ]]; then |
||||
|
rm $BASEDIR/media/* |
||||
|
fi |
||||
|
if [[ -f db.sqlite3 ]];then |
||||
|
rm db.sqlite3 |
||||
|
fi |
||||
|
podman pod rm -f cq_pod && |
||||
|
podman volume prune |
||||
|
} |
||||
|
|
||||
|
verify_python |
||||
|
verify_poetry |
||||
|
ARG=$2 |
||||
|
$1 |
@ -0,0 +1,64 @@ |
|||||
|
from django.contrib import admin |
||||
|
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin |
||||
|
from django.contrib.auth.forms import UserCreationForm |
||||
|
|
||||
|
from .forms import UserAdminForm |
||||
|
from .models import CustomUser, TagUnidade, Unidade, UsuarioPermissaoUnidadeTag |
||||
|
|
||||
|
|
||||
|
class UserAdmin(BaseUserAdmin): |
||||
|
add_form = UserCreationForm |
||||
|
add_fieldsets = ( |
||||
|
( |
||||
|
None, |
||||
|
{ |
||||
|
"classes": ("wide",), |
||||
|
"fields": ( |
||||
|
"username", |
||||
|
"email", |
||||
|
"password1", |
||||
|
"password2", |
||||
|
"is_active", |
||||
|
), |
||||
|
}, |
||||
|
), |
||||
|
) |
||||
|
form = UserAdminForm |
||||
|
fieldsets = ( |
||||
|
(None, {"fields": ("username", "email")}), |
||||
|
( |
||||
|
"Informações Básicas", |
||||
|
{ |
||||
|
"fields": ( |
||||
|
"first_name", |
||||
|
"last_login", |
||||
|
) |
||||
|
}, |
||||
|
), |
||||
|
( |
||||
|
"Permissões", |
||||
|
{ |
||||
|
"fields": ( |
||||
|
"is_active", |
||||
|
"is_staff", |
||||
|
"is_superuser", |
||||
|
"groups", |
||||
|
"user_permissions", |
||||
|
) |
||||
|
}, |
||||
|
), |
||||
|
) |
||||
|
list_display = [ |
||||
|
"username", |
||||
|
"first_name", |
||||
|
"email", |
||||
|
"is_active", |
||||
|
"is_staff", |
||||
|
"date_joined", |
||||
|
] |
||||
|
|
||||
|
|
||||
|
admin.site.register(CustomUser, UserAdmin) |
||||
|
admin.site.register(UsuarioPermissaoUnidadeTag) |
||||
|
admin.site.register(TagUnidade) |
||||
|
admin.site.register(Unidade) |
@ -0,0 +1,7 @@ |
|||||
|
from django.apps import AppConfig |
||||
|
|
||||
|
|
||||
|
class ContasConfig(AppConfig): |
||||
|
default_auto_field = "django.db.models.BigAutoField" |
||||
|
name = "contas" |
||||
|
default = False |
@ -0,0 +1,28 @@ |
|||||
|
from django import forms |
||||
|
from django.contrib.auth.forms import UserCreationForm |
||||
|
|
||||
|
from form_user.apps.contas.models import CustomUser, UsuarioPermissaoUnidadeTag |
||||
|
|
||||
|
|
||||
|
class UserAdminForm(forms.ModelForm): |
||||
|
class Meta: |
||||
|
model = CustomUser |
||||
|
fields = UserCreationForm.Meta.fields + ( |
||||
|
"username", |
||||
|
"email", |
||||
|
"first_name", |
||||
|
"is_active", |
||||
|
"is_staff", |
||||
|
) |
||||
|
|
||||
|
|
||||
|
class PermissaoForm(forms.ModelForm): |
||||
|
class Meta: |
||||
|
model = UsuarioPermissaoUnidadeTag |
||||
|
fields = ["tags", "unidades"] |
||||
|
|
||||
|
|
||||
|
class NewUserForm(forms.ModelForm): |
||||
|
class Meta: |
||||
|
model = CustomUser |
||||
|
fields = ["username"] |
@ -0,0 +1,33 @@ |
|||||
|
from decouple import config |
||||
|
from django.core.management.base import BaseCommand |
||||
|
from django.utils.translation import gettext_lazy as _ |
||||
|
|
||||
|
from form_user.apps.contas.models import CustomUser |
||||
|
|
||||
|
|
||||
|
class AppException(Exception, BaseCommand): |
||||
|
def __init__(self, exception): |
||||
|
print( |
||||
|
BaseCommand().stdout.write( |
||||
|
BaseCommand().style.NOTICE(f"Error: {exception}") |
||||
|
) |
||||
|
) |
||||
|
|
||||
|
|
||||
|
class Command(BaseCommand): |
||||
|
help = _("Creates initial information for application") |
||||
|
su_created = False |
||||
|
|
||||
|
def handle(self, *args, **options): |
||||
|
if not CustomUser.objects.filter(username=config("ADMIN_USERNAME")): |
||||
|
su = CustomUser.objects.create_superuser( |
||||
|
username=config("ADMIN_USERNAME"), |
||||
|
email=config("ADMIN_EMAIL"), |
||||
|
password=config("ADMIN_PASSWORD"), |
||||
|
is_active=True, |
||||
|
is_staff=True, |
||||
|
) |
||||
|
if su: |
||||
|
self.stdout.write(self.style.SUCCESS(_("Superuser created!"))) |
||||
|
else: |
||||
|
self.stdout.write(self.style.NOTICE(_("Superuser already exists!"))) |
@ -0,0 +1,7 @@ |
|||||
|
from django.contrib.auth.models import UserManager |
||||
|
from django.db.models import Q |
||||
|
|
||||
|
|
||||
|
class CustomUserManager(UserManager): |
||||
|
def all(self): |
||||
|
return self.get_queryset().filter(~Q(username="admin")) |
@ -0,0 +1,214 @@ |
|||||
|
# Generated by Django 5.0.2 on 2024-02-06 18:32 |
||||
|
|
||||
|
import django.contrib.auth.validators |
||||
|
import django.db.models.deletion |
||||
|
import django.utils.timezone |
||||
|
import form_user.apps.contas.managers |
||||
|
import uuid |
||||
|
from django.conf import settings |
||||
|
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="TagUnidade", |
||||
|
fields=[ |
||||
|
( |
||||
|
"id", |
||||
|
models.BigAutoField( |
||||
|
auto_created=True, |
||||
|
primary_key=True, |
||||
|
serialize=False, |
||||
|
verbose_name="ID", |
||||
|
), |
||||
|
), |
||||
|
("nome", models.CharField(max_length=50, verbose_name="Nome")), |
||||
|
], |
||||
|
), |
||||
|
migrations.CreateModel( |
||||
|
name="Unidade", |
||||
|
fields=[ |
||||
|
( |
||||
|
"id", |
||||
|
models.BigAutoField( |
||||
|
auto_created=True, |
||||
|
primary_key=True, |
||||
|
serialize=False, |
||||
|
verbose_name="ID", |
||||
|
), |
||||
|
), |
||||
|
("nome", models.CharField(max_length=50, verbose_name="Nome")), |
||||
|
], |
||||
|
), |
||||
|
migrations.CreateModel( |
||||
|
name="CustomUser", |
||||
|
fields=[ |
||||
|
("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", |
||||
|
), |
||||
|
), |
||||
|
( |
||||
|
"username", |
||||
|
models.CharField( |
||||
|
error_messages={ |
||||
|
"unique": "A user with that username already exists." |
||||
|
}, |
||||
|
help_text="Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.", |
||||
|
max_length=150, |
||||
|
unique=True, |
||||
|
validators=[ |
||||
|
django.contrib.auth.validators.UnicodeUsernameValidator() |
||||
|
], |
||||
|
verbose_name="username", |
||||
|
), |
||||
|
), |
||||
|
( |
||||
|
"first_name", |
||||
|
models.CharField( |
||||
|
blank=True, max_length=150, verbose_name="first name" |
||||
|
), |
||||
|
), |
||||
|
( |
||||
|
"last_name", |
||||
|
models.CharField( |
||||
|
blank=True, max_length=150, verbose_name="last name" |
||||
|
), |
||||
|
), |
||||
|
( |
||||
|
"email", |
||||
|
models.EmailField( |
||||
|
blank=True, max_length=254, verbose_name="email address" |
||||
|
), |
||||
|
), |
||||
|
( |
||||
|
"date_joined", |
||||
|
models.DateTimeField( |
||||
|
default=django.utils.timezone.now, verbose_name="date joined" |
||||
|
), |
||||
|
), |
||||
|
( |
||||
|
"id", |
||||
|
models.UUIDField( |
||||
|
default=uuid.uuid4, |
||||
|
editable=False, |
||||
|
primary_key=True, |
||||
|
serialize=False, |
||||
|
verbose_name="Identifier", |
||||
|
), |
||||
|
), |
||||
|
( |
||||
|
"is_staff", |
||||
|
models.BooleanField(default=False, verbose_name="staff status"), |
||||
|
), |
||||
|
( |
||||
|
"is_active", |
||||
|
models.BooleanField(default=False, verbose_name="active"), |
||||
|
), |
||||
|
( |
||||
|
"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", |
||||
|
), |
||||
|
), |
||||
|
( |
||||
|
"usuario_agrupador", |
||||
|
models.ForeignKey( |
||||
|
on_delete=django.db.models.deletion.CASCADE, |
||||
|
related_name="agrupador", |
||||
|
to=settings.AUTH_USER_MODEL, |
||||
|
verbose_name="Usuário Agrupador", |
||||
|
), |
||||
|
), |
||||
|
], |
||||
|
options={ |
||||
|
"verbose_name": "Usuário", |
||||
|
"verbose_name_plural": "Usuários", |
||||
|
}, |
||||
|
managers=[ |
||||
|
("objects", form_user.apps.contas.managers.CustomUserManager()), |
||||
|
], |
||||
|
), |
||||
|
migrations.CreateModel( |
||||
|
name="UsuarioPermissaoUnidadeTag", |
||||
|
fields=[ |
||||
|
( |
||||
|
"id", |
||||
|
models.BigAutoField( |
||||
|
auto_created=True, |
||||
|
primary_key=True, |
||||
|
serialize=False, |
||||
|
verbose_name="ID", |
||||
|
), |
||||
|
), |
||||
|
( |
||||
|
"tags", |
||||
|
models.ManyToManyField(to="contas.tagunidade", verbose_name="Tags"), |
||||
|
), |
||||
|
( |
||||
|
"unidades", |
||||
|
models.ManyToManyField( |
||||
|
to="contas.unidade", verbose_name="Unidades" |
||||
|
), |
||||
|
), |
||||
|
( |
||||
|
"usuario", |
||||
|
models.ForeignKey( |
||||
|
blank=True, |
||||
|
null=True, |
||||
|
on_delete=django.db.models.deletion.CASCADE, |
||||
|
related_name="per_custom_user", |
||||
|
to=settings.AUTH_USER_MODEL, |
||||
|
), |
||||
|
), |
||||
|
( |
||||
|
"usuario_inclusao", |
||||
|
models.ForeignKey( |
||||
|
blank=True, |
||||
|
null=True, |
||||
|
on_delete=django.db.models.deletion.CASCADE, |
||||
|
related_name="usuario_inclusao", |
||||
|
to=settings.AUTH_USER_MODEL, |
||||
|
), |
||||
|
), |
||||
|
], |
||||
|
options={ |
||||
|
"verbose_name": "PermissĂŁo de Acesso Tag e Unidade", |
||||
|
"verbose_name_plural": "Permissões de Acesso Tags e Unidades", |
||||
|
}, |
||||
|
), |
||||
|
] |
@ -0,0 +1,27 @@ |
|||||
|
# Generated by Django 5.0.2 on 2024-02-06 18:35 |
||||
|
|
||||
|
import django.db.models.deletion |
||||
|
from django.conf import settings |
||||
|
from django.db import migrations, models |
||||
|
|
||||
|
|
||||
|
class Migration(migrations.Migration): |
||||
|
|
||||
|
dependencies = [ |
||||
|
("contas", "0001_initial"), |
||||
|
] |
||||
|
|
||||
|
operations = [ |
||||
|
migrations.AlterField( |
||||
|
model_name="customuser", |
||||
|
name="usuario_agrupador", |
||||
|
field=models.ForeignKey( |
||||
|
blank=True, |
||||
|
null=True, |
||||
|
on_delete=django.db.models.deletion.CASCADE, |
||||
|
related_name="agrupador", |
||||
|
to=settings.AUTH_USER_MODEL, |
||||
|
verbose_name="Usuário Agrupador", |
||||
|
), |
||||
|
), |
||||
|
] |
@ -0,0 +1,79 @@ |
|||||
|
import uuid |
||||
|
|
||||
|
from django.contrib.auth.models import AbstractUser |
||||
|
from django.db import models |
||||
|
from django.utils.translation import gettext_lazy as _ |
||||
|
|
||||
|
from .managers import CustomUserManager |
||||
|
|
||||
|
|
||||
|
class TagUnidade(models.Model): |
||||
|
nome = models.CharField("Nome", max_length=50) |
||||
|
|
||||
|
def __str__(self): |
||||
|
return self.nome |
||||
|
|
||||
|
|
||||
|
class Unidade(models.Model): |
||||
|
nome = models.CharField("Nome", max_length=50) |
||||
|
|
||||
|
def __str__(self): |
||||
|
return self.nome |
||||
|
|
||||
|
|
||||
|
class CustomUser(AbstractUser): |
||||
|
id = models.UUIDField( |
||||
|
_("Identifier"), primary_key=True, default=uuid.uuid4, editable=False |
||||
|
) |
||||
|
is_staff = models.BooleanField(_("staff status"), default=False) |
||||
|
is_active = models.BooleanField(_("active"), default=False) |
||||
|
|
||||
|
usuario_agrupador = models.ForeignKey( |
||||
|
"self", |
||||
|
on_delete=models.CASCADE, |
||||
|
verbose_name="Usuário Agrupador", |
||||
|
related_name="agrupador", |
||||
|
null=True, |
||||
|
blank=True, |
||||
|
) |
||||
|
|
||||
|
EMAIL_FIELD = "email" |
||||
|
USERNAME_FIELD = "username" |
||||
|
REQUIRED_FIELDS = ["email"] |
||||
|
|
||||
|
objects = CustomUserManager() |
||||
|
|
||||
|
class Meta: |
||||
|
verbose_name = "Usuário" |
||||
|
verbose_name_plural = "Usuários" |
||||
|
|
||||
|
def __str__(self): |
||||
|
return self.first_name or self.username |
||||
|
|
||||
|
|
||||
|
class UsuarioPermissaoUnidadeTag(models.Model): |
||||
|
usuario = models.ForeignKey( |
||||
|
CustomUser, |
||||
|
on_delete=models.CASCADE, |
||||
|
related_name="per_custom_user", |
||||
|
null=True, |
||||
|
blank=True, |
||||
|
) |
||||
|
|
||||
|
tags = models.ManyToManyField(TagUnidade, verbose_name="Tags") |
||||
|
unidades = models.ManyToManyField(Unidade, verbose_name="Unidades") |
||||
|
|
||||
|
usuario_inclusao = models.ForeignKey( |
||||
|
CustomUser, |
||||
|
on_delete=models.CASCADE, |
||||
|
related_name="usuario_inclusao", |
||||
|
null=True, |
||||
|
blank=True, |
||||
|
) |
||||
|
|
||||
|
def __str__(self): |
||||
|
return self.usuario.username |
||||
|
|
||||
|
class Meta: |
||||
|
verbose_name = "PermissĂŁo de Acesso Tag e Unidade" |
||||
|
verbose_name_plural = "Permissões de Acesso Tags e Unidades" |
@ -0,0 +1,15 @@ |
|||||
|
*, |
||||
|
*::before, |
||||
|
*::after { |
||||
|
box-sizing: border-box; |
||||
|
margin: 0; |
||||
|
padding: 0; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
body { |
||||
|
display: grid; |
||||
|
place-content: center; |
||||
|
align-items: center; |
||||
|
height: 100vh; |
||||
|
} |
@ -0,0 +1,13 @@ |
|||||
|
{% load static %} |
||||
|
|
||||
|
<!DOCTYPE html> |
||||
|
<html lang="en"> |
||||
|
<head> |
||||
|
<meta charset="UTF-8"> |
||||
|
<link rel="stylesheet" href="{% static 'contas/css/main.css' %}"> |
||||
|
<title>Form Test</title> |
||||
|
</head> |
||||
|
<body> |
||||
|
{% block content %}{% endblock content %} |
||||
|
</body> |
||||
|
</html> |
@ -0,0 +1,13 @@ |
|||||
|
{% extends "contas/base.html" %} |
||||
|
|
||||
|
{% load static %} |
||||
|
|
||||
|
{% block content %} |
||||
|
<a href="{% url 'contas:index' %}">Voltar</a> |
||||
|
<form action="" method="post" style="margin-top: 2rem;" autocomplete="off"> |
||||
|
{% csrf_token %} |
||||
|
{{ form.as_p }} |
||||
|
{{ form_permissao.as_p }} |
||||
|
<input type="submit" value="Salvar"> |
||||
|
</form> |
||||
|
{% endblock content %} |
@ -0,0 +1,13 @@ |
|||||
|
{% extends "contas/base.html" %} |
||||
|
|
||||
|
{% load static %} |
||||
|
|
||||
|
{% block content %} |
||||
|
<a href="{% url 'contas:novo' %}">Novo Usuário</a><br> |
||||
|
<ul style="margin-top: 2rem;"> |
||||
|
{% for object in object_list %} |
||||
|
<li><a href="{% url 'contas:editar' object.pk %}">{{object}}</a></li> |
||||
|
{% endfor %} |
||||
|
</ul> |
||||
|
{% endblock content %} |
||||
|
|
@ -0,0 +1,3 @@ |
|||||
|
from django.test import TestCase |
||||
|
|
||||
|
# Create your tests here. |
@ -0,0 +1,11 @@ |
|||||
|
from django.urls import path |
||||
|
|
||||
|
from . import views |
||||
|
|
||||
|
app_name = "contas" |
||||
|
|
||||
|
urlpatterns = [ |
||||
|
path("", views.Index.as_view(), name="index"), |
||||
|
path("novo/", views.Novo.as_view(), name="novo"), |
||||
|
path("editar/<uuid:pk>/", views.Editar.as_view(), name="editar"), |
||||
|
] |
@ -0,0 +1,55 @@ |
|||||
|
from django.db import transaction |
||||
|
from django.http import HttpResponseRedirect |
||||
|
from django.urls import reverse_lazy |
||||
|
from django.views.generic import CreateView, ListView, UpdateView |
||||
|
|
||||
|
from form_user.apps.contas.models import CustomUser |
||||
|
|
||||
|
from . import forms |
||||
|
|
||||
|
|
||||
|
class Common: |
||||
|
model = CustomUser |
||||
|
template_name = "contas/form.html" |
||||
|
form_class = forms.NewUserForm |
||||
|
success_url = reverse_lazy("contas:index") |
||||
|
|
||||
|
|
||||
|
class Index(Common, ListView): |
||||
|
template_name = "contas/index.html" |
||||
|
paginate_by = 10 |
||||
|
|
||||
|
|
||||
|
class NovoEditar(Common): |
||||
|
def form_valid(self, form): |
||||
|
form_permissao = forms.PermissaoForm(self.request.POST) |
||||
|
form_permissao.full_clean() |
||||
|
|
||||
|
if not form_permissao.is_valid(): |
||||
|
context = self.get_context_data(form=form) |
||||
|
context.update(form_permissao=form_permissao) |
||||
|
return self.render_to_response(context) |
||||
|
|
||||
|
with transaction.atomic(): |
||||
|
ob = form.save() |
||||
|
form_permissao.instance.usuario = ob |
||||
|
form_permissao.instance.usuario_inclusao = ob |
||||
|
form_permissao.save() |
||||
|
|
||||
|
return HttpResponseRedirect(self.success_url) |
||||
|
|
||||
|
|
||||
|
class Novo(NovoEditar, CreateView): |
||||
|
def get_context_data(self, **kwargs): |
||||
|
context = super().get_context_data(**kwargs) |
||||
|
context["form_permissao"] = forms.PermissaoForm() |
||||
|
return context |
||||
|
|
||||
|
|
||||
|
class Editar(NovoEditar, UpdateView): |
||||
|
def get_context_data(self, **kwargs): |
||||
|
context = super().get_context_data(**kwargs) |
||||
|
context["form_permissao"] = forms.PermissaoForm( |
||||
|
instance=self.object.per_custom_user.first() |
||||
|
) |
||||
|
return context |
@ -0,0 +1,16 @@ |
|||||
|
""" |
||||
|
ASGI config for form_user 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.0/howto/deployment/asgi/ |
||||
|
""" |
||||
|
|
||||
|
import os |
||||
|
|
||||
|
from django.core.asgi import get_asgi_application |
||||
|
|
||||
|
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'form_user.settings') |
||||
|
|
||||
|
application = get_asgi_application() |
@ -0,0 +1,138 @@ |
|||||
|
""" |
||||
|
Django settings for form_user project. |
||||
|
|
||||
|
Generated by 'django-admin startproject' using Django 5.0.2. |
||||
|
|
||||
|
For more information on this file, see |
||||
|
https://docs.djangoproject.com/en/5.0/topics/settings/ |
||||
|
|
||||
|
For the full list of settings and their values, see |
||||
|
https://docs.djangoproject.com/en/5.0/ref/settings/ |
||||
|
""" |
||||
|
|
||||
|
import os |
||||
|
from pathlib import Path |
||||
|
|
||||
|
from decouple import Csv, config |
||||
|
from dj_database_url import parse as dburl |
||||
|
|
||||
|
# 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.0/howto/deployment/checklist/ |
||||
|
|
||||
|
# SECURITY WARNING: keep the secret key used in production secret! |
||||
|
SECRET_KEY = config("SECRET_KEY") |
||||
|
|
||||
|
# SECURITY WARNING: don't run with debug turned on in production! |
||||
|
DEBUG = config("DEBUG", default=False, cast=bool) |
||||
|
|
||||
|
ALLOWED_HOSTS = config("ALLOWED_HOSTS", cast=Csv()) |
||||
|
|
||||
|
# Application definition |
||||
|
|
||||
|
INSTALLED_APPS = [ |
||||
|
"django.contrib.admin", |
||||
|
"django.contrib.auth", |
||||
|
"django.contrib.contenttypes", |
||||
|
"django.contrib.sessions", |
||||
|
"django.contrib.messages", |
||||
|
"django.contrib.staticfiles", |
||||
|
"django_extensions", |
||||
|
"form_user.apps.contas", |
||||
|
] |
||||
|
|
||||
|
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 = "form_user.urls" |
||||
|
|
||||
|
TEMPLATES = [ |
||||
|
{ |
||||
|
"BACKEND": "django.template.backends.django.DjangoTemplates", |
||||
|
"DIRS": ["templates", BASE_DIR / "templates"], |
||||
|
"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 = "form_user.wsgi.application" |
||||
|
|
||||
|
|
||||
|
# Database |
||||
|
# https://docs.djangoproject.com/en/5.0/ref/settings/#databases |
||||
|
|
||||
|
default_dburl = "sqlite:///" + os.path.join(BASE_DIR, "db.sqlite3") |
||||
|
|
||||
|
DATABASES = { |
||||
|
"default": config("DATABASE_URL", default=default_dburl, cast=dburl), |
||||
|
} |
||||
|
|
||||
|
|
||||
|
# Password validation |
||||
|
# https://docs.djangoproject.com/en/5.0/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.0/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.0/howto/static-files/ |
||||
|
STATIC_URL = "static/" |
||||
|
|
||||
|
STATICFILES_DIRS = [ |
||||
|
os.path.join(BASE_DIR, "staticfiles"), |
||||
|
] |
||||
|
|
||||
|
MEDIA_URL = "/media/" |
||||
|
|
||||
|
MEDIA_ROOT = os.path.join(BASE_DIR, "media") |
||||
|
|
||||
|
STATIC_ROOT = os.path.join(BASE_DIR, "static/") |
||||
|
|
||||
|
# Default primary key field type |
||||
|
# https://docs.djangoproject.com/en/5.0/ref/settings/#default-auto-field |
||||
|
|
||||
|
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" |
||||
|
|
||||
|
AUTH_USER_MODEL = "contas.CustomUser" |
@ -0,0 +1,24 @@ |
|||||
|
""" |
||||
|
URL configuration for form_user project. |
||||
|
|
||||
|
The `urlpatterns` list routes URLs to views. For more information please see: |
||||
|
https://docs.djangoproject.com/en/5.0/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 include, path |
||||
|
|
||||
|
urlpatterns = [ |
||||
|
path("admin/", admin.site.urls), |
||||
|
path("", include("form_user.apps.contas.urls", namespace="contas")), |
||||
|
] |
@ -0,0 +1,16 @@ |
|||||
|
""" |
||||
|
WSGI config for form_user 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.0/howto/deployment/wsgi/ |
||||
|
""" |
||||
|
|
||||
|
import os |
||||
|
|
||||
|
from django.core.wsgi import get_wsgi_application |
||||
|
|
||||
|
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'form_user.settings') |
||||
|
|
||||
|
application = get_wsgi_application() |
@ -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', 'form_user.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() |
@ -0,0 +1,118 @@ |
|||||
|
# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. |
||||
|
|
||||
|
[[package]] |
||||
|
name = "asgiref" |
||||
|
version = "3.7.2" |
||||
|
description = "ASGI specs, helper code, and adapters" |
||||
|
optional = false |
||||
|
python-versions = ">=3.7" |
||||
|
files = [ |
||||
|
{file = "asgiref-3.7.2-py3-none-any.whl", hash = "sha256:89b2ef2247e3b562a16eef663bc0e2e703ec6468e2fa8a5cd61cd449786d4f6e"}, |
||||
|
{file = "asgiref-3.7.2.tar.gz", hash = "sha256:9e0ce3aa93a819ba5b45120216b23878cf6e8525eb3848653452b4192b92afed"}, |
||||
|
] |
||||
|
|
||||
|
[package.extras] |
||||
|
tests = ["mypy (>=0.800)", "pytest", "pytest-asyncio"] |
||||
|
|
||||
|
[[package]] |
||||
|
name = "dj-database-url" |
||||
|
version = "2.1.0" |
||||
|
description = "Use Database URLs in your Django Application." |
||||
|
optional = false |
||||
|
python-versions = "*" |
||||
|
files = [ |
||||
|
{file = "dj-database-url-2.1.0.tar.gz", hash = "sha256:f2042cefe1086e539c9da39fad5ad7f61173bf79665e69bf7e4de55fa88b135f"}, |
||||
|
{file = "dj_database_url-2.1.0-py3-none-any.whl", hash = "sha256:04bc34b248d4c21aaa13e4ab419ae6575ef5f10f3df735ce7da97722caa356e0"}, |
||||
|
] |
||||
|
|
||||
|
[package.dependencies] |
||||
|
Django = ">=3.2" |
||||
|
typing-extensions = ">=3.10.0.0" |
||||
|
|
||||
|
[[package]] |
||||
|
name = "django" |
||||
|
version = "5.0.2" |
||||
|
description = "A high-level Python web framework that encourages rapid development and clean, pragmatic design." |
||||
|
optional = false |
||||
|
python-versions = ">=3.10" |
||||
|
files = [ |
||||
|
{file = "Django-5.0.2-py3-none-any.whl", hash = "sha256:56ab63a105e8bb06ee67381d7b65fe6774f057e41a8bab06c8020c8882d8ecd4"}, |
||||
|
{file = "Django-5.0.2.tar.gz", hash = "sha256:b5bb1d11b2518a5f91372a282f24662f58f66749666b0a286ab057029f728080"}, |
||||
|
] |
||||
|
|
||||
|
[package.dependencies] |
||||
|
asgiref = ">=3.7.0,<4" |
||||
|
sqlparse = ">=0.3.1" |
||||
|
tzdata = {version = "*", markers = "sys_platform == \"win32\""} |
||||
|
|
||||
|
[package.extras] |
||||
|
argon2 = ["argon2-cffi (>=19.1.0)"] |
||||
|
bcrypt = ["bcrypt"] |
||||
|
|
||||
|
[[package]] |
||||
|
name = "django-extensions" |
||||
|
version = "3.2.3" |
||||
|
description = "Extensions for Django" |
||||
|
optional = false |
||||
|
python-versions = ">=3.6" |
||||
|
files = [ |
||||
|
{file = "django-extensions-3.2.3.tar.gz", hash = "sha256:44d27919d04e23b3f40231c4ab7af4e61ce832ef46d610cc650d53e68328410a"}, |
||||
|
{file = "django_extensions-3.2.3-py3-none-any.whl", hash = "sha256:9600b7562f79a92cbf1fde6403c04fee314608fefbb595502e34383ae8203401"}, |
||||
|
] |
||||
|
|
||||
|
[package.dependencies] |
||||
|
Django = ">=3.2" |
||||
|
|
||||
|
[[package]] |
||||
|
name = "python-decouple" |
||||
|
version = "3.8" |
||||
|
description = "Strict separation of settings from code." |
||||
|
optional = false |
||||
|
python-versions = "*" |
||||
|
files = [ |
||||
|
{file = "python-decouple-3.8.tar.gz", hash = "sha256:ba6e2657d4f376ecc46f77a3a615e058d93ba5e465c01bbe57289bfb7cce680f"}, |
||||
|
{file = "python_decouple-3.8-py3-none-any.whl", hash = "sha256:d0d45340815b25f4de59c974b855bb38d03151d81b037d9e3f463b0c9f8cbd66"}, |
||||
|
] |
||||
|
|
||||
|
[[package]] |
||||
|
name = "sqlparse" |
||||
|
version = "0.4.4" |
||||
|
description = "A non-validating SQL parser." |
||||
|
optional = false |
||||
|
python-versions = ">=3.5" |
||||
|
files = [ |
||||
|
{file = "sqlparse-0.4.4-py3-none-any.whl", hash = "sha256:5430a4fe2ac7d0f93e66f1efc6e1338a41884b7ddf2a350cedd20ccc4d9d28f3"}, |
||||
|
{file = "sqlparse-0.4.4.tar.gz", hash = "sha256:d446183e84b8349fa3061f0fe7f06ca94ba65b426946ffebe6e3e8295332420c"}, |
||||
|
] |
||||
|
|
||||
|
[package.extras] |
||||
|
dev = ["build", "flake8"] |
||||
|
doc = ["sphinx"] |
||||
|
test = ["pytest", "pytest-cov"] |
||||
|
|
||||
|
[[package]] |
||||
|
name = "typing-extensions" |
||||
|
version = "4.9.0" |
||||
|
description = "Backported and Experimental Type Hints for Python 3.8+" |
||||
|
optional = false |
||||
|
python-versions = ">=3.8" |
||||
|
files = [ |
||||
|
{file = "typing_extensions-4.9.0-py3-none-any.whl", hash = "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd"}, |
||||
|
{file = "typing_extensions-4.9.0.tar.gz", hash = "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783"}, |
||||
|
] |
||||
|
|
||||
|
[[package]] |
||||
|
name = "tzdata" |
||||
|
version = "2023.4" |
||||
|
description = "Provider of IANA time zone data" |
||||
|
optional = false |
||||
|
python-versions = ">=2" |
||||
|
files = [ |
||||
|
{file = "tzdata-2023.4-py2.py3-none-any.whl", hash = "sha256:aa3ace4329eeacda5b7beb7ea08ece826c28d761cda36e747cfbf97996d39bf3"}, |
||||
|
{file = "tzdata-2023.4.tar.gz", hash = "sha256:dd54c94f294765522c77399649b4fefd95522479a664a0cec87f41bebc6148c9"}, |
||||
|
] |
||||
|
|
||||
|
[metadata] |
||||
|
lock-version = "2.0" |
||||
|
python-versions = "^3.11" |
||||
|
content-hash = "3f3d4eb61266813806f194403d47bbd1801f62ca247a7ef3dc226a606fe9327f" |
@ -0,0 +1,17 @@ |
|||||
|
[tool.poetry] |
||||
|
name = "form-user" |
||||
|
version = "0.1.0" |
||||
|
description = "" |
||||
|
authors = ["Lucas F. <lucas@lucasf.dev>"] |
||||
|
readme = "README.md" |
||||
|
|
||||
|
[tool.poetry.dependencies] |
||||
|
python = "^3.11" |
||||
|
django = "^5.0.2" |
||||
|
python-decouple = "^3.8" |
||||
|
django-extensions = "^3.2.3" |
||||
|
dj-database-url = "^2.1.0" |
||||
|
|
||||
|
[build-system] |
||||
|
requires = ["poetry-core"] |
||||
|
build-backend = "poetry.core.masonry.api" |
@ -0,0 +1,8 @@ |
|||||
|
asgiref==3.7.2 ; python_version >= "3.11" and python_version < "4.0" |
||||
|
dj-database-url==2.1.0 ; python_version >= "3.11" and python_version < "4.0" |
||||
|
django-extensions==3.2.3 ; python_version >= "3.11" and python_version < "4.0" |
||||
|
django==5.0.2 ; python_version >= "3.11" and python_version < "4.0" |
||||
|
python-decouple==3.8 ; python_version >= "3.11" and python_version < "4.0" |
||||
|
sqlparse==0.4.4 ; python_version >= "3.11" and python_version < "4.0" |
||||
|
typing-extensions==4.9.0 ; python_version >= "3.11" and python_version < "4.0" |
||||
|
tzdata==2023.4 ; python_version >= "3.11" and python_version < "4.0" and sys_platform == "win32" |
Loading…
Reference in new issue