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
Showing
13 changed files
with
241 additions
and
3 deletions
project/apps/evento/__init__.py
0 → 100644
project/apps/evento/admin.py
0 → 100644
1 | +from django.contrib import admin | ||
2 | + | ||
3 | +from .models import Evento, FechaEvento | ||
4 | +from .forms import EventoForms | ||
5 | + | ||
6 | +# Register your models here. | ||
7 | + | ||
8 | + | ||
9 | +@admin.register(Evento) | ||
10 | +class EventoAdmin(admin.ModelAdmin): | ||
11 | + form = EventoForms | ||
12 | + list_display = ( | ||
13 | + 'titulo', | ||
14 | + 'categoria', | ||
15 | + 'descripcion', | ||
16 | + 'direccion', | ||
17 | + ) | ||
18 | + search_fields = ( | ||
19 | + 'titulo', | ||
20 | + 'categoria', | ||
21 | + 'fecha_inicio', | ||
22 | + 'fecha_fin', | ||
23 | + ) | ||
24 | + | ||
25 | + | ||
26 | +@admin.register(FechaEvento) | ||
27 | +class FechaEventoAdmin(admin.ModelAdmin): | ||
28 | + model = FechaEvento |
project/apps/evento/apps.py
0 → 100644
project/apps/evento/forms.py
0 → 100644
1 | +import re | ||
2 | + | ||
3 | +from django import forms | ||
4 | +from django.core.exceptions import ValidationError | ||
5 | +from django.utils.translation import gettext_lazy as _ | ||
6 | + | ||
7 | +from .models import Evento | ||
8 | + | ||
9 | + | ||
10 | +class EventoForms(forms.ModelForm): | ||
11 | + class Meta: | ||
12 | + model = Evento | ||
13 | + fields = ( | ||
14 | + 'titulo', | ||
15 | + 'categoria', | ||
16 | + 'fecha_inicio', | ||
17 | + 'hora_inicio', | ||
18 | + 'fecha_final', | ||
19 | + 'hora_fin', | ||
20 | + 'fechas', | ||
21 | + 'descripcion', | ||
22 | + 'direccion', | ||
23 | + 'url', | ||
24 | + 'organismo', | ||
25 | + 'dependencia', | ||
26 | + 'imagen', | ||
27 | + ) | ||
28 | + | ||
29 | + def clean_direccion(self): | ||
30 | + clean = super().clean() | ||
31 | + direccion = clean.get('direccion') | ||
32 | + | ||
33 | + maps_regex = re.compile( | ||
34 | + r'^(https?://)?(www\.)?(google\.com/maps|goo\.gl|maps\.app\.goo\.gl)/\S+$', | ||
35 | + re.IGNORECASE | ||
36 | + ) | ||
37 | + if direccion: | ||
38 | + if not maps_regex.match(direccion): | ||
39 | + raise ValidationError( | ||
40 | + _('La dirección no es un enlace válido de Google Maps.') | ||
41 | + ) | ||
42 | + return direccion | ||
43 | + | ||
44 | + def clean_fecha_final(self): | ||
45 | + fecha_inicio = self.cleaned_data.get('fecha_inicio') | ||
46 | + fecha_final = self.cleaned_data.get('fecha_final') | ||
47 | + | ||
48 | + if fecha_inicio and fecha_final: | ||
49 | + if fecha_final < fecha_inicio: | ||
50 | + raise ValidationError( | ||
51 | + _('La fecha final no puede ser anterior a la fecha de inicio.' | ||
52 | + ) | ||
53 | + ) | ||
54 | + | ||
55 | + return fecha_final | ||
56 | + | ||
57 | + def clean_hora_fin(self): | ||
58 | + clean = super().clean() | ||
59 | + | ||
60 | + fecha_inicio = clean.get('fecha_inicio') | ||
61 | + hora_inicio = clean.get('hora_inicio') | ||
62 | + fecha_final = clean.get('fecha_final') | ||
63 | + hora_fin = clean.get('hora_fin') | ||
64 | + | ||
65 | + if fecha_final == fecha_inicio: | ||
66 | + if hora_fin <= hora_inicio: | ||
67 | + raise ValidationError( | ||
68 | + _('La hora de finalización debe ser posterior a la hora de inicio.' | ||
69 | + ) | ||
70 | + ) | ||
71 | + | ||
72 | + return hora_fin |
1 | +# Generated by Django 4.2.9 on 2024-10-02 00:54 | ||
2 | + | ||
3 | +import django.core.validators | ||
4 | +from django.db import migrations, models | ||
5 | + | ||
6 | + | ||
7 | +class Migration(migrations.Migration): | ||
8 | + | ||
9 | + initial = True | ||
10 | + | ||
11 | + dependencies = [ | ||
12 | + ('organismo', '0001_initial'), | ||
13 | + ] | ||
14 | + | ||
15 | + operations = [ | ||
16 | + migrations.CreateModel( | ||
17 | + name='FechaEvento', | ||
18 | + fields=[ | ||
19 | + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | ||
20 | + ('dia_evento', models.DateField(verbose_name='Días del evento')), | ||
21 | + ], | ||
22 | + options={ | ||
23 | + 'verbose_name': 'Fecha del Eventos', | ||
24 | + 'verbose_name_plural': 'Fechas del Eventos', | ||
25 | + }, | ||
26 | + ), | ||
27 | + migrations.CreateModel( | ||
28 | + name='Evento', | ||
29 | + fields=[ | ||
30 | + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | ||
31 | + ('fecha_inicio', models.DateField(verbose_name='Fecha de inicio del evento')), | ||
32 | + ('hora_inicio', models.TimeField(verbose_name='Hora de apertura')), | ||
33 | + ('fecha_final', models.DateField(verbose_name='Fecha de cierre del evento')), | ||
34 | + ('hora_fin', models.TimeField(verbose_name='Hora de cierre')), | ||
35 | + ('titulo', models.CharField(max_length=350)), | ||
36 | + ('categoria', models.CharField(max_length=150)), | ||
37 | + ('direccion', models.URLField(help_text='Ingrese la url obtenida por google maps', max_length=150, verbose_name='Ubicación del evento')), | ||
38 | + ('descripcion', models.TextField(verbose_name='Descripción')), | ||
39 | + ('url', models.URLField(blank=True, max_length=300, verbose_name='Dirección Web')), | ||
40 | + ('imagen', models.ImageField(blank=True, upload_to='static/eventos', validators=[django.core.validators.FileExtensionValidator(allowed_extensions=['jpg', 'png'])], verbose_name='Banner promocional')), | ||
41 | + ('dependencia', models.ManyToManyField(blank=True, related_name='evento_dependencia', to='organismo.dependencia')), | ||
42 | + ('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')), | ||
43 | + ('organismo', models.ManyToManyField(blank=True, related_name='evento_organismo', to='organismo.organismo')), | ||
44 | + ], | ||
45 | + options={ | ||
46 | + 'verbose_name': 'Evento', | ||
47 | + 'verbose_name_plural': 'Eventos', | ||
48 | + 'ordering': ('titulo', 'categoria'), | ||
49 | + }, | ||
50 | + ), | ||
51 | + ] |
project/apps/evento/migrations/__init__.py
0 → 100644
project/apps/evento/models.py
0 → 100644
1 | +from django.db import models | ||
2 | + | ||
3 | +from django.core.validators import FileExtensionValidator | ||
4 | + | ||
5 | +from organismo.models import Organismo, Dependencia | ||
6 | + | ||
7 | +# Create your models here. | ||
8 | + | ||
9 | + | ||
10 | +class Evento(models.Model): | ||
11 | + class Meta: | ||
12 | + ordering = 'titulo', 'categoria' | ||
13 | + verbose_name = 'Evento' | ||
14 | + verbose_name_plural = 'Eventos' | ||
15 | + | ||
16 | + organismo = models.ManyToManyField( | ||
17 | + Organismo, | ||
18 | + related_name='evento_organismo', | ||
19 | + blank=True | ||
20 | + ) | ||
21 | + dependencia = models.ManyToManyField( | ||
22 | + Dependencia, | ||
23 | + related_name='evento_dependencia', | ||
24 | + blank=True | ||
25 | + ) | ||
26 | + fecha_inicio = models.DateField(verbose_name='Fecha de inicio del evento') | ||
27 | + hora_inicio = models.TimeField(blank=False, verbose_name='Hora de apertura') | ||
28 | + fecha_final = models.DateField(verbose_name='Fecha de cierre del evento') | ||
29 | + hora_fin = models.TimeField(blank=False, verbose_name='Hora de cierre') | ||
30 | + fechas = models.ManyToManyField( | ||
31 | + 'FechaEvento', | ||
32 | + related_name='evento_fechas', | ||
33 | + blank=True, | ||
34 | + verbose_name='Días disponibles', | ||
35 | + help_text='Por favor, indique los días disponibles para el evento' | ||
36 | + ) | ||
37 | + titulo = models.CharField(max_length=350, null=False) | ||
38 | + categoria = models.CharField(max_length=150, null=False) | ||
39 | + direccion = models.URLField( | ||
40 | + max_length=150, | ||
41 | + verbose_name='Ubicación del evento', | ||
42 | + help_text='Ingrese la url obtenida por google maps' | ||
43 | + ) | ||
44 | + descripcion = models.TextField(null=False, verbose_name='Descripción') | ||
45 | + url = models.URLField( | ||
46 | + max_length=300, | ||
47 | + blank=True, | ||
48 | + verbose_name='Dirección Web' | ||
49 | + ) | ||
50 | + imagen = models.ImageField( | ||
51 | + upload_to='static/eventos', | ||
52 | + validators=[FileExtensionValidator(allowed_extensions=['jpg', 'png'])], | ||
53 | + blank=True, | ||
54 | + verbose_name='Banner promocional' | ||
55 | + ) | ||
56 | + | ||
57 | + def __str__(self): | ||
58 | + return f'{self.titulo} - {self.descripcion}' | ||
59 | + | ||
60 | + | ||
61 | +class FechaEvento(models.Model): | ||
62 | + class Meta: | ||
63 | + verbose_name = 'Fecha del Eventos' | ||
64 | + verbose_name_plural = 'Fechas del Eventos' | ||
65 | + | ||
66 | + dia_evento = models.DateField(verbose_name='Días del evento') | ||
67 | + | ||
68 | + def __str__(self): | ||
69 | + return f'{self.dia_evento}' |
project/apps/evento/tests.py
0 → 100644
project/apps/evento/views.py
0 → 100644
@@ -63,6 +63,7 @@ THIRD_PARTY_APPS = ( | @@ -63,6 +63,7 @@ THIRD_PARTY_APPS = ( | ||
63 | PROJECT_APPS = ( | 63 | PROJECT_APPS = ( |
64 | 'core', | 64 | 'core', |
65 | 'organismo', | 65 | 'organismo', |
66 | + 'evento', | ||
66 | ) | 67 | ) |
67 | 68 | ||
68 | INSTALLED_APPS = DJANGO_APPS + THIRD_PARTY_APPS + PROJECT_APPS | 69 | INSTALLED_APPS = DJANGO_APPS + THIRD_PARTY_APPS + PROJECT_APPS |
@@ -99,7 +100,8 @@ LANGUAGES = [ | @@ -99,7 +100,8 @@ LANGUAGES = [ | ||
99 | # https://docs.djangoproject.com/en/1.7/howto/static-files/ | 100 | # https://docs.djangoproject.com/en/1.7/howto/static-files/ |
100 | 101 | ||
101 | STATIC_ROOT = str(PROJECT_DIR.path('static')) | 102 | STATIC_ROOT = str(PROJECT_DIR.path('static')) |
102 | -STATIC_URL = '/static/' | 103 | +STATIC_URL = env.str('DJANGO_STATIC_URL', default='/static/') |
104 | +STATICFILES_DIRS = [str(PROJECT_DIR.path('assets')), ] | ||
103 | 105 | ||
104 | MEDIA_ROOT = str(PROJECT_DIR.path('media')) | 106 | MEDIA_ROOT = str(PROJECT_DIR.path('media')) |
105 | MEDIA_URL = env.str('MEDIA_URL', default='/media/') | 107 | MEDIA_URL = env.str('MEDIA_URL', default='/media/') |
@@ -16,6 +16,7 @@ Including another URLconf | @@ -16,6 +16,7 @@ Including another URLconf | ||
16 | from django.contrib import admin | 16 | from django.contrib import admin |
17 | from django.urls import path, include, reverse_lazy | 17 | from django.urls import path, include, reverse_lazy |
18 | from django.conf import settings | 18 | from django.conf import settings |
19 | +from django.conf.urls.static import static | ||
19 | from django.views.generic.base import RedirectView | 20 | from django.views.generic.base import RedirectView |
20 | 21 | ||
21 | from .router import router | 22 | from .router import router |
@@ -28,4 +29,4 @@ urlpatterns = [ | @@ -28,4 +29,4 @@ urlpatterns = [ | ||
28 | path('', RedirectView.as_view(url=reverse_lazy('admin:index'))), | 29 | path('', RedirectView.as_view(url=reverse_lazy('admin:index'))), |
29 | path('admin/', admin.site.urls), | 30 | path('admin/', admin.site.urls), |
30 | path('api/v1/', include(router.urls)), | 31 | path('api/v1/', include(router.urls)), |
31 | -] | 32 | +] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) |
@@ -9,6 +9,9 @@ djangorestframework-jsonapi==6.1.0 | @@ -9,6 +9,9 @@ djangorestframework-jsonapi==6.1.0 | ||
9 | django-oauth-toolkit==2.3.0 | 9 | django-oauth-toolkit==2.3.0 |
10 | mozilla-django-oidc==3.0.0 | 10 | mozilla-django-oidc==3.0.0 |
11 | 11 | ||
12 | +# visualizar imagenes. | ||
13 | +pillow==10.4.0 | ||
14 | + | ||
12 | 15 | ||
13 | # database | 16 | # database |
14 | psycopg2==2.9.9 | 17 | psycopg2==2.9.9 |
-
Please register or login to post a comment