2010-06-10 10 views
12

J'ai deux modèles, un MainModel et un InlineModel en rapport que je voudrais afficher en ligne dans l'admin. Ce InlineModel peut être utilisé pour, disons, prendre des notes sur le modèle et doit suivre les modifications effectuées par l'utilisateur admin connecté. Bien que cela semble simple (et en effet, les docs montrent un exemple pour ceci quand le champ d'utilisateur fait partie du MainModel), je ne peux pas sembler le saisir quand le champ est sur le Inline.Django InlineModelAdmin - définir le champ inline à partir de la demande lors de la sauvegarde (définir le champ utilisateur automatiquement) (save_formset vs save_model)

Pour être plus précis, mon objectif est:

  1. modifications utilisateur MainModel
  2. utilisateur ajoute un InlineModel, ne remplissant pas dans le champ utilisateur
  3. presses Permet d'enregistrer
  4. code
  5. remplit dans le domaine de l'utilisateur pour les instances InlineModel nouvellement créées
  6. (Le champ utilisateur Bonus est en lecture seule pour les instances existantes et masqué pour les nouvelles entités)

Et mes questions:

  1. Est-ce exact? Son trop bas save_model n'est pas appelé pour les instances InlineModelAdmin
  2. Est-ce que cela permet de sauvegarder sans provoquer d'erreur? (l'utilisateur est requis, la validation le signale)
  3. Comment puis-je masquer le champ de saisie de l'utilisateur pour de nouvelles inlines, et le garder en lecture seule pour les inlines existants?

Voici mes idées actuelles:


#models.py 
class MainModel(models.Model): 
    some_info = models.IntegerField() 

class InlineModel(models.Model): 
    main = models.ForeignKey(MainModel) 
    data = models.CharField(max_length=255) 
    user = models.ForeignKey('auth.User') 

#admin.py 
class InlineModelInline(admin.TabularInline): 
    model = InlineModel 
    fields = ('data', 'user') 
    #readonly_fields = ('data', 'user') #Bonus question later 

class MainModelAdmin(admin.ModelAdmin): 
    list_display = ('id', 'some_info') 
    inlines = [InlineModelInline] 

    #def save_model(self, request, obj, form, change): 
     #http://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.save_model 
     #Only called for MainModel, not for any of the inlines 
     #Otherwise, would be ideal 

    def save_formset(self, request, form, formset, change): 
     #http://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.save_formset 
     #Experimenting showd this is called once per formset (where the formset is a group of inlines) 
     #See code block at http://code.djangoproject.com/browser/django/tags/releases/1.2.1/django/contrib/admin/options.py#L894 
     if not isinstance(formset.model, InlineModel): 
      return super(MainModelAdmin, self).save_formset(request, form, formset, change) 
     instances = formset.save(commit=False) 
     for instance in instances: 
      if not instance.pk: 
       instance.user = request.user 
     instance.save() 
     formset.save_m2m() 

Répondre

9

J'ai résolu la première moitié de ma question:

def save_formset(self, request, form, formset, change): 
    if formset.model != InlineModel: 
     return super(MainModelAdmin, self).save_formset(request, form, formset, change) 
    instances = formset.save(commit=False) 
    for instance in instances: 
     if not instance.pk: 
      instance.user = request.user 
     instance.save() 
    formset.save_m2m() 

Maintenant, je suis intéressé par le comportement de bonus:

  1. Je suis nécessaire pour sélectionner un utilisateur lors de l'ajout d'une nouvelle ligne en raison de règles de validation. Ma meilleure estimation est de ne pas inclure le champ 'user' dans mon tuple InlineModelInline.fields, mais cela ne montrera pas l'auteur pour les instances InlineModel existantes. (Edit: ajouter 'user' à readonly_fields fonctionne ici)

  2. (Éditer) Comment faire en sorte que les inlines existants rendent le 'data' en lecture seule, tout en étant capable de le modifier en ajoutant un nouveau inline?

+1

Une note à moi-même, ce save_formset est une méthode de la admin.ModelAdmin, et il traitera tous les enfants Inlines attribué dans le ModelAdmin – monkut

+0

Merci pour vos questions/réponses ici En ce qui concerne la fonctionnalité 'bonus' - après avoir marqué l'utilisateur foreignKey dans le modèle django avec editable = False, le formset en ligne a passé la validation, le champ utilisateur était encore défini et tout était kasher. user = models.ForeignKey (Utilisateur, modifiable = Faux) – sdailey

+0

Hm, totalement oublié editable = Faux dans le modèle. tch, merci. –

1

Cela a fonctionné pour moi. L'approche This ne me permettra pas de supprimer des éléments Inline.

def save_formset(self, request, form, formset, change): 
    for form in formset.forms: 
     form.instance.user = request.user 
    formset.save() 
0

Pour répondre à la question bonus: « Comment puis-je faire les inline existantes rendent « données », mais en lecture seule encore pouvoir le modifier lors de l'ajout d'une nouvelle ligne?« :

J'utilise deux inline pour le même modèle.

#admin.py 
class InlineModelInline(admin.TabularInline): 
    model = InlineModel 
    extra = 1 
    max_num = 1 

#admin.py 
class InlineModelExistingInline(admin.TabularInline): 
    model = InlineModel 
    readonly_fields = ('data', 'user') #All Fields here except pk 
    can_delete = False 
    extra = 0 
    max_num = 0 

class MainModelAdmin(admin.ModelAdmin): 
    ... 
    inlines = [InlineModelInline, InlineModelExistingInline] 
    ...