Enzo Yair

Merge branch 'feature/evento_admin' into 'develop'

Feature/evento admin

feature:
-Creacion de modelos Evento
-Creacion de modelos Fecha
-Validacion de campo direccion
-Validacion de campo fecha_inicio y fecha_final
-Registro de modelo Evento en admin
-Registro de modelo Fecha en admin
Test resultados:
================================================================ 2 passed, 1 warning in 2.64s ================================================================= 

See merge request !2
... ... @@ -110,5 +110,5 @@ deployment/logs/
.pytest_cache/
project/settings/production.py
project/static/*
project/assets/static/*
project/media/*
... ...
from django.contrib import admin
from .models import Evento, FechaEvento
from .forms import EventoForms
# Register your models here.
@admin.register(Evento)
class EventoAdmin(admin.ModelAdmin):
form = EventoForms
list_display = (
'titulo',
'categoria',
'descripcion',
'direccion',
)
search_fields = (
'titulo',
'categoria',
'fecha_inicio',
'fecha_fin',
)
@admin.register(FechaEvento)
class FechaEventoAdmin(admin.ModelAdmin):
model = FechaEvento
... ...
from django.apps import AppConfig
class EventoConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'evento'
... ...
import re
from django import forms
from django.core.exceptions import ValidationError
from django.utils.translation import gettext_lazy as _
from .models import Evento
class EventoForms(forms.ModelForm):
class Meta:
model = Evento
fields = (
'titulo',
'categoria',
'fecha_inicio',
'hora_inicio',
'fecha_final',
'hora_fin',
'fechas',
'descripcion',
'direccion',
'url',
'organismo',
'dependencia',
'imagen',
)
def clean_direccion(self):
clean = super().clean()
direccion = clean.get('direccion')
maps_regex = re.compile(
r'^(https?://)?(www\.)?(google\.com/maps|goo\.gl|maps\.app\.goo\.gl)/\S+$',
re.IGNORECASE
)
if direccion:
if not maps_regex.match(direccion):
raise ValidationError(
_('La dirección no es un enlace válido de Google Maps.')
)
return direccion
def clean_fecha_final(self):
fecha_inicio = self.cleaned_data.get('fecha_inicio')
fecha_final = self.cleaned_data.get('fecha_final')
if fecha_inicio and fecha_final:
if fecha_final < fecha_inicio:
raise ValidationError(
_('La fecha final no puede ser anterior a la fecha de inicio.'
)
)
return fecha_final
def clean_hora_fin(self):
clean = super().clean()
fecha_inicio = clean.get('fecha_inicio')
hora_inicio = clean.get('hora_inicio')
fecha_final = clean.get('fecha_final')
hora_fin = clean.get('hora_fin')
if fecha_final == fecha_inicio:
if hora_fin <= hora_inicio:
raise ValidationError(
_('La hora de finalización debe ser posterior a la hora de inicio.'
)
)
return hora_fin
... ...
# Generated by Django 4.2.9 on 2024-10-02 00:54
import django.core.validators
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
('organismo', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='FechaEvento',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('dia_evento', models.DateField(verbose_name='Días del evento')),
],
options={
'verbose_name': 'Fecha del Eventos',
'verbose_name_plural': 'Fechas del Eventos',
},
),
migrations.CreateModel(
name='Evento',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('fecha_inicio', models.DateField(verbose_name='Fecha de inicio del evento')),
('hora_inicio', models.TimeField(verbose_name='Hora de apertura')),
('fecha_final', models.DateField(verbose_name='Fecha de cierre del evento')),
('hora_fin', models.TimeField(verbose_name='Hora de cierre')),
('titulo', models.CharField(max_length=350)),
('categoria', models.CharField(max_length=150)),
('direccion', models.URLField(help_text='Ingrese la url obtenida por google maps', max_length=150, verbose_name='Ubicación del evento')),
('descripcion', models.TextField(verbose_name='Descripción')),
('url', models.URLField(blank=True, max_length=300, verbose_name='Dirección Web')),
('imagen', models.ImageField(blank=True, upload_to='static/eventos', validators=[django.core.validators.FileExtensionValidator(allowed_extensions=['jpg', 'png'])], verbose_name='Banner promocional')),
('dependencia', models.ManyToManyField(blank=True, related_name='evento_dependencia', to='organismo.dependencia')),
('fechas', models.ManyToManyField(blank=True, help_text='Por favor, indique los días disponibles para el evento', related_name='evento_fechas', to='evento.fechaevento', verbose_name='Días disponibles')),
('organismo', models.ManyToManyField(blank=True, related_name='evento_organismo', to='organismo.organismo')),
],
options={
'verbose_name': 'Evento',
'verbose_name_plural': 'Eventos',
'ordering': ('titulo', 'categoria'),
},
),
]
... ...
from django.db import models
from django.core.validators import FileExtensionValidator
from organismo.models import Organismo, Dependencia
# Create your models here.
class Evento(models.Model):
class Meta:
ordering = 'titulo', 'categoria'
verbose_name = 'Evento'
verbose_name_plural = 'Eventos'
organismo = models.ManyToManyField(
Organismo,
related_name='evento_organismo',
blank=True
)
dependencia = models.ManyToManyField(
Dependencia,
related_name='evento_dependencia',
blank=True
)
fecha_inicio = models.DateField(verbose_name='Fecha de inicio del evento')
hora_inicio = models.TimeField(blank=False, verbose_name='Hora de apertura')
fecha_final = models.DateField(verbose_name='Fecha de cierre del evento')
hora_fin = models.TimeField(blank=False, verbose_name='Hora de cierre')
fechas = models.ManyToManyField(
'FechaEvento',
related_name='evento_fechas',
blank=True,
verbose_name='Días disponibles',
help_text='Por favor, indique los días disponibles para el evento'
)
titulo = models.CharField(max_length=350, null=False)
categoria = models.CharField(max_length=150, null=False)
direccion = models.URLField(
max_length=150,
verbose_name='Ubicación del evento',
help_text='Ingrese la url obtenida por google maps'
)
descripcion = models.TextField(null=False, verbose_name='Descripción')
url = models.URLField(
max_length=300,
blank=True,
verbose_name='Dirección Web'
)
imagen = models.ImageField(
upload_to='static/eventos',
validators=[FileExtensionValidator(allowed_extensions=['jpg', 'png'])],
blank=True,
verbose_name='Banner promocional'
)
def __str__(self):
return f'{self.titulo} - {self.descripcion}'
class FechaEvento(models.Model):
class Meta:
verbose_name = 'Fecha del Eventos'
verbose_name_plural = 'Fechas del Eventos'
dia_evento = models.DateField(verbose_name='Días del evento')
def __str__(self):
return f'{self.dia_evento}'
\ No newline at end of file
... ...
from django.test import TestCase
# Create your tests here.
... ...
from django.shortcuts import render
# Create your views here.
... ...
... ... @@ -63,6 +63,7 @@ THIRD_PARTY_APPS = (
PROJECT_APPS = (
'core',
'organismo',
'evento',
)
INSTALLED_APPS = DJANGO_APPS + THIRD_PARTY_APPS + PROJECT_APPS
... ... @@ -99,7 +100,8 @@ LANGUAGES = [
# https://docs.djangoproject.com/en/1.7/howto/static-files/
STATIC_ROOT = str(PROJECT_DIR.path('static'))
STATIC_URL = '/static/'
STATIC_URL = env.str('DJANGO_STATIC_URL', default='/static/')
STATICFILES_DIRS = [str(PROJECT_DIR.path('assets')), ]
MEDIA_ROOT = str(PROJECT_DIR.path('media'))
MEDIA_URL = env.str('MEDIA_URL', default='/media/')
... ...
... ... @@ -16,6 +16,7 @@ Including another URLconf
from django.contrib import admin
from django.urls import path, include, reverse_lazy
from django.conf import settings
from django.conf.urls.static import static
from django.views.generic.base import RedirectView
from .router import router
... ... @@ -28,4 +29,4 @@ urlpatterns = [
path('', RedirectView.as_view(url=reverse_lazy('admin:index'))),
path('admin/', admin.site.urls),
path('api/v1/', include(router.urls)),
]
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
... ...
... ... @@ -9,6 +9,9 @@ djangorestframework-jsonapi==6.1.0
django-oauth-toolkit==2.3.0
mozilla-django-oidc==3.0.0
# visualizar imagenes.
pillow==10.4.0
# database
psycopg2==2.9.9
... ...