Buscar..


Introducción

En el caso básico, un modelo es una clase de Python que se asigna a una única tabla de base de datos. Los atributos de la clase se asignan a las columnas de la tabla y una instancia de la clase representa una fila en la tabla de la base de datos. Los modelos heredan de django.db.models.Model que proporciona una API enriquecida para agregar y filtrar resultados de la base de datos.

Crea tu primer modelo

Creando tu primer modelo

Los modelos normalmente se definen en el archivo models.py en el subdirectorio de su aplicación. El Model la clase de django.db.models módulo es una buena clase de partida para extender sus modelos de. Por ejemplo:

from django.db import models

class Book(models.Model):
    title = models.CharField(max_length=100)
    author = models.ForeignKey('Author', on_delete=models.CASCADE, related_name='authored_books')
    publish_date = models.DateField(null=True, blank=True)

    def __str__(self): # __unicode__ in python 2.*
        return self.title

Cada atributo en un modelo representa una columna en la base de datos.

  • title es un texto con una longitud máxima de 100 caracteres.
  • author es una ForeignKey que representa una relación con otro modelo / tabla, en este caso Author (solo se utiliza con fines de ejemplo). on_delete le dice a la base de datos qué hacer con el objeto en caso de que se elimine el objeto relacionado (un Author ). (Cabe señalar que dado que django 1.9 on_delete puede usarse como el segundo argumento posicional. En django 2 es un argumento obligatorio y es recomendable tratarlo como tal. En versiones anteriores, se usará de forma predeterminada en CASCADE .)
  • publish_date almacena una fecha. Tanto el null como el blank se establecen en True para indicar que no es un campo obligatorio (es decir, puede agregarlo en una fecha posterior o dejarlo vacío).

Junto con los atributos, definimos un método __str__ devuelve el título del libro que se usará como su representación de string cuando sea necesario, en lugar del valor predeterminado.

Aplicando los cambios a la base de datos (Migraciones).

Después de crear un nuevo modelo o modificar modelos existentes, deberá generar migraciones para sus cambios y luego aplicar las migraciones a la base de datos especificada. Esto se puede hacer usando el sistema de migraciones incorporado de Django. Usando la utilidad manage.py cuando manage.py en el directorio raíz del proyecto:

python manage.py makemigrations <appname>

El comando anterior creará los scripts de migración que son necesarios en el subdirectorio de migrations de su aplicación. Si omite el parámetro <appname> , se procesarán todas las aplicaciones definidas en el argumento INSTALLED_APPS de settings.py . Si lo considera necesario, puede editar las migraciones.

Puede verificar qué migraciones son necesarias sin crear realmente la migración, use la opción --dry-run, por ejemplo:

python manage.py makemigrations --dry-run

Para aplicar las migraciones:

python manage.py migrate <appname>

El comando anterior ejecutará los scripts de migración generados en el primer paso y actualizará físicamente la base de datos.

Si se cambia el modelo de la base de datos existente, se necesita el siguiente comando para realizar los cambios necesarios.

python manage.py migrate --run-syncdb

Django creará la tabla con el nombre <appname>_<classname> de forma predeterminada. En algún momento no quieres usarlo. Si desea cambiar el nombre predeterminado, puede anunciar el nombre de la tabla configurando db_table en la clase Meta :

from django.db import models

class YourModel(models.Model):
    parms = models.CharField()
    class Meta:
        db_table = "custom_table_name"

Si desea ver qué código SQL ejecutará una determinada migración, simplemente ejecute este comando:

python manage.py sqlmigrate <app_label> <migration_number>

Django> 1.10
La nueva opción makemigrations --check hace que el comando salga con un estado distinto de cero cuando se detectan cambios en el modelo sin migraciones.

Ver Migraciones para más detalles sobre migraciones.

Creando un modelo con relaciones.

Relación de muchos a uno

from django.db import models

class Author(models.Model):
   name = models.CharField(max_length=50)

#Book has a foreignkey (many to one) relationship with author
class Book(models.Model):
    author = models.ForeignKey(Author, on_delete=models.CASCADE)
    publish_date = models.DateField()

La opción más genérica. Se puede utilizar en cualquier lugar que desee representar una relación

Relación de muchos a muchos

class Topping(models.Model):
    name = models.CharField(max_length=50)

# One pizza can have many toppings and same topping can be on many pizzas
class Pizza(models.Model):
    name = models.CharField(max_length=50)
    toppings = models.ManyToManyField(Topping)

Internamente esto se representa a través de otra tabla. Y ManyToManyField debe colocar en modelos que se ManyToManyField en un formulario. Por ejemplo: la Appointment tendrá un ManyToManyField llamado Customer , Pizza tiene Toppings y así sucesivamente.

Relación de muchos a muchos usando clases directas

class Service(models.Model):
     name = models.CharField(max_length=35)

class Client(models.Model):
    name = models.CharField(max_length=35)
    age = models.IntegerField()
    services = models.ManyToManyField(Service, through='Subscription')

class Subscription(models.Model):
     client = models.ForeignKey(Client)
     service = models.ForeignKey(Service)
     subscription_type = models.CharField(max_length=1, choices=SUBSCRIPTION_TYPES)
     created_at = models.DateTimeField(default=timezone.now)

De esta manera, podemos mantener más metadatos sobre una relación entre dos entidades. Como puede verse, un cliente puede suscribirse a varios servicios a través de varios tipos de suscripción. La única diferencia en este caso es que para agregar nuevas instancias a la relación M2M, no se puede usar el método abreviado pizza.toppings.add(topping) , sino que se debe crear un nuevo objeto de la clase through , Subscription.objects.create(client=client, service=service, subscription_type='p')

En otros idiomas, las through tables también se conocen como JoinColumn , Intersection table o mapping table

Relación uno a uno

class Employee(models.Model):
   name = models.CharField(max_length=50)
   age = models.IntegerField()
   spouse = models.OneToOneField(Spouse)

class Spouse(models.Model):
   name = models.CharField(max_length=50)

Utilice estos campos cuando solo tendrá una relación de composición entre los dos modelos.

Consultas básicas de Django DB

Django ORM es una poderosa abstracción que le permite almacenar y recuperar datos de la base de datos sin tener que escribir consultas SQL por su cuenta.

Asumamos los siguientes modelos:

class Author(models.Model):
   name = models.CharField(max_length=50)

class Book(models.Model): 
   name = models.CharField(max_length=50)
   author = models.ForeignKey(Author)

Suponiendo que haya agregado el código anterior a una aplicación de django y ejecute el comando migrate (para que se cree su base de datos). Inicia el shell Django

python manage.py shell

Esto inicia el shell estándar de Python, pero con las bibliotecas de Django relevantes importadas, para que pueda centrarse directamente en las partes importantes.

Comience importando los modelos que acabamos de definir (supongo que esto se hace en un archivo models.py )

from .models import Book, Author

Ejecute su primera consulta de selección:

>>> Author.objects.all() 
[]
>>> Book.objects.all()
[]

Permite crear un autor y objeto de libro:

>>> hawking = Author(name="Stephen hawking")
>>> hawking.save()
>>> history_of_time = Book(name="history of time", author=hawking)
>>> history_of_time.save()

o use la función crear para crear objetos modelo y guardar en un código de línea

>>> wings_of_fire = Book.objects.create(name="Wings of Fire", author="APJ Abdul Kalam")

Ahora vamos a ejecutar la consulta

>>> Book.objects.all()
[<Book: Book object>]
>>> book = Book.objects.first() #getting the first book object
>>> book.name
u'history of time'

Agreguemos una cláusula where a nuestra consulta de selección

>>> Book.objects.filter(name='nothing')
[]
>>> Author.objects.filter(name__startswith='Ste')
[<Author: Author object>]

Para obtener los detalles sobre el autor de un libro determinado

>>> book = Book.objects.first() #getting the first book object
>>> book.author.name # lookup on related model
u'Stephen hawking'

Para obtener todos los libros publicados por Stephen Hawking (libro de búsqueda por su autor)

>>> hawking.book_set.all()
[<Book: Book object>]

_set es la notación que se usa para "búsquedas inversas", es decir, mientras el campo de búsqueda está en el modelo de Libro, podemos usar book_set en un objeto de autor para obtener todos sus libros.

Una tabla básica no gestionada.

En algún momento del uso de Django, es posible que desee interactuar con tablas que ya se han creado o con vistas de base de datos. En estos casos, no querrá que Django administre las tablas a través de sus migraciones. Para configurar esto, necesita agregar solo una variable a la clase Meta su modelo: managed = False .

Este es un ejemplo de cómo puede crear un modelo no administrado para interactuar con una vista de base de datos:

class Dummy(models.Model):
    something = models.IntegerField()

    class Meta:
       managed = False

Esto se puede asignar a una vista definida en SQL de la siguiente manera.

CREATE VIEW myapp_dummy AS 
SELECT id, something FROM complicated_table 
WHERE some_complicated_condition = True

Una vez que haya creado este modelo, puede usarlo como lo haría con cualquier otro modelo:

>>> Dummy.objects.all()
[<Dummy: Dummy object>, <Dummy: Dummy object>, <Dummy: Dummy object>]
>>> Dummy.objects.filter(something=42)
[<Dummy: Dummy object>]

Modelos avanzados

Un modelo puede proporcionar mucha más información que solo los datos sobre un objeto. Veamos un ejemplo y dividámoslo en lo que es útil para:

from django.db import models
from django.urls import reverse
from django.utils.encoding import python_2_unicode_compatible

@python_2_unicode_compatible
class Book(models.Model):
    slug = models.SlugField()
    title = models.CharField(max_length=128)
    publish_date = models.DateField()

    def get_absolute_url(self):
        return reverse('library:book', kwargs={'pk':self.pk})

    def __str__(self):
        return self.title

    class Meta:
        ordering = ['publish_date', 'title']

Llave primaria automatica

Puede notar el uso de self.pk en el método get_absolute_url . El campo pk es un alias de la clave principal de un modelo. Además, django agregará automáticamente una clave principal si falta. Eso es una cosa menos de la que preocuparse: le permite establecer una clave externa para cualquier modelo y obtenerla fácilmente.

Url absoluta

La primera función que se define es get_absolute_url . De esta manera, si tiene un libro, puede obtener un enlace a él sin tener que manipular la etiqueta url, la resolución, el atributo y similares. Simplemente llame a book.get_absolute_url y obtendrá el enlace correcto. Como beneficio adicional, su objeto en el administrador de django obtendrá un botón "ver en el sitio".

Representación de cuerdas

Tenga un método __str__ que le permita usar el objeto cuando necesite mostrarlo. Por ejemplo, con el método anterior, agregar un enlace al libro en una plantilla es tan simple como <a href="{{ book.get_absolute_url }}">{{ book }}</a> . Directo al grano. Este método también controla lo que se muestra en el menú desplegable de administración, por ejemplo, para clave externa.

El decorador de clase te permite definir el método una vez para __str__ y __unicode__ en python 2 sin causar problemas en python 3. Si esperas que tu aplicación se ejecute en ambas versiones, esa es la manera de hacerlo.

Campo de babosa

El campo slug es similar a un campo char pero acepta menos símbolos. Por defecto, solo letras, números, guiones bajos o guiones. Es útil si desea identificar un objeto con una buena representación, por ejemplo, en url.

La clase meta

La clase Meta nos permite definir mucha más información sobre toda la colección de artículos. Aquí, solo se establece el orden predeterminado. Es útil con el objeto ListView, por ejemplo. Se necesita una lista corta ideal de campos para usar en la clasificación. Aquí, el libro se ordenará primero por fecha de publicación y luego por título si la fecha es la misma.

Otros atributos frecuentes son verbose_name y verbose_name_plural . De forma predeterminada, se generan a partir del nombre del modelo y deben estar bien. Pero la forma plural es ingenua, simplemente anexando una 's' al singular por lo que es posible que desee establecerlo explícitamente en algún caso.

Valores calculados

Una vez que se ha recuperado un objeto modelo, se convierte en una instancia completamente realizada de la clase. Como tal, se puede acceder a cualquier método adicional en formularios y serializadores (como Django Rest Framework).

El uso de propiedades de python es una forma elegante de representar valores adicionales que no se almacenan en la base de datos debido a diversas circunstancias.

def expire():
    return timezone.now() + timezone.timedelta(days=7)

class Coupon(models.Model):
    expiration_date = models.DateField(default=expire)

    @property
    def is_expired(self):
        return timezone.now() > self.expiration_date

Si bien la mayoría de los casos puede complementar los datos con anotaciones en sus consultas, los valores computados como propiedades de modelo son ideales para cálculos que no pueden evaluarse simplemente dentro del alcance de una consulta.

Además, las propiedades, ya que están declaradas en la clase python y no como parte del esquema, no están disponibles para realizar consultas.

Añadiendo una representación de cadena de un modelo.

Para crear una presentación legible por humanos de un objeto modelo, necesita implementar el método Model.__str__() (o Model.__unicode__() en python2). Se llamará a este método siempre que llame a str() en una instancia de su modelo (incluido, por ejemplo, cuando el modelo se utiliza en una plantilla). Aquí hay un ejemplo:

  1. Crear un modelo de libro.

    # your_app/models.py
    
    from django.db import models
    
    class Book(models.Model):
        name = models.CharField(max_length=50)
        author = models.CharField(max_length=50)
    
  2. Cree una instancia del modelo y guárdela en la base de datos:

    >>> himu_book = Book(name='Himu Mama', author='Humayun Ahmed')
    >>> himu_book.save()
    
  3. Ejecute print() en la instancia:

    >>> print(himu_book)
    <Book: Book object>
    

<Libro: Objeto de libro> , el resultado predeterminado, no nos ayuda. Para solucionar esto, vamos a agregar un método __str__ .

from django.utils.encoding import python_2_unicode_compatible

@python_2_unicode_compatible
class Book(models.Model):
    name = models.CharField(max_length=50)
    author = models.CharField(max_length=50)

    def __str__(self):
        return '{} by {}'.format(self.name, self.author)

Tenga en cuenta que el decorador compatible con python_2_unicode_compatible es necesario solo si desea que su código sea compatible con python 2. Este decorador copia el método __str__ para crear un método __unicode__ . Importarlo desde django.utils.encoding .

Ahora si llamamos a la función de impresión la instancia de libro de nuevo:

>>> print(himu_book)
Himu Mama by Humayun Ahmed

¡Mucho mejor!

La representación de la cadena también se usa cuando el modelo se usa en los ModelForm para ForeignKeyField y ManyToManyField .

Modelo mixins

En los mismos casos, diferentes modelos podrían tener los mismos campos y procedimientos en el ciclo de vida del producto. Para manejar estas similitudes sin tener herencia de repetición de código se podría utilizar. En lugar de heredar una clase completa, el patrón de diseño mixin nos ofrece heredar ( o algunos dicen que incluyen ) algunos métodos y atributos. Veamos un ejemplo:

class PostableMixin(models.Model):
    class Meta:
        abstract=True
    
    sender_name = models.CharField(max_length=128)
    sender_address = models.CharField(max_length=255)
    receiver_name = models.CharField(max_length=128)
    receiver_address = models.CharField(max_length=255)
    post_datetime = models.DateTimeField(auto_now_add=True)
    delivery_datetime = models.DateTimeField(null=True)
    notes = models.TextField(max_length=500)

class Envelope(PostableMixin):
    ENVELOPE_COMMERCIAL = 1
    ENVELOPE_BOOKLET = 2
    ENVELOPE_CATALOG = 3

    ENVELOPE_TYPES = (
        (ENVELOPE_COMMERCIAL, 'Commercial'),
        (ENVELOPE_BOOKLET, 'Booklet'),
        (ENVELOPE_CATALOG, 'Catalog'),
    )

    envelope_type = models.PositiveSmallIntegerField(choices=ENVELOPE_TYPES)

class Package(PostableMixin):
    weight = models.DecimalField(max_digits=6, decimal_places=2)
    width = models.DecimalField(max_digits=5, decimal_places=2)
    height = models.DecimalField(max_digits=5, decimal_places=2)
    depth = models.DecimalField(max_digits=5, decimal_places=2)

Para convertir un modelo en una clase abstracta, deberá mencionar abstract=True en su clase Meta interna. Django no crea ninguna tabla para modelos abstractos en la base de datos. Sin embargo, para los modelos Envelope y Package , las tablas correspondientes se crearían en la base de datos.

Además, los campos de algunos métodos de modelo serán necesarios en más de un modelo. Por lo tanto, estos métodos podrían agregarse a mixins para evitar la repetición del código. Por ejemplo, si creamos un método para establecer la fecha de entrega en PostableMixin , será accesible desde sus dos hijos:

class PostableMixin(models.Model):
    class Meta:
        abstract=True

    ...
    ...

    def set_delivery_datetime(self, dt=None):
        if dt is None:
            from django.utils.timezone import now
            dt = now()

        self.delivery_datetime = dt
        self.save()

Este método se puede utilizar como sigue en los niños:

>> envelope = Envelope.objects.get(pk=1)
>> envelope.set_delivery_datetime()

>> pack = Package.objects.get(pk=1)
>> pack.set_delivery_datetime()

UUID clave primaria

Un modelo por defecto utilizará una clave primaria de incremento automático (entero). Esto le dará una secuencia de teclas 1, 2, 3.

Se pueden establecer diferentes tipos de clave primaria en un modelo con pequeñas modificaciones al modelo.

Un UUID es un identificador único universal, este es un identificador aleatorio de 32 caracteres que se puede usar como una identificación. Esta es una buena opción para usar cuando no desea que los ID secuenciales se asignen a los registros en su base de datos. Cuando se usa en PostgreSQL, esto se almacena en un tipo de datos uuid, de lo contrario en un char (32).

import uuid
from django.db import models

class ModelUsingUUID(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)

La clave generada estará en el formato 7778c552-73fc-4bc4-8bf9-5a2f6f7b7f47

Herencia

La herencia entre modelos se puede hacer de dos maneras:

  • una clase abstracta común (ver el ejemplo "Modelo mixins")
  • un modelo común con múltiples tablas

La herencia de tablas múltiples creará una tabla para los campos comunes y una por ejemplo de modelo secundario:

from django.db import models

class Place(models.Model):
    name = models.CharField(max_length=50)
    address = models.CharField(max_length=80)

class Restaurant(Place):
    serves_hot_dogs = models.BooleanField(default=False)
    serves_pizza = models.BooleanField(default=False)

creará 2 tablas, una para Place y otra para Restaurant con un campo OneToOne oculto a Place para los campos comunes.

tenga en cuenta que esto requerirá una consulta adicional a las tablas de lugares cada vez que obtenga un objeto de restaurante.



Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow