python tutorial - Cómo funcionan las propiedades en los campos del modelo django?




queryset filter (4)

Creo que la mejor manera de hacer esta pregunta es con algún código ... ¿puedo hacer esto? ( editar : RESPUESTA: no)


    class MyModel(models.Model):
foo = models.CharField(max_length = 20)
bar = models.CharField(max_length = 20)
    def get_foo(self):  
        if self.bar:  
            return self.bar  
        else:  
            return self.foo  

    def set_foo(self, input):  
        self.foo = input  

    foo = property(get_foo, set_foo)  

o tengo que hacerlo así:

Sí, tienes que hacerlo así:

class MyModel(models.Model):
    _foo = models.CharField(max_length = 20, db_column='foo')
    bar = models.CharField(max_length = 20)

    def get_foo(self):
        if self.bar:
            return self.bar
        else:
            return self._foo

    def set_foo(self, input):
        self._foo = input

    foo = property(get_foo, set_foo)

nota : puede mantener el nombre de la columna como 'foo' en la base de datos al pasar una columna db al campo modelo. Esto es muy útil cuando trabajas en un sistema existente y no quieres tener que hacer migraciones de db sin ningún motivo


Answers

Como se mencionó, una alternativa correcta para implementar su propia clase django.db.models.Field, se debe usar el argumento db_column y un atributo de clase personalizado (u oculto). Solo estoy reescribiendo el código en la edición de @Jiaaro siguiendo convenciones más estrictas para OOP en python (por ejemplo, si _foo debe estar realmente oculto):

class MyModel(models.Model):
    __foo = models.CharField(max_length = 20, db_column='foo')
    bar = models.CharField(max_length = 20)

    @property
    def foo(self):
        if self.bar:
            return self.bar
        else:
            return self.__foo

    @foo.setter
    def foo(self, value):
        self.__foo = value

__foo se resolverá en _MyModel__foo (como se ve por dir (..) ) así oculto ( private ). Tenga en cuenta que este formulario también permite el uso de @property decorator, que en última instancia sería una forma más agradable de escribir código legible.

De nuevo, django creará la tabla * _MyModel con dos campos foo y barra .


Las soluciones anteriores sufren porque @property causa problemas en el administrador y .filter (_foo).

Una mejor solución sería anular setattr, excepto que esto puede causar problemas al inicializar el objeto ORM desde el DB. Sin embargo, hay un truco para evitar esto, y es universal.

class MyModel(models.Model):
    foo = models.CharField(max_length = 20)
    bar = models.CharField(max_length = 20)

    def __setattr__(self, attrname, val):
        setter_func = 'setter_' + attrname
        if attrname in self.__dict__ and callable(getattr(self, setter_func, None)):
            super(MyModel, self).__setattr__(attrname, getattr(self, setter_func)(val))
        else:
            super(MyModel, self).__setattr__(attrname, val)

    def setter_foo(self, val):
        return val.upper()

El secreto es ' attrname en self .__ dict__ '. ¡Cuando el modelo se inicializa desde nuevo o hidratado desde el __dict__ !


Un campo modelo ya es propiedad, por lo que diría que tienes que hacerlo de la segunda manera para evitar un conflicto de nombres.

Cuando defines foo = property (..), en realidad anula la línea foo = models .. para que ese campo ya no sea accesible.

Tendrá que usar un nombre diferente para la propiedad y el campo. De hecho, si lo haces de la manera en que lo tienes en el ejemplo n. ° 1, obtendrás un bucle infinito cuando intentes acceder a la propiedad, ya que ahora intenta regresar por sí mismo.

EDITAR: Quizás también debas considerar no usar _foo como nombre de campo, sino foo, y luego definir otro nombre para tu propiedad porque las propiedades no se pueden usar en QuerySet, por lo que necesitarás usar los nombres de campo reales cuando hagas un filtrar por ejemplo.


No entiendo por qué la gente lo hace tan complicado:

objs.sort(function(a, b){
  return a.last_nom > b.last_nom;
});

Para motores más estrictos:

objs.sort(function(a, b){
  return a.last_nom == b.last_nom ? 0 : +(a.last_nom > b.last_nom) || -1;
});

Cambie el operador para ordenarlo por orden alfabético inverso.





python django properties models