2010-11-11 3 views
4

J'ai deux modèles permet de dire:Stockage de l'historique des modifications d'un modèle de django dans un autre modèle personnalisé

class superfields(Model): 
    fieldA = models.FloatField() 
    fieldB = models.FloatField() 
    class Meta: 
     abstract = True 

class my_model(superfields): 
    def has_history(self): 
     return self.my_model_history_set.count() > 0 

class my_model_history(superfields): 
    reason = models.TextField() 
    mymodel = models.ForeignKey(my_model) 

« my_model » est peuplé de données (sous FieldA et FieldB). Chaque fois que quelqu'un édite les champs et les sauvegardes de my_model, je ne veux pas enregistrer le changement dans ce modèle mais je veux le stocker comme une nouvelle ligne avec toutes les valeurs dans 'my_model_history', en plus d'un champ 'reason' avec 'my_model' les données restent les mêmes.

Quelle est la meilleure façon d'aborder ce scénario en termes de modèles personnalisés, de vues personnalisées, d'administrateurs de modèles, etc. Je le fais correctement? Pour donner à ma question ci-dessus un sens, dans mon projet, la nature des données sous «my_model» est les prix du marché et je dois maintenir un historique de tous les prix du marché édités avec une «raison» pour l'édition.

+3

Je ne sais pas si cela vous convient, mais django-reversion (https://github.com/etianen/django-reversion) est une solution très pratique pour administrer l'histoire d'un modèle! –

+0

Hmm c'est une bonne extension, mais c'est plus d'aider dans le développement et de fournir beaucoup d'autres fonctionnalités qui n'ont rien à voir avec mes besoins. Mettre en œuvre ceci pourrait être exagéré pour ce dont j'ai besoin. – sysasa

+0

Avez-vous déjà choisi une solution? –

Répondre

1

Ma solution:

oui. Une solution simple et rapide je suivais comme suit: Je crée trois modèles similaires à ceci:

class my_super_abstract_model(Model): 
    #All fields I need to keep a history for: 
    fieldA = models.FloatField() 
    fieldB = models.FloatField() 
    class Meta: 
     abstract = True 

class my_model(my_super_abstract_model): 
    def has_history(self): 
     return self.my_model_history_set.count() > 0 

class my_model_history(my_super_abstract_model): 
    reason = models.TextField() 
    history_entry_for = models.ForeignKey(my_model) 

J'ai installé un signal:

pre_save.connect(create_history, 
        sender = my_model_history) 

et « créer l'histoire » à appeler par le signal pre_save() avant d'enregistrer en my_model_history:

def create_history(sender, **kwargs): 
    #get variables passed by the pre-save signal: 
    history_model = kwargs['instance'] 
    # Get main model object 
    main_model = history_model.history_entry_for 
    # swap all common fields between history edit and main model (except id) 
    main_model_fields = [f.name for f in main_model._meta.fields] 
    history_model_fields = [f.name for f in history_model._meta.fields] 
    field_index = list([f for f in history_model_fields if f in main_model_fields and f != 'id' and f != 'created_date' ]) 
    #loop thru to swap values: 
    for field_name in field_index: 
     temp = getattr(main_model, field_name) 
     setattr(main_model, field_name, getattr(history_model, field_name)) 
     setattr(history_model, field_name, temp) 
    # After the swap, save main model object here 
    main_model.save() 

Chaque fois que l'utilisateur clique sur une ligne de my_model pour l'édition, j'utilise « my_model_history » pour générer ma forme d'édition et remplissez-le avec les valeurs de la ligne sélectionnée par l'utilisateur. (Ont écrit une vue et un modèle pour le faire)

Ainsi, le formulaire d'édition aura maintenant:

    champ
  1. A -populated avec des valeurs de données my_model ligne
  2. champ
  3. B -populated avec des valeurs de données my_model ligne
  4. Raison zone de texte -empty
  5. history_entry_for -hidden de la vue

L'utilisateur peut maintenant modifier champA/champB. Entrez une raison. Appuyez sur Enregistrer pour déclencher le signal ci-dessus. Avant d'enregistrer,

  1. Signal échangera les valeurs entre le modèle principal (anciennes valeurs) et modèle d'histoire (nouvelles valeurs)
  2. Remplacer et enregistrer la ligne principale du modèle (avec les nouvelles valeurs).
  3. Insérez et enregistrez une nouvelle ligne dans le modèle d'historique (avec les anciennes valeurs) avec une raison.

Espérons que cela aide. Faites-moi savoir s'il y a d'autres questions.

2

Au lieu de modifier une entrée existante, pourquoi ne pas utiliser cette entrée comme donnée initiale pour un formulaire pour créer une nouvelle instance? Le nouvel objet est sauvegardé, l'original reste le même ...

+0

hmmm. Je vais essayer cette approche. Je vous tiendrai au courant de la solution ou en cas de problème. Merci! – sysasa

+0

solution ci-dessous: – sysasa

0

J'ai trouvé une explication sur la conservation des historiques détaillés dans le livre 'pro django' page 264. Après une lecture, je vais essayer une implémentation de ce que je avoir besoin. Publierai mon approche ici quand je suis fait

+1

5 ans et toujours pas lu? – yoshi

Questions connexes