Sortierung gehört auch dazu.
Bei Anwendungen mit zig Apps und hunderten von Models ist es nicht sinnvoll jedes Model anzufassen und denen immer wieder die gleichen Attribute wie "created", "updated" bzw. "sorting" einzutragen. Abgesehen davon verstößt man da gegen das DRY-Prinzip und man macht sich unnötig viel Arbeit, spätestens wenn weitere Attribute hinzukommen, gelöscht oder umbenannt werden.
In den 5 Jahren (2007) Django Entwicklung habe ich einige Strategien untersucht und eine hat sich als am praxistauglichsten herausgestellt, Abstrakte-Klassen.
Dabei ist django sehr freundlich was das Ableiten von abstrakte-Klassen angeht, es verhält sich exakt so wie man es von eine objekt-orientierte-sprache erwartet und überträgt dieser durch den ORM in die Datenbank.
Hier die Klassen.
Die Klasse "DjObject" ist unsere Basis, sie besitzt die Attribute, hidden (falls ein Datensatz nur als unsichtbar markiert werden soll), deleted (wenn ein Datensatz gelöscht wird - "Mülltonne", es ist noch da wird aber nirgends angezeigt).
Da kommt der DjObjectManager ins Spiel, solange man den Manager über XX.objects.visible() aufruft werden nur nicht gelöschte Datensätze gefiltert und das für ALLE Klassen die von DjObject ableiten - ist das nicht cool?.
Jetzt gehen wir ein Schritt weiter und fügen die Klasse "Sortable" hinzu, diese hat nur das Attribut "sorting", gleichzeitig hat es auch alle Attribute und Funktionen von DjObject.
Damit das Sorting automatisch für alle abgeleiteten Klassen hochzählt müssen wir die Save-Funktion erweitern.
Beim Sortieren hilft uns Django wieder aus, mit der Meta-Klasse kann der django-default-manager angewiesen werden nach dem Attribut "sorting" zu sortieren.
from django.db import models
class DjObjectManager(models.Manager):
def visible(self):
return self.filter(hidden = False, deleted = False)
class DjObject(models.Model):
hidden = models.BooleanField( default = False )
deleted = models.BooleanField (default = False )
created = models.DateTimeField(auto_now_add = True )
updated = models.DateTimeField( auto_now = True )
objects = DjObjectManager()
def hide(self):
self.hidden = True
self.save()
def show(self):
self.hidden = False
self.save()
def remove(self):
self.hidden = True
self.deleted = True
self.save()
class Meta:
abstract = True
class Sortable(DjObject):
sorting = models.IntegerField( blank = True, null = True )
sorting_increment = 10
def save(self, *args, **kwargs):
self.sorting = self.__class__.objects.count() + self.sorting_increment
super(Sortable, self).save(*args, **kwargs)
class Meta:
ordering = ("sorting", )
abstract = True
Jetzt leiten wir mal eine konkrete Klasse von den Abtraktenklassen ab.
class Country(Sortable):
name = models.CharField(max_length=255)
def __unicode__(self):
return self.name
class Address(DjObject):
name = models.CharField(max_length = 255)
descrription = models.TextField(blank = True, null = True)
def __unicode__(self):
return self.name
Der django-orm-Mapper löst die Klasse so auf
Die Attribute der Abtrakten-Klassen werden auf die Konkrete Klasse übertragen, in diesem Falle sind es die Attribute von DjObject und Sortable, zuletzt werden die Klassen-attribute hinzugefügt, in diesem Falle "name".
CREATE TABLE app_country
(
id serial NOT NULL,
hidden boolean NOT NULL,
deleted boolean NOT NULL,
created timestamp with time zone NOT NULL,
modified timestamp with time zone NOT NULL,
sorting integer,
name character varying(255) NOT NULL,
CONSTRAINT app_country_pkey PRIMARY KEY (id )
)
CREATE TABLE app_address
(
id serial NOT NULL,
hidden boolean NOT NULL,
deleted boolean NOT NULL,
created timestamp with time zone NOT NULL,
modified timestamp with time zone NOT NULL,
name character varying(255),
description text
)
Jetzt können wir auch auf die Funktionen der Abstrakte-klassen zugreifen:
Company.objects.all() # django-default-manager
Company.objects.visible() # djobject-manager
company = Company.objects.create(name="XXX") # aufruf von save - zaehlt sorting hoch
company.hide() # das Objekt unsichtbar machen
company.show() # object wieder sichtbar machen
company.remove() # als geloescht markieren
Hiermit kommt man schon ziemlich weit, es gibt noch komplexere Anwendungsfälle die komplexere Strukturen benötigen, das hier reicht für 99% der Anwendungen aus.
dann viel spaß beim Testen
und gerne könnt ihr mir einen Kommentar hinerlassen.
Keine Kommentare:
Kommentar veröffentlichen