2017-10-12 1 views
0

Parfois, nous sauvegardons certains champs qui changent beaucoup à Redis ou d'autres backends.Comment faire un attribut automatique non-base de données à une instance de modèle Django

Mais de cette façon, nous pourrions perdre la commodité d'obtenir une valeur d'une instance par article.count.

Nous définissons généralement une fonction de propriété à un modèle, qui effectue la logique d'interrogation de la base de données basée sur la mémoire.

class WhatEver(models.Model): 
    @property 
    def some_field(self): 
     return redis.hget('what-ever-%s' % self.id) 

    def set_some_field(self, value): 
     return redis.hset('what-ever-%s' % self.id, value) 

Laide, mais utile. Mais, cela ne marche pas tout le temps, car c'est une manière intrusive de nous apporter la capacité.

Dites, nous voulons obtenir un visites de l'utilisateur,

Nous voulons vraiment appeler user.visits,

Mais ce n'est pas bon pour un sous-module pour remplacer le module de base, donc nous ne pouvons l'envelopper comme fonction get_user_visits(user) et encore, pas élégant.

Avons-nous un moyen de faire ce genre de trucs automatiquement et de manière non intrusive?

Répondre

0

Enfin, aucune solution existante ne pourrait résoudre mes besoins.

J'ai mis et ouvert le code source: django-in-memory-models

Il peut être installé par pip install django-in-memory-models

1

Pour définir la valeur, vous devez le faire au niveau de l'instance. Donc, soit en créant une méthode personnalisée dans le modèle, soit en utilisant judicieusement les signaux, vous pouvez le faire.

Pour extraire les résultats, vous pouvez décorer le résultat du modèle à l'aide d'un gestionnaire personnalisé et d'un custom method on the manager.

from django.db import models 

class RedisManager(models.Manager): 
    def visits(self): 
     results = [] 
     for obj in self.model.get_query_set().all(): 
      obj.visits = redis.hget('what-ever-%s' % obj.id) 
      results.append(obj) 
     return results 

class SomeModelNeedsVisits(models.Model): 
    objects = RedisManager() 
    # your normal fields here 

for obj in SomeModelNeedsVisits.objects.visits(): 
     print(obj.visits) 
+0

Merci pour votre réponse. Existe-t-il un moyen d'utiliser le mécanisme ORM de Django, mais pas de «remplacer» ou de «corriger le singe» des modules? Serait-il préférable de "simuler" un modèle? – Cai

+0

Ce que je vous ai décrit n'est ni l'écrasement ni le patch de singe. C'est la manière décrite dans la documentation d'enrichir l'ORM avec des fonctionnalités personnalisées. –

+0

Oui, c'est. Mais il doit changer les 'objets 'assignés dans la classe Model? Comme je le sais, il n'est pas capable d'appeler à partir d'une instance comme 'instance.visits', à moins d'écraser ou de corriger le module original. – Cai