5. Models erstellen¶
“A model is the single, definitive source of information about your data. It contains the essential fields and behaviors of the data you’re storing. Generally, each model maps to a single database table.”
Der nächste Schritt ist das Erstellen der Datenstrukturen mit Hilfe der Models.
Models definieren, wie Daten gespeichert werden. Üblicherweise repräsentiert ein Model eine Tabelle in der Datenbank und besteht aus Feldern, Metadaten und Methoden. Durch diese Informationen kann Django automatisch eine Schnittstelle zur Datenbank generieren, die es erlaubt, objektorientiert auf diese zuzugreifen. Man spricht hierbei auch von Object-Relational-Mapping (ORM).
Bei django-marcador werden zwei Models benötigt. Diese werden im oben stehenden Diagramm dargestellt. Bookmark
repräsentiert die eigentlichen Lesezeichen und enthält dementsprechend Felder für URL, Titel und Beschreibung. Darüber hinaus werden Daten über den Ersteller, die Sichtbarkeit und Zeitstempel gespeichert. Diese Daten werden später vor allem zum Filtern der Einträge verwendet. Ein weiteres Model Tag
repräsentiert Schlagwörter, die einem Lesezeichen zugewiesen werden können und dem leichteren Auffinden dienen. Zwischen Bookmark
und Tag
besteht eine m:n Beziehung (Many-to-many) für die Django automatisch eine Zwischentabelle erstellt.
Damit Django eine Klasse als Model erkennt, muss diese von django.db.models.Model
erben und in der Datei models.py
stehen, die sich im Verzeichnisses einer App (hier mysite/marcador/
) befindet.
5.1. Felder¶
Felder werden als Klassenattribute definiert und entsprechen den Spalten einer Tabelle. Django bietet verschiedene Typen von Feldern, um die Daten in einem möglichst sinnvollen Format abzulegen. So entspricht beispielsweise CharField
einer Spalte vom Typ VARCHAR
in einer SQL-Datenbank. Eine Liste der Feldtypen kannst du in der Django-Dokumentation finden.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | # encoding: utf-8
from django.contrib.auth.models import User
from django.db import models
class Tag(models.Model):
name = models.CharField(max_length=50, unique=True)
class Bookmark(models.Model):
url = models.URLField()
title = models.CharField('title', max_length=255)
description = models.TextField('description', blank=True)
is_public = models.BooleanField('public', default=True)
date_created = models.DateTimeField('date created')
date_updated = models.DateTimeField('date updated')
owner = models.ForeignKey(User, verbose_name='owner',
related_name='bookmarks')
tags = models.ManyToManyField(Tag, blank=True)
|
5.2. Metadaten¶
Models können Metadaten enthalten, welche die Darstellung oder das Verhalten beeinflussen. Sie werden in der internen Klasse Meta
definiert. Im Beispiel werden der Name für die Darstellung (singular und plural) sowie die Standardsortierung festgelegt.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | # encoding: utf-8
from django.contrib.auth.models import User
from django.db import models
class Tag(models.Model):
name = models.CharField(max_length=50, unique=True)
class Meta:
verbose_name = 'tag'
verbose_name_plural = 'tags'
ordering = ['name']
class Bookmark(models.Model):
url = models.URLField()
title = models.CharField('title', max_length=255)
description = models.TextField('description', blank=True)
is_public = models.BooleanField('public', default=True)
date_created = models.DateTimeField('date created')
date_updated = models.DateTimeField('date updated')
owner = models.ForeignKey(User, verbose_name='owner',
related_name='bookmarks')
tags = models.ManyToManyField(Tag, blank=True)
class Meta:
verbose_name = 'bookmark'
verbose_name_plural = 'bookmarks'
ordering = ['-date_created']
|
5.3. Methoden¶
You can now add Model functionality Methods for actions that apply to a single
record. For instance, it is usual to create a human readable form of the
record with the method __str__
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | # encoding: utf-8
from django.contrib.auth.models import User
from django.db import models
from django.utils.encoding import python_2_unicode_compatible
from django.utils.timezone import now
@python_2_unicode_compatible
class Tag(models.Model):
name = models.CharField(max_length=50, unique=True)
class Meta:
verbose_name = 'tag'
verbose_name_plural = 'tags'
ordering = ['name']
def __str__(self):
return self.name
@python_2_unicode_compatible
class Bookmark(models.Model):
url = models.URLField()
title = models.CharField('title', max_length=255)
description = models.TextField('description', blank=True)
is_public = models.BooleanField('public', default=True)
date_created = models.DateTimeField('date created')
date_updated = models.DateTimeField('date updated')
owner = models.ForeignKey(User, verbose_name='owner',
related_name='bookmarks')
tags = models.ManyToManyField(Tag, blank=True)
class Meta:
verbose_name = 'bookmark'
verbose_name_plural = 'bookmarks'
ordering = ['-date_created']
def __str__(self):
return '%s (%s)' % (self.title, self.url)
def save(self, *args, **kwargs):
if not self.id:
self.date_created = now()
self.date_updated = now()
super(Bookmark, self).save(*args, **kwargs)
|
Beim Bookmark-Model wird außerdem die Methode save()
überschrieben, um beim Speichern automatisch das richtige Erstellungs- bzw. Änderungsdatum zu setzen. Der Zustand des Felds id
wird benutzt, um zu entscheiden, ob diese Model Instanz schon einmal gespeichert wurde oder nicht. Das Feld id
existiert an jedem Model, denn wenn es nicht explizit deklariert wird erzeugt es Django automatisch. Es ist der Primärschlüssel des Models (damit kann jeder Datensatz eindeutig identifiziert werden). Existiert dieser nicht, wurde das Model noch nie gespeichert. Die Funktion super()
ruft zuletzt die Methode save()
an der Klasse auf, von der unsere Klasse geerbt hat.
Bemerkung
Marcador unterstützt Python 2 und 3. Dies wird durch die Verwendung des Dekorators @python_2_unicode_compatible
und von __str__
anstelle von __unicode__
erreicht, dass du in älteren Versionen der Dokumentation finden wirst.
5.4. Manager¶
Für jedes Model existiert ein Manager, über den die Abfragen (Queries) erfolgen. Sofern nicht anders festgelegt, wird er über das Attribut objects
der Model-Klasse angesprochen. Durch das Überschreiben oder Hinzufügen eines Managers können die Abfragen beeinflusst werden.
Die Django-Dokumentation beschreibt die Verwendung von Managern wie folgt:
“To retrieve objects from your database, construct a
QuerySet
via aManager
on your model class.A
QuerySet
represents a collection of objects from your database. It can have zero, one or many filters – criteria that narrow down the collection based on given parameters. In SQL terms, aQuerySet
equates to aSELECT
statement, and a filter is a limiting clause such asWHERE
orLIMIT
.”
Most of the QuerySet
methods return a new QuerySet
so you can combine
multiple of them. To access the items in a QuerySet
you can loop over it or
simply use the item’s index. For example the following Python code returns the
first item of a QuerySet
which contains all public bookmarks ordered by
their title:
>>> Bookmark.objects.filter(is_public=True).order_by('title')[0]
The SQL query executed against the database for the Python code above looks like this:
SELECT "marcador_bookmark"."id",
"marcador_bookmark"."url",
"marcador_bookmark"."title",
"marcador_bookmark"."description",
"marcador_bookmark"."is_public",
"marcador_bookmark"."date_created",
"marcador_bookmark"."date_updated",
"marcador_bookmark"."owner_id"
FROM "marcador_bookmark"
WHERE "marcador_bookmark"."is_public" = True
ORDER BY "marcador_bookmark"."title" ASC LIMIT 1
Eine Übersicht aller QuerySet
-Methoden ist der Dokumentation zu entnehmen.
In unserem Beispiel werden wir oft nur öffentliche Lesezeichen anzeigen, daher wird dem Model Bookmark
ein weiterer Manager hinzugefügt, der nur die öffentlichen Lesezeichen zurück gibt. Er wird über das Attribut public
referenziert. Damit der Default-Manager bestehen bleibt, muss er noch einmal explizit dem Attribut objects
zugewiesen werden.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | class PublicBookmarkManager(models.Manager):
def get_queryset(self):
qs = super(PublicBookmarkManager, self).get_queryset()
return qs.filter(is_public=True)
@python_2_unicode_compatible
class Bookmark(models.Model):
url = models.URLField()
title = models.CharField('title', max_length=255)
description = models.TextField('description', blank=True)
is_public = models.BooleanField('public', default=True)
date_created = models.DateTimeField('date created')
date_updated = models.DateTimeField('date updated')
owner = models.ForeignKey(User, verbose_name='owner',
related_name='bookmarks')
tags = models.ManyToManyField(Tag, blank=True)
objects = models.Manager()
public = PublicBookmarkManager()
class Meta:
verbose_name = 'bookmark'
verbose_name_plural = 'bookmarks'
ordering = ['-date_created']
def __str__(self):
return '%s (%s)' % (self.title, self.url)
def save(self, *args, **kwargs):
if not self.id:
self.date_created = now()
self.date_updated = now()
super(Bookmark, self).save(*args, **kwargs)
|
5.5. The complete file¶
Am Schluss sieht die vollständige Datei models.py
wie folgt aus:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | # encoding: utf-8
from django.contrib.auth.models import User
from django.db import models
from django.utils.encoding import python_2_unicode_compatible
from django.utils.timezone import now
@python_2_unicode_compatible
class Tag(models.Model):
name = models.CharField(max_length=50, unique=True)
class Meta:
verbose_name = 'tag'
verbose_name_plural = 'tags'
ordering = ['name']
def __str__(self):
return self.name
class PublicBookmarkManager(models.Manager):
def get_queryset(self):
qs = super(PublicBookmarkManager, self).get_queryset()
return qs.filter(is_public=True)
@python_2_unicode_compatible
class Bookmark(models.Model):
url = models.URLField()
title = models.CharField('title', max_length=255)
description = models.TextField('description', blank=True)
is_public = models.BooleanField('public', default=True)
date_created = models.DateTimeField('date created')
date_updated = models.DateTimeField('date updated')
owner = models.ForeignKey(User, verbose_name='owner',
related_name='bookmarks')
tags = models.ManyToManyField(Tag, blank=True)
objects = models.Manager()
public = PublicBookmarkManager()
class Meta:
verbose_name = 'bookmark'
verbose_name_plural = 'bookmarks'
ordering = ['-date_created']
def __str__(self):
return '%s (%s)' % (self.title, self.url)
def save(self, *args, **kwargs):
if not self.id:
self.date_created = now()
self.date_updated = now()
super(Bookmark, self).save(*args, **kwargs)
|