Problema al sobreescribir metodo save() con campo ManyToMany

334 views
Skip to first unread message

Sandra V.

unread,
Jul 29, 2015, 12:16:56 AM7/29/15
to Django-es
Hola colegas:
Estoy empezando con Django y me encuentro con un problema que por mucho que leído no he encontrado la repuesta. Resulta que tengo una clase Descriptor, que entre otros campos, tiene uno que es 'termino_generico' y otro 'termino_especifico', que tienen una relación de M2M con la misma clase Descriptor. Así queda una parte del modelo:
class Descriptor(models.Model):
  termino
= models.CharField(max_length=200, unique=True, verbose_name="Término")
  termino_generico
= models.ManyToManyField('self', related_name="generic_term", symmetrical=False, null=True, blank=True, verbose_name="Término genérico")
  termino_especifico
=  models.ManyToManyField('self', related_name="specific_terms", symmetrical=False, null=True, blank=True, verbose_name="Términos específicos")
La lógica que debo aplicar es que si un descriptor tiene un término genérico, entonces ese descriptor va a ser un término específico del término genérico. Ejemplo: "Gato" tiene como término genérico "Animal", por tanto, "Gato" va a ser un término específico de "Animal".
La forma que se me ocurrió de representar esto fue haciéndolo "a mano" en el método save().
def save(self, *args, **kwargs):
 
if self.id:
    genericos
= self.termino_generico.all()
   
for g in genericos:
      b
.termino_especifico.add(self)
 
super(Descriptor, self).save(*args, **kwargs)
Y eso me funciona de cierto modo, porque me inserta bien la relación cuando guardo el Descriptor por segunda vez, o sea, cuando ya está creado. No sé si tendrá que ver con el «if.self.id» que le agregué, pero si se lo quito, me lanza este error:
<Descriptor: Felino>" needs to have a value for field "from_descriptor" before this many-to-many relationship can be used
Me pueden ayudar? Lo que requiero es que desde el primer momento en que yo le de Guardar, se salve la relación y todo.
Saludos y agradecida de antemano.

monoBOT

unread,
Jul 29, 2015, 8:38:45 AM7/29/15
to djan...@googlegroups.com
los campos many to many solo se pueden guardar cuando el objeto que los contiene esta guardado. es decir cuando tiene id; y la razón de esto es porque lo que hace el orm de django es crear tablas relacionales entre los diferentes objectos y sus campos many to many. Lo mismo ocurre con los foreignkey.

No entiendo bien la relacion que estás creando entre los diferentes objetos pero crear una clase y relacionarla dos veces many2many con el mismo tipo de clase me parece como muy enrevesado.

Tal vez lo que pasa es que no sepas que los objetos se relacionan a través del orm de forma bidireccional es decir 
usando '_set'


saludos!

--
--
Ha recibido este mensaje porque está suscrito a Grupo "Grupo de Usuarios del Framework Django de habla hispana" de Grupos de Google.
Si quieres publicar en este grupo, envía un mensaje de correo
electrónico a djan...@googlegroups.com
Para anular la suscripción a este grupo, envíe un mensaje a django-es-...@googlegroups.com
Para obtener más opciones, visita este grupo en http://groups.google.com.bo/group/django-es.
---
Has recibido este mensaje porque estás suscrito al grupo "Django-es" de Grupos de Google.
Para anular la suscripción a este grupo y dejar de recibir sus mensajes, envía un correo electrónico a django-es+...@googlegroups.com.
Para acceder a más opciones, visita https://groups.google.com/d/optout.



--
monoBOT
Visite mi sitio(Visit my site): monobotsoft.es/blog/

Hiko hitokiri

unread,
Jul 29, 2015, 9:35:12 AM7/29/15
to djan...@googlegroups.com
la verdad no me queda claro que es lo que quieres hacer si me das un poco de contexto que es lo que quieres lograr te podría ayudar

Sandra V.

unread,
Jul 29, 2015, 11:04:17 AM7/29/15
to Django-es, sandra....@gmail.com
Hola. Agradezco el tiempo que me han dedicado. Voy a contextualizar a ver si me comprenden mejor.
Estoy haciendo un tesauro o vocabulario controlado, que no son más que términos (descriptores) que tienen diferentes relaciones con otros terminos. Un descriptor tiene términos genéricos, términos específicos, términos relacionados. Ejemplo:
Término: Felino
Término Genérico: Animal
Términos Específicos: Gato, Tigre, Jaguar
Donde Felino, Animal, Gato, Tigre y Jaguar son descriptores.
La cosa es que como regla de los tesauros, si Gato, Tigre y Jaguar son Términos Específicos de Felino, entonces Felino es Término Genérico de estos 3 descriptores. Dicho en lenguaje natural sería: Los tipos de felinos son Gato, Tigre y Jaguar; y Gato, Tigre, Jaguar son felinos
Entendido eso, espero que comprendan mejor mi modelo. Ahora, el problema está en que esa inferencia que les comenté anteriormente no sé cómo hacerla. Se me ocurrió que podía ser en el método save() como les puse anteriormente.
monoBOT entiendo perfectamente lo que me comentas sobre las relaciones M2M. Pero es que necesito encontrar la forma para que cuando yo llame al método save() salve primero el descriptor para tener ya un id, y luego me guarde las relaciones, pero de una vez!
Alternativamente, el método me quedó así, pero con el mismo resultado:
def save(self, *args, **kwargs):
   
super(Descriptor, self).save(*args, **kwargs)
    broaders
= self.broader.all()
   
for b in broaders:
      b
.narrower.add(self)
Agradecida una vez más. Perdonen tanto texto y tanta explicación :)

Hiko hitokiri

unread,
Jul 29, 2015, 11:23:01 AM7/29/15
to djan...@googlegroups.com
hum no se si soy yo pero veo muy mal ese modelo desde el punto que todos apuntan a el mismo como podrías hacer categorías y sub categorías  si estas buscando y guardándolas a ellas mismas. ya que si no defines el tipo o por lo menos ahí no se ve . eso es un desorden terrible esa clase en mi opinión por lo menos.

para evitar problemas de esta clase deberías de dividirla en tres

Término
Término Genérico
Términos Específicos

Sandra V.

unread,
Jul 29, 2015, 11:37:24 AM7/29/15
to Django-es, las...@gmail.com
hiko_hitokiri el problema es que todos al final son términos. Yo no puedo crear como instancia de un Término Específico a Felino por ejemplo, porque él es un Término, que además también es un Término Genérico de Gato como puse en el ejemplo, que al mismo tiempo que puede ser un Término Específico de Animal. Te das cuenta de que me quedaría en el aire a la hora de ver a qué clase pudiera pertenecer? A lo mejor es que no logro explicarlo bien :(

Franklin Sarmiento

unread,
Jul 29, 2015, 11:47:31 AM7/29/15
to Django-es
Saludos, y si trabajas con clases abstractas ?

--
--
Ha recibido este mensaje porque está suscrito a Grupo "Grupo de Usuarios del Framework Django de habla hispana" de Grupos de Google.
Si quieres publicar en este grupo, envía un mensaje de correo
electrónico a djan...@googlegroups.com
Para anular la suscripción a este grupo, envíe un mensaje a django-es-...@googlegroups.com
Para obtener más opciones, visita este grupo en http://groups.google.com.bo/group/django-es.
---
Has recibido este mensaje porque estás suscrito al grupo "Django-es" de Grupos de Google.
Para anular la suscripción a este grupo y dejar de recibir sus mensajes, envía un correo electrónico a django-es+...@googlegroups.com.
Para acceder a más opciones, visita https://groups.google.com/d/optout.



--
FGSC

Hiko hitokiri

unread,
Jul 29, 2015, 12:02:33 PM7/29/15
to djan...@googlegroups.com
en realidad no veo por que te quedarías en el aire ya que tienes dos campos que apuntarían a esas otras dos clases adicionales.  y como serias tu la que decidiese a cuales pertenecen no veo por que el problema.

ojo: esa es mi opinión de como podrías hacerlo para no enredarte pero al final eres tu quien decide. mi forma no es la mejor ni la única solo lo que yo veo mas factible según lo entiendo

ya que de todos modos en la interfaz depende como la hagas al final tu seras quien le diga a cuales de los otros dos campos pertenece. si tienes dudas yo te puedo hacer un ejemplo de lo que te estoy diciendo . solo dime como se supone que el usuario ingresa los datos y escoge a que tipo lo y sub tipo pertenece según ese ejemplo que has hecho .
si puedes mandar el projecto en un zip para verlo y modificarlo como te digo asi tu decides 

 

Franklin Sarmiento

unread,
Jul 29, 2015, 12:20:24 PM7/29/15
to Django-es
y si trabajas con clases abstractas ? es el mejor ejemplo para clases que son dependientes de un mismo tipo teniendo en común las mismas características y funcionalidades.

Saludos!


Sandra V.

unread,
Jul 29, 2015, 12:34:38 PM7/29/15
to Django-es, frankl...@gmail.com
Gracias chicos por contestar.
Es que aun no veo claro lo de dividir las clases ni de crear una abstracta. Voy a intentar enviar en un .zip lo que tengo del proyecto a ver si me logran entenderme, o que traten de describirme mejor lo que me están sugiriendo.
Sldos!!

David Helmut Reese Molinas

unread,
Jul 29, 2015, 1:26:10 PM7/29/15
to djan...@googlegroups.com
Seún creo entender la clave está en lo que dijiste en el último email... "Todos son términos"... y finalmente pueden relacionarse entre sí sin tener una "jerarquía" perfectamente lógica para el sistema.

Aun así no creo que lo que plantea Hiko Hitokiri esté mal:
Finalmente lo que hará el orm es crear dos entidades (tablas) para las relaciones M2M, por lo que igualmente tendrás una tabla de:

Terminos como principal y dos tablas "hijas" que serían
TerminosGenericos y
TerminosEspecificos
que representarían tus relaciones M2M
El ORM lo hará por detrás de todas maneras, Ahora, el hacerlo en el código ayudará más bien a la lectura y comprensión del código...

Ahora, sobre la forma de enfocarlo creo que primero necesitas analizar la jerarquía, ya que, aunque aparentemente no existe, tiene una lógica jerárquica.
Por decir:

Si Animal es un Termino Genérico de Felino
y Felino es un Termino Genérico de Gato, Tigre y Leon
y Gato es un Termino Genérico de Siames, Persa y Angola...

La lógica te indica que Felino no puede ser un término "específico" de "Persa", así como Gato no puede ser un término Genérico de Animal, por lo que solo necesitarías una relación

Todos son términos, por lo que solucionas las relaciones de registros teniendo:

class Descriptor(models.Model):
  termino 
= models.CharField(max_length=200, unique=True, verbose_name="Término")

  termino_especifico 
=  models.ManyToOne('self', related_name="specific_terms", symmetrical=False, null=True, blank=True, verbose_name="Términos específicos")

ya que la relación indica qué si el registro cuenta con un término específico, por lógica el registro creado es un término genérico de sus terminos específicos.

Todo registro es un "término" que: 
si se agrega a la lista de "especificos" de otro término lo convierte en el termino específico de este
si se agrega un termino a su lista de "especificos" se asume como termino genérico de este

Y al ser una relacion de autoreferencia no es restrictiva, por lo que con una relación uno a muchos solucionas la lógica.
Creo que esto lo haría más fácil de programar.


--
--
Ha recibido este mensaje porque está suscrito a Grupo "Grupo de Usuarios del Framework Django de habla hispana" de Grupos de Google.
Si quieres publicar en este grupo, envía un mensaje de correo
electrónico a djan...@googlegroups.com
Para anular la suscripción a este grupo, envíe un mensaje a django-es-...@googlegroups.com
Para obtener más opciones, visita este grupo en http://groups.google.com.bo/group/django-es.
---
Has recibido este mensaje porque estás suscrito al grupo "Django-es" de Grupos de Google.
Para anular la suscripción a este grupo y dejar de recibir sus mensajes, envía un correo electrónico a django-es+...@googlegroups.com.
Para acceder a más opciones, visita https://groups.google.com/d/optout.



--
----------------------------------------
David H. Reese M.
Investigación y Desarrollo
Dirección Nacional de Contrataciones Públicas
Asunción - Paraguay
Teléfono: 595 971 351390
----------------------------------------

Sandra V.

unread,
Jul 29, 2015, 1:51:37 PM7/29/15
to Django-es, dree...@gmail.com
Hola! Entendí lo que me propones y me parece la solución correcta. El lio es que en el momento en que lo modelé, no tenía clara la inferencia que había que hacer, y cuando me lo dijeron, traté de meter hacerlo con lo que estaba y no me daba cuenta de que había que cambiar el modelo. Muchas gracias!! Ahora es mucho más fácil :)
Agradezco a todos por la colaboración. Sldos
Reply all
Reply to author
Forward
0 new messages