Lavoro su una grande applicazione Django che usa CouchDB come database e couchdbkit per mappare i documenti CouchDB in oggetti in Python, in modo simile all'ORM predefinito di Django. Ha dozzine di classi modello e cento o due visualizzazioni CouchDB.
L'applicazione consente agli utenti di registrare un "dominio", che fornisce loro un URL univoco contenente il nome di dominio che consente loro l'accesso a un progetto i cui dati non si sovrappongono ai dati di altri domini. Ogni documento che fa parte di un dominio ha la sua proprietà domain
impostata sul nome di quel dominio.
Per quanto riguarda le relazioni tra i documenti, tutti i domini sono effettivamente sottoinsiemi mutuamente esclusivi dei dati, ad eccezione di alcuni casi limite (alcuni utenti possono essere membri di più di un dominio, e ci sono alcuni rapporti amministrativi che includono tutti domini, ecc.).
Il codice è pieno di riferimenti espliciti al nome di dominio, e mi chiedo se valga la pena aggiungere la complessità per estrapolarlo. Mi piacerebbe anche sapere se c'è un nome per il tipo di approccio legato alle proprietà che sto prendendo qui.
Fondamentalmente, ho in mente qualcosa di simile:
Prima
in models.py
class User(Document):
domain = StringProperty()
class Group(Document):
domain = StringProperty()
name = StringProperty()
user_ids = StringListProperty()
# method that returns related document set
def users(self):
return [User.get(id) for id in self.user_ids]
# method that queries a couch view optimized for a specific lookup
@classmethod
def by_name(cls, domain, name):
# the view method is provided by couchdbkit and handles
# wrapping json CouchDB results as Python objects, and
# can take various parameters modifying behavior
return cls.view('groups/by_name', key=[domain, name])
# method that creates a related document
def get_new_user(self):
user = User(domain=self.domain)
user.save()
self.user_ids.append(user._id)
return user
in views.py:
from models import User, Group
# there are tons of views like this, (request, domain, ...)
def create_new_user_in_group(request, domain, group_name):
group = Group.by_name(domain, group_name)[0]
user = User(domain=domain)
user.save()
group.user_ids.append(user._id)
group.save()
in group / by_name / map.js:
function (doc) {
if (doc.doc_type == "Group") {
emit([doc.domain, doc.name], null);
}
}
Dopo
models.py
class DomainDocument(Document):
domain = StringProperty()
@classmethod
def domain_view(cls, *args, **kwargs):
kwargs['key'] = [cls.domain.default] + kwargs['key']
return super(DomainDocument, cls).view(*args, **kwargs)
@classmethod
def get(cls, *args, **kwargs, validate_domain=True):
ret = super(DomainDocument, cls).get(*args, **kwargs)
if validate_domain and ret.domain != cls.domain.default:
raise Exception()
return ret
def models(self):
# a mapping of all models in the application. accessing one returns the equivalent of
class BoundUser(User):
domain = StringProperty(default=self.domain)
class User(DomainDocument):
pass
class Group(DomainDocument):
name = StringProperty()
user_ids = StringListProperty()
def users(self):
return [self.models.User.get(id) for id in self.user_ids]
@classmethod
def by_name(cls, name):
return cls.domain_view('groups/by_name', key=[name])
def get_new_user(self):
user = self.models.User()
user.save()
views.py
@domain_view # decorator that sets request.models to the same sort of object that is returned by DomainDocument.models and removes the domain argument from the URL router
def create_new_user_in_group(request, group_name):
group = request.models.Group.by_name(group_name)
user = request.models.User()
user.save()
group.user_ids.append(user._id)
group.save()
(Potrebbe essere meglio lasciare qui l'astrazione che perde qui per evitare di dover gestire uno // stile! couchapp di un wrapper per emettere che antepone doc.domain alla chiave o qualche altra soluzione simile.)
function (doc) {
if (doc.doc_type == "Group") {
emit([doc.name], null);
}
}
Pro e contro
Quindi quali sono i pro e i contro di questo?
Pro:
- asciugatrice
- ti impedisce di creare documenti correlati dimenticando di impostare il dominio.
- ti impedisce di scrivere accidentalmente una vista di django - > percorso di esecuzione della visualizzazione del divano che porta a una violazione della sicurezza
- non ti impedisce di accedere al sottostante self.domain e al normale metodo Document.view ()
- potenzialmente elimina la necessità di un sacco di controlli di integrità verificando se due documenti i cui domini ci aspettiamo siano uguali.
Contro:
- aggiunge una certa complessità
- nasconde ciò che sta realmente accadendo
- non richiede che i moduli del modello abbiano classi con lo stesso nome o che tu debba aggiungere attributi secondari a self.models per i moduli. Tuttavia, richiedere i nomi di classe univoci a livello di progetto per i modelli dovrebbe andare bene perché corrispondono alla proprietà doc_type che usa couchdbkit per decidere quale classe istanziarli come, che dovrebbe essere unica.
- rimuove la documentazione di dipendenza esplicita (dal gruppo di importazione group.models)