PDA

Ver la versión completa : Agregación Django



mbr386
29-06-2020, 06:19 AM
Como va foro ?

LLevo un par de días leyendo la documentación de Django y por stackoverflow, sinceramente debe ser mi nivel de inglés porque no puedo dar con la solución.

Tengo una agregación y quiero representarla en el modelo, algo así:

https://imgur.com/NoipesH.jpg
En la BD las agregaciones que tengo son como en el caso 1 (no se si afecta la cardinalidad de la relación dentro de la agregación para armarla), me falto agregar quizás un caso 3(1aN entre usuarios y la agregación) y 4(1a1 entre usuarios y la agregación).

Ahora estoy tirando fruta para ver si llego a lo que debería ser... las clases me quedaron algo así:


class USUARIOS(AbstractUser):
first_name = models.CharField(_("Nombre"), max_length=50, null=False)
last_name = models.CharField(_("Apellido"), max_length=50, null=True, blank=True)
email = models.EmailField(unique=True, max_length=100, null=False)
Telefono = models.PositiveIntegerField(null=True, blank=True)
Celular = models.PositiveIntegerField(null=True, blank=True)
TipoUsuario = models.CharField(max_length=20, null=False)

USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username', 'first_name', 'TipoUsuario']



class MENSAJE(models.Model):
Mensjae = models.TextField(max_length=500, null=False)



class NOTIFICACION(models.Model):
FechaEnvio = models.TimeField(default=now, null=False)
Mensaje = models.ForeignKey(MENSAJE, on_delete=models.CASCADE)


Acá es donde quiero armar la agregación (pura fruta):


class USUARIO_NOTIFICACION_MENSAJE(models.Model):
NotificacionMensaje = models.ManyToManyField(NOTIFICACION, through='USUARIO_NOTIFICACION_MENSAJE')
Usuarios = models.ForeignKey(USUARIOS, on_delete=models.CASCADE, null=False)

El resultado son 2 tablas
1) USUARIO_NOTIFICACION_MENSAJE que tiene un ID y la clave foranea Usuarios
2) USUARIO_NOTIFICACION_MENSAJE_NotificacionMensaje que tiene un ID, la clave foranea USUARIO_NOTIFICACION_MENSAJE y la clave foranea NOTIFICACION

Acá si las cosas las hiciera bien debería tener: ID, clave foranea NOTIFICACION, clave foranea MENSAJE y clave foranea USUARIOS.


Además de crear la agregación me gustaría que la clave de MENSAJE se propague a NOTIFICACION y no quede en otra tabla.

La BD me debería quedar:

TABLA 1: NOTIFICACION
TABLA 2: MENSAJE
TABLA 3: USUARIO
TABLA 4: AGREGACIÓN (TABLAS 1,2 Y 3)

Si soluciono me conformo con que quede así:

TABLA 1: NOTIFICACION
TABLA 2: MENSAJE
TABLA 3: RELACIÓN (TABLAS 1 Y 2)
TABLA 4: USUARIO
TABLA 5: AGREGACIÓN (TABLAS 1,2 Y 3)

Y ya que estoy, en que me cambia que yo arme la tabla a mano ?

Desde ya les agradezco !!!

Master of the Wind
29-06-2020, 02:31 PM
Salgo del retiro, porque por lo que veo la Fundadora no participa fuera de su topic sagrado de feminismo, es un ejemplo de staff, le re importa su ideologia fascista, digo, el foro.



Una agregacion que tiene una relacion N a 1 no tiene sentido, cuando se te da ese caso es mejor una relacion N a 1 con totalidad, y la relacion fuera de la relacion, la relacionas directamente con la entidad que tiene la N, en ese caso, yo haria

[Usuario] -- N ---- <Generan> --- N -- [Notificacion] --N ----- o< Tienen > ---1- [Mensaje]

Las relaciones N a 1 sin totalidad de por si no tienen mucho sentido, te generan una tabla mas que no aporta demasiado.

Otra cosa, yo ahi tambien haria una relacion triple entre las 3, muy parecido al caso 1



. [Notificacion] --N-----<Generan> ------1 [Mensaje]
. ....................................|
. ....................................|
. ....................................|
. ....................................N
. ...............................[Usuario]


Le pongo .... porque los espacios en blanco no andan

La agregacion es solamente cuando las entidades de adentro se relacionan siempre, y ocacionalmente con la de afuera, si tenes 3 entidades relacionandose siempre, es mejor una relacion triple, da menos redundancia y mas consistencia.



Django es un poco complejo con las tablas de relaciones porque le encanta hacer un id automaticamente como PK salvo que le digas lo contrario, y sobretodo, NO soporta claves primarias compuestas por mas de una columna.


Fijate si te convence el modelo como te puse ahi y vemos como pilotearla en django.


Que armes la tabla vos a mano en funcionamiento no te cambia nada, si usas migrations ganas consistencia, y como es codigo fuente, podes versionar la estructura de la db dentro del mismo codigo y no aparte, ademas que podes hacer rollback por ejemplo si una tabla queda mal definida, o si cambias un modelo, y generas y aplicas la migration le cambia la estructura a la tabla automaticamente.

mbr386
29-06-2020, 04:09 PM
Una agregacion que tiene una relacion N a 1 no tiene sentido, cuando se te da ese caso es mejor una relacion N a 1 con totalidad, y la relacion fuera de la relacion, la relacionas directamente con la entidad que tiene la N, en ese caso, yo haria

[Usuario] -- N ---- <Generan> --- N -- [Notificacion] --N ----- o< Tienen > ---1- [Mensaje]

Las relaciones N a 1 sin totalidad de por si no tienen mucho sentido, te generan una tabla mas que no aporta demasiado.

Otra cosa, yo ahi tambien haria una relacion triple entre las 3, muy parecido al caso 1



. [Notificacion] --N-----<Generan> ------1 [Mensaje]
. ....................................|
. ....................................|
. ....................................|
. ....................................N
. ...............................[Usuario]


Le pongo .... porque los espacios en blanco no andan

La agregacion es solamente cuando las entidades de adentro se relacionan siempre, y ocacionalmente con la de afuera, si tenes 3 entidades relacionandose siempre, es mejor una relacion triple, da menos redundancia y mas consistencia.

Lo veo bien en la noche y te digo.
edit: ahora viendo el mer tiene mas sentido lo que decís, sale cambiazo.



Django es un poco complejo con las tablas de relaciones porque le encanta hacer un id automaticamente como PK salvo que le digas lo contrario, y sobretodo, NO soporta claves primarias compuestas por mas de una columna.

Lo de generar ID lo había leído, creo que me puede servir la autogeneración de ID. Estoy haciendo un proyecto personal con la idea de aprender aun mas django y me encontré con esto que me superó. Seguro que a manopla anda pero quería hacerlo como django manda (por lo que leí podría ganar en armar las consultas mas fácil)



Fijate si te convence el modelo como te puse ahi y vemos como pilotearla en django.

pss no va a servir, ya estoy viendo de cambiarlo.



Que armes la tabla vos a mano en funcionamiento no te cambia nada, si usas migrations ganas consistencia, y como es código fuente, podes versionar la estructura de la db dentro del mismo codigo y no aparte, ademas que podes hacer rollback por ejemplo si una tabla queda mal definida, o si cambias un modelo, y generas y aplicas la migration le cambia la estructura a la tabla automaticamente.

en cada app se crea una carpeta migrations con los archivos de las migraciones. Siempre me dan problemas cuando modifico algo. Buscando encontré que la solución podía ser borrando esos archivos. Como vi que funciona ya lo hago por defecto


El tema con django es que me gustaría hacerlo como django manda, me parece una chanchada hacerlo a mano. Se que se puede hacer porque ya lo hice, pero no quiero hacerlo siempre así.

Master of the Wind
29-06-2020, 05:51 PM
El tema con las migrations es que cuando haces un cambio en un model, tenes que ejecutar "python manage.py makemigrations [NOMBRE DE LA APP]", con eso no tenes margen de falla.


El ID generado autonumerico esta bueno para algunas cosas, normalmente las tablas que representan entidades, para otras te rompe la integridad referencial a la mierda, a los campos que quieras que sean tu clave privada les podes poner UNIQUE, pero no se comporta como clave primaria, ya que son unicos los valores de cada columna y no la combinacion de ambas como si fuera una PK y termina rompiendo las pelotas, y terminas metiendo las FK de otras tablas como columnas normales y controlando por software el valor de ambas, y entras en lo que defino como la anomalía de la caja de zapatos: si vas a usar una base de datos que no controla nada, y tenes que hacer cosas por software, no estas usando una base de datos, es una caja de zapatos que le tiras cosas para adentro nomas.

Master of the Wind
29-06-2020, 08:26 PM
Los modelos estan bien definidos, segui en esa linea nomas y vas a andar bien.

Un par de detalles de convenciones de codigo, no le pongas nombres a las clases en mayuscula, solo pone en mayuscula la primer letra de cada palabra (por ejemplo, si tuvieras una clase Usuario Especial, tendria que llamarse UsuarioEspecial).

Lo mismo podes hacer con las variables Fields para los selectors, en vez de separar con _ podes poner "UsernameFields", eso es una convencion de casing que lo podes aplicar todo: clases, funciones, variables, instancias, etc, normalmente lo que se hace es cuando un elemento es publico la primer letra de la primer palabra empieza en mayuscula, y cuando es privado o local es en minuscula, pero seguis saltando de palabra con mayuscula (se llaman Camel Casing para los elementos privados o locales y Pascal Casing para los elementos publicos, por si queres seguir viendo mas)

Por ejemplo

clasePrivada
ClasePublica

FuncionPublica
funcionLocal

Te queda mucho mas natural, usable y entendible en el codigo.



Vuelvo a mi retiro pro facismo, no sea cosa que la fundadora se entere que volvi y pida mi nai cabeza para tirarle el ban-hammer por hate-speech, aunque lo dudo ya que no entra al 90% del foro.

mbr386
30-06-2020, 06:03 AM
Los modelos estan bien definidos, segui en esa linea nomas y vas a andar bien.

Un par de detalles de convenciones de codigo, no le pongas nombres a las clases en mayuscula, solo pone en mayuscula la primer letra de cada palabra (por ejemplo, si tuvieras una clase Usuario Especial, tendria que llamarse UsuarioEspecial).

Lo mismo podes hacer con las variables Fields para los selectors, en vez de separar con _ podes poner "UsernameFields", eso es una convencion de casing que lo podes aplicar todo: clases, funciones, variables, instancias, etc, normalmente lo que se hace es cuando un elemento es publico la primer letra de la primer palabra empieza en mayuscula, y cuando es privado o local es en minuscula, pero seguis saltando de palabra con mayuscula (se llaman Camel Casing para los elementos privados o locales y Pascal Casing para los elementos publicos, por si queres seguir viendo mas)

Por ejemplo

clasePrivada
ClasePublica

FuncionPublica
funcionLocal

Te queda mucho mas natural, usable y entendible en el codigo.



Vuelvo a mi retiro pro facismo, no sea cosa que la fundadora se entere que volvi y pida mi nai cabeza para tirarle el ban-hammer por hate-speech, aunque lo dudo ya que no entra al 90% del foro.

Ahí tenes razón, las convenciones para que ja.
Las puse en mayúscula porque así entendía rápido que era el nombre de la clase, no recuerdo por qué cuando estaba haciendo el otro proyecto (también para aprender) me confundía con algo, no recuerdo. se que lo había nombrado muy parecido (cambiaba alguna letra en mayúscula, igual se me complicaba) y me armaba tremendo pedo.

Y respecto a las migraciones, yo uso a secas "py manage.py makemigrations". Claro, por eso me debe dar pila de problemas. voy a empezar a usar la migración solo de la app que modifico

mbr386
30-06-2020, 09:00 AM
Leyendo un poco mas en la web de django dicen que usar ManyToManyField es lo mismo que ForeignKey, así que bueno. Sale con ForeignKey y la tabla a manopla (igual voy a seguir leyendo porque como dije antes me gustaría seguir aplicar ManyToManyField).
Lo otro es que justo esas relaciones las podía simplificar un poco más, 2 tablas para guardar 1 atributo. Creo que lo voy a dejar así:

https://imgur.com/kGahFGN.jpg

De todos modos me sirve lo que comentaste master porque tengo 3 agregaciones más que podría revisar, son candidatas a cambiarse.

Gracias cHe!