Django Tutorial Part 3: Using models

Questo articolo mostra come definire dei modelli per il sito della LocalLibrary. Spiega cos'è un modello, come viene dichiarato e alcuni dei principali tipi di campo. Mostra anche brevemente alcuni dei principali modi in cui è possibile accedere ai dati del modello.

Prerequisiti: Django Tutorial Part 2: Creating a skeleton website.
Obbiettivi: Essere in grado di progettare e creare i propri modelli, scegliendo i campi in modo appropriato.

Panoramica

Le applicazioni web Django accedono e gestiscono i dati tramite oggetti Python denominati modelli. I modelli definiscono la struttura dei dati memorizzati, inclusi i tipi di campo e possibilmente anche la loro dimensione massima,valori predefiniti, opzioni dell'elenco di selezione, testo di aiuto per la documentazione, testo della label per i moduli, ecc. La definizione del modello è indipendente dal database sottostante: è possibile sceglierne uno tra i diversi come parte delle impostazioni del progetto. Una volta scelto il database che si desidera utilizzare, non è necessario interrogarlo direttamente, basta scrivere la struttura del modello e altro codice, e Django gestirà tutto il lavoro sporco di comunicazione con il database.

Questo tutorial mostra come definire e accedere ai modelli per l'esempio del LocalLibrary website.

Progettare i model per la LocalLibrary

Prima di saltare e iniziare a codificare i modelli, vale la pena dedicare alcuni minuti a pensare a quali dati dobbiamo memorizzare e alle relazioni tra i diversi oggetti.

Sappiamo che abbiamo bisogno di memorizzare informazioni sui libri (titolo, sommario, autore, lingua scritta, categoria, ISBN) e che potremmo avere più copie disponibili (con ID unico globale, stato di disponibilità, ecc.). Potremmo aver bisogno di memorizzare più informazioni sugli autori oltre al loro nome e potrebbero esserci più autori con nomi uguali o simili. Vogliamo essere in grado di ordinare le informazioni in base al titolo del libro, autore, lingua scritta e categoria.

Quando si progettano i modelli, è logico disporre di modelli separati per ogni "oggetto" (un gruppo di informazioni correlate). In questo caso gli oggetti ovvi sono i libri, le istanze di libri e gli autori

Potresti anche voler utilizzare i modelli per rappresentare delle opzioni per un elenco di selezione (ad esempio, come un elenco a discesa), piuttosto che codificare le scelte nel sito stesso - questo è consigliato quando tutte le opzioni non sono note in anticipo o potrebbero essere modificate. I candidati ovvi per i modelli in questo caso includono il genere di libro (ad esempio Fantascienza, Poesia francese, ecc.) e la lingua (Inglese, Francese, Giapponese).

Una volta che abbiamo deciso i nostri modelli e i nostri campi, dobbiamo pensare alle relazioni. Django ti permette di definire relazioni che sono uno a uno (OneToOneField), uno a molti (ForeignKey) e molti a molti (ManyToManyField).Con questo in mente, lo schema di associazione UML qui sotto mostra i modelli che definiremo in questo caso (come schede).

LocalLibrary Model UML

Come sopra, abbiamo creato modelli per book (i dettagli generici del libro), per book instance (lo stato di specifiche copie fisiche del libro disponibile nel sistema) e author. Abbiamo anche deciso di avere un modello per il genere (genre), in modo che i valori possano essere creati/selezionati attraverso l'interfaccia di amministrazione. Abbiamo deciso di non avere un modello per BookInstance:status - abbiamo codificato i valori (LOAN_STATUS) perché non ci aspettiamo che questi cambino. All'interno di ciascuna casella è possibile visualizzare il nome del model, i nomi dei campi e i tipi, nonché i metodi e i relativi tipi di ritorno.

Il diagramma mostra anche le relazioni tra i modelli, incluse le loro molteplicità. Le molteplicità sono i numeri sul diagramma che mostrano i numeri (massimo e minimo) di ciascun modello che può essere presente nella relazione. Ad esempio, la linea di collegamento tra le caselle mostra che Book e un Genre sono correlati. I numeri vicino al modello Genre mostrano che un Book deve avere uno o più Genres (quanti ne vuoi), mentre i numeri all'altro capo della riga accanto al model Book mostrano che un Genre può avere zero o molti Books associati.

Nota: La prossima sezione fornisce un manuale di base che spiega come vengono definiti e utilizzati i models. Mentre lo leggi, considera come costruiremo ciascuno dei modelli nel diagramma sopra.

Fondamenti del modello

Questa sezione fornisce una breve panoramica di come viene definito un model e alcuni dei campi e argomenti di campo più importanti.

Definizione del modello

I model vengono generalmente definiti nel file models.py di una applicazione. Sono implementati come sottoclassi di django.db.models.Model, e possono includere campi, metodi e metadati. Il frammento di codice seguente mostra un modello "tipico", denominato MyModelName:

from django.db import models

class MyModelName(models.Model):
    """A typical class defining a model, derived from the Model class."""

    # Fields
    my_field_name = models.CharField(max_length=20, help_text='Enter field documentation')
    ...

    # Metadata
    class Meta: 
        ordering = ['-my_field_name']

    # Methods
    def get_absolute_url(self):
        """Returns the url to access a particular instance of MyModelName."""
        return reverse('model-detail-view', args=[str(self.id)])
    
    def __str__(self):
        """String for representing the MyModelName object (in Admin site etc.)."""
        return self.my_field_name

Nelle sezioni seguenti esploreremo in dettaglio ciascuna funzionalità all'interno del modello:

Campi

Un modello può avere un numero arbitrario di campi, di qualsiasi tipo - ognuno rappresenta una colonna di dati che vogliamo memorizzare in una delle nostre tabelle del database. Ogni record di database (riga) consisterà in uno di ciascun valore di quei campi. Osserviamo l'esempio seguente:

my_field_name = models.CharField(max_length=20, help_text='Enter field documentation')

Il nostro esempio precedente ha un singolo campo chiamato my_field_name, di tipo models.CharField — che significa che questo campo conterrà stringhe di caratteri alfanumerici. I tipi di campo vengono assegnati utilizzando classi specifiche, che determinano il tipo di record utilizzato per memorizzare i dati nel database, insieme ai criteri di convalida da utilizzare quando i valori vengono ricevuti da un form HTML (vale a dire ciò che costituisce un valore valido). I tipi di campo possono anche prendere argomenti che specificano ulteriormente come il campo è memorizzato o può essere utilizzato. In questo caso stiamo dando al nostro campo due argomenti:

  • max_length=20 — Indica che la lunghezza massima di un valore in questo campo è di 20 caratteri.
  • help_text='Enter field documentation' — fornisce un'etichetta di testo da visualizzare per aiutare gli utenti a sapere quale valore fornire quando questo valore deve essere inserito da un utente tramite un form HTML.

Il nome del campo viene utilizzato per fare riferimento ad esso in query e templates. I campi hanno anche un'etichetta, che è specificata come argomento (verbose_name) o dedotto variando in maiuscola la prima lettera del nome della variabile del campo e sostituendo qualsiasi underscore con uno spazio (ad esempio my_field_name avrebbe una etichetta di default My field name).

L'ordine in cui i campi sono dichiarati influenzerà il loro ordine predefinito se un modello viene reso in un modulo (ad esempio nel sito di amministrazione), tuttavia questo ordine può essere sovrascritto.

Argomenti comuni nei campi

I seguenti argomenti comuni possono essere utilizzati per dichiarare molti dei diversi tipi di campo:

  • help_text: Fornisce un'etichetta di testo per i form HTML (ad esempio nel sito di amministrazione), come descritto sopra.
  • verbose_name: Un nome leggibile dall'uomo per il campo utilizzato nelle etichette di campo. Se non specificato, Django dedurrà il nome dettagliato predefinito dal nome del campo.
  • default: Il valore predefinito per il campo. Questo può essere un valore o un oggetto callable, nel qual caso l'oggetto verrà chiamato ogni volta che viene creato un nuovo record.
  • null: Se True, Django memorizzerà i valori bianchi come NULL nel database per i campi dove questo è appropriato (un campo CharField per esempio memorizzerà invece una stringa vuota). Per default è False.
  • blank: Se True, il campo può essere vuoto nelle tue forme. L'impostazione predefinita è False, il che significa che la convalida del modulo di Django ti costringerà a inserire un valore. Spesso usato con null=True , perché se hai intenzione di consentire valori vuoti, vuoi anche che il database sia in grado di rappresentarli in modo appropriato.
  • choices: Un gruppo di scelte per questo campo. Se viene fornito, il widget modulo corrispondente predefinito sarà una casella di selezione con queste scelte al posto del campo di testo standard.
  • primary_key: Se True, imposta il campo corrente come chiave primaria per il modello (una chiave primaria è una colonna di database speciale designata per identificare in modo univoco tutti i diversi record di tabella). Se non viene specificato alcun campo come chiave primaria, Django aggiungerà automaticamente un campo per questo scopo.

Ci sono molte altre opzioni — consultare full list of field options here.

Tipi di campo più comuni

Il seguente elenco descrive alcuni dei tipi di campi più comunemente usati.

  • CharField è usato per definire stringhe di lunghezza fissa di dimensioni medio-piccole. Devi specificare il max_length dei dati memorizzati.
  • TextField viene utilizzato per stringhe di lunghezza arbitraria di grandi dimensioni. Puoi specificare la max_length per il campo, ma questo viene utilizzato solo quando il campo viene visualizzato nei moduli (non viene applicato a livello di database).
  • IntegerField è un campo per la memorizzazione di valori interi (numero intero) e per la convalida di valori immessi come numeri interi nei moduli.
  • DateField e DateTimeField sono utilizzati per storare/rappresentare date e data/time (in Python come oggetti datetime.date e datetime.datetime, rispettivamente). Questi campi possono essere dichiarati con dei parametri (mutualmente esclusivi) auto_now=True (per settare la data odierna automaticamente ogni volta che il modello viene salvato), auto_now_add (per settare la data solo quando il modello viene creato per la prima volta) , e default (per settare una data di default che possa essere sovrascritta dall'utente).
  • EmailField per storare e validare indirizzi mail.
  • FileField e ImageField per uploadare file e immagini rispettivamente (ImageField aggiunge semplicemente ulteriore convalida che il file caricato è un'immagine). Questi hanno parametri per definire come e dove sono memorizzati i file caricati.
  • AutoField tipologia speciale di IntegerField con autoincremento. Una chiave primaria di questo tipo viene automaticamente aggiunta al tuo modello se non ne specifichi esplicitamente una.
  • ForeignKey è usato per specificare una relazione uno-a-molti con un altro modello di database (ad esempio, un'auto ha un produttore, ma un produttore può fare molte automobili). Il lato "uno" della relazione è il modello che contiene la chiave.
  • ManyToManyField è usato per specificare una relazione molti-a-molti (ad esempio un libro può avere diversi generi e ogni genere può contenere diversi libri). Nella nostra app di libreria li useremo in modo molto simile a ForeignKeys, ma possono essere usati in modi più complicati per descrivere le relazioni tra i gruppi. Questi hanno il parametro on_delete per definire cosa succede quando il record associato viene cancellato (ad esempio un valore models.SET_NULL setta il valore a NULL).

Esistono molti altri tipi di campi, compresi i campi per diversi tipi di numeri (interi grandi, interi piccoli, float), booleani, URL, slug, ID univoci e altre informazioni "temporali" (durata, tempo, ecc.) . È possibile visualizzare la full list here.

Metadata

Puoi dichiarare metadata per il tuo Modello utilizzando class Meta, come mostrato sotto.

class Meta:
    ordering = ['-my_field_name']

Una delle funzionalità più utili di questi metadati consiste nel controllare l'ordinamento predefinito dei record restituiti quando si esegue una query sul tipo di modello. A tale scopo, specificare l'ordine di corrispondenza in un elenco di nomi di campi sull'attributo ordering come sopra. L'ordine dipende dal tipo di campo (i campi dei caratteri sono ordinati alfabeticamente, mentre i campi delle date sono ordinati in ordine cronologico). Come mostrato sopra, puoi anteporre il nome del campo al simbolo meno (-) per invertire l'ordine.

Per esempio, se scegliamo un sort dei libri come nell'esempio per default:

ordering = ['title', '-pubdate']

i libri saranno ordinati alfabeticamente per titolo, dalla A alla Z e quindi per data di pubblicazione all'interno di ciascun titolo, dal più recente al più vecchio. Un altro attributo comune è verbose_name, un nome dettagliato per la classe in forma singolare e plurale:

verbose_name = 'BetterName'

Altri attributi utili consentono di creare e applicare nuove "autorizzazioni di accesso" per il modello (le autorizzazioni predefinite vengono applicate automaticamente), consentire l'ordinamento in base a un altro campo o dichiarare che la classe è "astratta" (una classe base per cui non è possibile creare record, e sarà invece derivato da creare altri modelli). Molte altre opzioni di metadati controllano quale database deve essere utilizzato per il modello e come vengono archiviati i dati (questi sono davvero utili solo se è necessario associare un modello a un database esistente).

La lista completa di opzioni per i metadati: Model metadata options (Django docs).

Metodi

Un modello può avere metodi.

In ogni caso, in ogni modello è necessario definire il metodo standard della classe Python __str__() per restituire una stringa leggibile dall'uomo per ciascun oggetto. Questa stringa viene utilizzata per rappresentare singoli record nel sito di amministrazione (e in qualsiasi altro punto è necessario fare riferimento a un'istanza del modello). Spesso questo restituirà un titolo o un campo nome dal modello.

def __str__(self):
    return self.field_name

Un altro metodo comune da includere nei modelli Django è get_absolute_url (), che restituisce un URL per la visualizzazione di record di modelli individuali sul sito Web (se si definisce questo metodo, Django aggiungerà automaticamente un pulsante "Visualizza sul sito" alle schermate di modifica dei record del modello in il sito di amministrazione). Di seguito viene mostrato un tipico pattern per get_absolute_url ().

def get_absolute_url(self):
    """Returns the url to access a particular instance of the model."""
    return reverse('model-detail-view', args=[str(self.id)])

Nota: Supponendo che utilizzerai URLs come /myapplication/mymodelname/2 per visualizzare record individuali per il tuo modello (dove "2" è l'id per un particolare record), dovrai creare un mapper URL per passare la risposta e l'id a una "model detail view" (vista di dettaglio del modello) (che farà il lavoro richiesto per mostrare il record). la funzione reverse() sopra effettua un "reverse" del tuo url mapper (nel caso sopra nominato 'model-detail-view') per creare un URL nel formato corretto.

Ovviamente per fare questo lavoro devi ancora scrivere la mappatura degli URL, la vista e il template!

Puoi anche definire altri metodi che ti piacciono e chiamarli dal tuo codice o template (a condizione che non prendano alcun parametro).

Gestone del modello

Una volta definite le classi model, è possibile utilizzarle per creare, aggiornare o eliminare record e per eseguire query per ottenere tutti i record o particolari sottoinsiemi di record. Ti mostreremo come farlo nel tutorial quando definiremo le nostre views, ma ecco un breve sommario.

Creare e modificare record

Per creare un record puoi definire una istanza del modello e poi richiamare save().

# Create a new record using the model's constructor.
record = MyModelName(my_field_name="Instance #1")

# Save the object into the database.
record.save()

Note: Se non hai dichiarato alcun campo come primary_key, al nuovo record ne verrà assegnato uno automaticamente, con nome del campo id. È possibile interrogare questo campo dopo aver salvato il record precedente, esso dovrebbe avere il valore 1.

È possibile accedere ai campi in questo nuovo record e modificarne i valori utilizzando la sintassi dot (.) e per memorizzare nel database i valori modificati devi chiamare save().

# Access model field values using Python attributes.
print(record.id) # should return 1 for the first record. 
print(record.my_field_name) # should print 'Instance #1'

# Change record by modifying the fields, then calling save().
record.my_field_name = "New Instance Name"
record.save()

Ricercare record

È possibile cercare i record che soddisfano determinati criteri utilizzando l'attributo objects del model (fornito dalla classe base).

Nota: Spiegare come cercare i record usando il modello "astratto" nei nomi dei campi può generare un po 'di confusione. Nella discussione seguente faremo riferimento a un modello Book con campi title e genre, in cui genre è anche lui un modello con un singolo campo name.

Possiamo ottenere tutti i record per un modello come un QuerySet, utilizzando objects.all().  Il QuerySet è un oggetto iterabile, ovvero contiene un numero di oggetti che è possibile scorrere/iterare/ciclare.

all_books = Book.objects.all()

Il metodo filter() di Django ci consente di filtrare il QuerySet restituito per matchare un campo di testo o numerico specificato a un particolare criterio. Ad esempio, per filtrare i libri che contengono "wild" nel titolo e poi contarli, potremmo fare quanto segue.

wild_books = Book.objects.filter(title__contains='wild')
number_wild_books = wild_books.count()

I campi da matchare e il tipo di corrispondenza sono definiti nel nome del parametro del filtro, utilizzando il formato: field_name__match_type (notare il doppio underscore tra title e contains sopra). In alto stiamo filtrando title con una corrispondenza case-sensitive. Esistono molti altri tipi di corrispondenze: icontains (case-insensitive), iexact (corrispondenza esatta case-insensitive), exact (corrispondenza esatta case-sensitive) e in, gt (grater than), startswith, ecc. Consultare la lista completa qui.

In alcuni casi sarà necessario filtrare su un campo che definisce una relazione uno-a-molti con un altro modello (per esempio una ForeignKey). In questo caso è possibile "indicizzare" i campi all'interno del modello correlato con un doppio underscore aggiuntivo. Quindi, ad esempio, per filtrare i libri con uno specifico pattern genre, dovrai indicizzare al name attraverso il campo genre, come mostrato sotto:

# Will match on: Fiction, Science fiction, non-fiction etc.
books_containing_genre = Book.objects.filter(genre__name__icontains='fiction')

Nota: Puoi usare gli underscores (__) per navigare su tutti i livelli di relazione che ti servono (ForeignKey/ManyToManyField). Per esempio, un Book che aveva diversi tipi, definiti utilizzando un'ulteriore relazione "cover" potrebbe avere un nome di parametro: type__cover__name__exact='hard'.

C'è molto di più che puoi fare con le query, comprese le ricerche all'indietro dai modelli correlati, concatenare i filtri, restituire un insieme più piccolo di valori, ecc. Per ulteriori informazioni, vedere Making queries (Django Docs).

Definire i Models della LocalLibrary

In questa sezione inizieremo a definire i modelli per la libreria. Apri models.py (in /locallibrary/catalog/). Le righe di codice iniziali importano il modulo models, che contiene la classe di base models.Model da cui i nostri modelli erediteranno.

from django.db import models

# Create your models here.

Modello Genre

Copia il codice del modello Genre mostrato sotto e incollalo alla fine del file models.py. Questo modello viene utilizzato per memorizzare informazioni sulla categoria di libri, ad esempio se si tratta di narrativa o saggistica, storia romantica o militare, ecc. Come menzionato sopra, abbiamo creato il Genre come model piuttosto che come testo libero o elenco di selezione in modo che i possibili valori possano essere gestiti tramite il database anziché essere hard-coded.

class Genre(models.Model):
    """Model representing a book genre."""
    name = models.CharField(max_length=200, help_text='Enter a book genre (e.g. Science Fiction)')
    
    def __str__(self):
        """String for representing the Model object."""
        return self.name

Il modello ha un singolo campo CharField (name), che descrive il genere (limitato a 200 caratteri e con un help_text. Alla fine del modello definiamo un metodo __str__(), che restituisce semplicemente il nome del genere definito da un particolare record. Nessun nome dettagliato (verbose) è stato definito, quindi il campo nel form verrà chiamato Name.

Modello Book

Copia il modello Book in basso e incollalo nuovamente nella parte inferiore del file. Il modello del libro rappresenta tutte le informazioni su un libro disponibile in senso generale, ma non una particolare "istanza" fisica o "copia" disponibile per il prestito. Il modello usa un campo CharField per rappresentare titleisbn del libro (notare come isbn specifica la sua etichetta come "ISBN" utilizzando il primo parametro senza nome, in caso contrario la label di default sarebbe "Isbn"). Il modello usa TextField per il summary, perchè potrebbe essere un campo abbastanza lungo.

from django.urls import reverse # Used to generate URLs by reversing the URL patterns

class Book(models.Model):
    """Model representing a book (but not a specific copy of a book)."""
    title = models.CharField(max_length=200)

    # Foreign Key used because book can only have one author, but authors can have multiple books
    # Author as a string rather than object because it hasn't been declared yet in the file
    author = models.ForeignKey('Author', on_delete=models.SET_NULL, null=True)
    
    summary = models.TextField(max_length=1000, help_text='Enter a brief description of the book')
    isbn = models.CharField('ISBN', max_length=13, help_text='13 Character <a href="https://www.isbn-international.org/content/what-isbn">ISBN number</a>')
    
    # ManyToManyField used because genre can contain many books. Books can cover many genres.
    # Genre class has already been defined so we can specify the object above.
    genre = models.ManyToManyField(Genre, help_text='Select a genre for this book')
    
    def __str__(self):
        """String for representing the Model object."""
        return self.title
    
    def get_absolute_url(self):
        """Returns the url to access a detail record for this book."""
        return reverse('book-detail', args=[str(self.id)])

Genre è un campo ManyToManyField, in modo che un libro possa avere più generi e un genere possa avere molti libri. L'autore è dichiarato come ForeignKey, quindi ogni libro avrà un solo autore, ma un autore può avere molti libri (in pratica un libro potrebbe avere più autori, ma non in questa implementazione semplificata!)

In entrambi i tipi di campo, la classe del modello correlata viene dichiarata come il primo parametro senza nome utilizzando la classe del modello o una stringa contenente il nome del modello correlato. È necessario utilizzare il nome del modello come stringa se la classe associata non è stata ancora definita in questo file prima che venga referenziata! Gli altri parametri di interesse nel campo author sono null=True, che consente al database di memorizzare un valore Null se nessun autore viene selezionato e on_delete=models.SET_NULL, che imposterà il valore dell'autore su Null se l'autore associato al record viene cancellato.

Inoltre il modello definisce __str__() , utilizzando il titolo del libro title per rappresentare un record di Book. L'ultimo metodo, get_absolute_url() ritorna un URL che può essere usato per accedere a un record di dettaglio per questo modello (per farlo funzionare dovremo definire una mappatura URL che abbia il nome book-detail, e una view e un template associati).

Modello BookInstance

Copia il modello BookInstance sotto gli altri modelli. BookInstance rappresenta una copia specifica di un libro che potrebbe essere presa in prestito da qualcuno e include informazioni sul fatto che la copia sia disponibile o sulla data in cui è prevista la restituzione, o dettagli sulla versione e un ID univoco per il libro nella biblioteca.

Alcuni metodi e campi suoneranno familiari. Il modello utilizza

  • ForeignKey per identificare il Book (ogni book ha possibilità di avere molte copie, ma una copia può avere un solo Book).
  • CharField per rappresentare l'edizione del libro.
import uuid # Required for unique book instances

class BookInstance(models.Model):
    """Model representing a specific copy of a book (i.e. that can be borrowed from the library)."""
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, help_text='Unique ID for this particular book across whole library')
    book = models.ForeignKey('Book', on_delete=models.SET_NULL, null=True) 
    imprint = models.CharField(max_length=200)
    due_back = models.DateField(null=True, blank=True)

    LOAN_STATUS = (
        ('m', 'Maintenance'),
        ('o', 'On loan'),
        ('a', 'Available'),
        ('r', 'Reserved'),
    )

    status = models.CharField(
        max_length=1,
        choices=LOAN_STATUS,
        blank=True,
        default='m',
        help_text='Book availability',
    )

    class Meta:
        ordering = ['due_back']

    def __str__(self):
        """String for representing the Model object."""
        return f'{self.id} ({self.book.title})'

Dichiaramo una ulteriore serie di nuovi campi di altri tipi:

  • UUIDField usato per l'id per impostarlo come primary_key per questo modello. Questo tipo di campo alloca un valore globalmente univoco per ogni istanza (una per ogni libro che è possibile trovare nella biblioteca).
  • DateField usato per la data due_back (data in cui il libro dovrebbe ritornare disponibile dopo essere stato in prestito o in manutenzione). Questo valore può essere blanknull (necessario per quando il libro è disponibile). Il metadato del modello (Class Meta) utilizza questo campo per ordinare i record quando vengono restituiti da una query.
  • status è un CharField che definisce una scelta/lista di selezione. Come puoi vedere, definiamo una tupla contenente tuple di coppie chiave-valore (LOAN_STATUS) e la passiamo all'argomento di choices. Il valore in una coppia chiave/valore è un valore di visualizzazione che un utente può selezionare, mentre le chiavi sono i valori che vengono effettivamente salvati se l'opzione è selezionata. Abbiamo anche impostato un valore predefinito di "m" (manutenzione) poiché i libri inizialmente non saranno disponibili prima di essere immagazzinati sugli scaffali.

__str__() rappresenta l'oggetto BookInstance usando una combinazione del suo id univoco e del titolo del libro.

Nota: un po' di Python:

  • A partire da Python 3.6, puoi utilizzare la sintassi di interpolazione delle stringhe (anche nota come f-strings): f'{self.id} ({self.book.title})'.
  • in altre versioni di questo tutorial, più vecchie, usavamo una stringa formattata (formatted string), che è un altro modo valido di formattare le stringhe in Python (esempio: '{0} ({1})'.format(self.id,self.book.title)).

Modello Autore

Copia il modello Author (che trovi qui sotto) dopo il codice esistente in models.py.

class Author(models.Model):
    """Model representing an author."""
    first_name = models.CharField(max_length=100)
    last_name = models.CharField(max_length=100)
    date_of_birth = models.DateField(null=True, blank=True)
    date_of_death = models.DateField('Died', null=True, blank=True)

    class Meta:
        ordering = ['last_name', 'first_name']
    
    def get_absolute_url(self):
        """Returns the url to access a particular author instance."""
        return reverse('author-detail', args=[str(self.id)])

    def __str__(self):
        """String for representing the Model object."""
        return f'{self.last_name}, {self.first_name}'

Tutti i campi/metodi dovrebbero ora essere familiari. Il modello definisce un autore avente un nome, un cognome, una data di nascita e la data di morte (entrambe opzionali). Esso specifica che per impostazione predefinita __str__() restituisca il nome nell'ordine cognome nome. Il metodo get_absolute_url() inverte il mapping degli URL di author-detail per ottenere l'URL per la visualizzazione di un singolo autore.

Rieseguire le migrazioni del database

Tutti i modelli sono stati creati. Rilanciamo la migrazione del database per aggiungerli effettivamente al database.

python3 manage.py makemigrations
python3 manage.py migrate

Modello del linguaggio — Sfida

Immagina che un benefattore locale doni un certo numero di nuovi libri scritti in un'altra lingua (diciamo, Farsi). La sfida è capire come questi sarebbero meglio rappresentati nel nostro sito web della biblioteca e poi aggiungerli ai model.

Alcune considerazioni:

  • "Language" dovrebbe essere associato con Book, BookInstance, o altri objects?
  • I diversi linguaggi dovrebbero essere rappresentati utilizzando un model, una casella di testo o una lista codificata a mano?

Dopo aver deciso, aggiungi il campo. Puoi vedere cosa abbiamo deciso su Github here.

Non dimenticare di rieffettuare le migrazioni dopo ogni cambiamento al tuo modello.

python3 manage.py makemigrations
python3 manage.py migrate

Sommario

In questo articolo abbiamo appreso come sono definiti i modelli, quindi abbiamo utilizzato queste informazioni per progettare e implementare modelli appropriati per il sito Web LocalLibrary.

A questo punto ci allontaneremo brevemente dalla creazione del sito e controlleremo il sito di amministrazione di Django. Questo sito ci permetterà di aggiungere alcuni dati alla biblioteca, che possiamo quindi visualizzare usando le nostre view e template (ancora da creare).

Consulta anche

In questo modulo