2009-09-07 15 views
5

Quiero asegurarme de que un objeto sea único y arrojar un error cuando un usuario intenta guardarlo (por ejemplo, a través del administrador) de no ser así? Por único, quiero decir que algunos de los atributos del objeto pueden tener los mismos valores que los de otros objetos, pero no todos PUEDEN ser idénticos a los valores de otros objetos.objetos únicos SECADOS en Django

Si no me equivoco, yo puedo hacer esto de esta manera:

class Animal(models.Model): 
    common_name = models.CharField(max_length=150) 
    latin_name = models.CharField(max_length=150) 
    class Meta: 
     unique_together = ("common_name", "latin_name") 

Pero entonces cada vez que refactorizar el modelo (por ejemplo, para añadir un nuevo campo, o para cambiar el nombre de un campo existente), También tengo que editar la lista de campos en el paréntesis asignado a unique_together. Con un modelo simple, está bien, pero con uno sustancial, se convierte en una verdadera molestia durante la refactorización.

¿Cómo puedo evitar tener que repetir escribiendo la lista de nombres de campo en el unique_together entre paréntesis? ¿Hay alguna manera de pasar la lista de los campos del modelo a una variable y asignar esa variable a unique_together en su lugar?

+1

+1 - grande pregunta. No creo que puedas, pero estoy interesado en escuchar las opiniones de los demás. –

+0

+1 - Realmente es interesante si alguien puede encontrar una buena solución. Lo intenté pero no pude hacerlo a través de la reflexión, porque no puedes leer las propiedades de la clase Animal (lo cual es obvio porque Animal no está completamente definido en ese momento). – FlorianH

+0

jtiai on irc: //irc.freenode.net/django amablemente se tomó un tiempo para discutir la pregunta y sugirió que podía 'agregar mi propia clase' AllUniqueModel ', heredar el' Modelo 'estándar y hacer algo de magia de metaclass para inyectar todos los campos en unique_togerther después de que sean procesados ​​por el procedimiento de creación estándar. ' No estoy del todo seguro de lo que jtiai quiso decir con eso, pero parece una solución más complicada de lo que esperaba. – sampablokuper

Respuesta

4

modelos de Refactoring es una cosa bastante caro hacerlo:

  • Tendrá que cambiar todo el código usando sus modelos ya que los nombres de campo corresponden a propiedades de objetos
  • Tendrá que cambiar la base de datos manualmente desde Django no puede hacer esto para usted (al menos la versión que utilizó la última vez cuando trabajaba con Django no podía)

por lo tanto pienso actualización de la lista de nombres de campos únicos en la clase meta modelo es el menos problema que debería preocuparse combate.

EDITAR: Si de verdad quieres hacer esto y todo de sus campos debe ser "única juntos", entonces el chico en freenode es correcto y que tendrá que escribir una metaclase personalizado. Esto es bastante complicado y propenso a errores, además puede hacer que su código sea incompatible con versiones futuras de Django.

ORM de Django "magic" está controlado por la metaclase ModelBase (django.db.models.base.ModelBase) de la clase base genérica Model. Esta clase es responsable de tomar su definición de clase con todos los campos y metainformación y construir la clase que usará en su código más adelante.

Esta es una receta de cómo se podría lograr su objetivo:

  1. Subclase ModelBase utilizar su propio metaclase.
  2. reemplazar el método __new__(cls, name, bases, dict)
  3. Inspeccionar dict para reunir la Meta miembro (dict["Meta"]), así como todos los miembros de campo
  4. Establecer meta.unique_together en base a los nombres de los campos que se reunieron.
  5. Llame a la aplicación super (ModelBase.__new__)
  6. Uso de la metaclase personalizado para todos sus modelos únicos utilizando el miembro de la magia __metaclass__ = MyMetaclass (o derivar una clase base abstracta que se extiende Model y anulando la metaclase)
+1

En la etapa de creación de prototipos, los modelos de refactorización son baratos, pero la duplicación del código es costosa, de ahí mi pregunta. Obviamente, en producción, es una cuestión diferente, pero si se puede encontrar una buena respuesta a mi pregunta, esto al menos reducirá * uno * de los pasos que de otro modo tendría que tomar al refactorizar en producción. – sampablokuper

+1

Vea mi respuesta actualizada para la respuesta larga, tal vez entienda que puede ser demasiado complicado de hacer. –

+2

Gracias por actualizar su respuesta. Sí, veo que es bastante complicado lograr esto. Hmm. Sería muy bueno si Django pudiera simplemente proporcionar la opción de especificar ** unique \ _together = (all) ** o somesuch, o si pudiera permitir a los modelos realizar una introspección sobre ellos mismos para generar listas de campo para pasar a las opciones Meta, etc. . O ambos :) – sampablokuper

Cuestiones relacionadas