2010-05-02 8 views
7

Je souhaite ajouter quelques champs à chaque modèle de mon application django. Cette fois c'est created_at, updated_at et notes. Le code de duplication pour chacun des 20+ modèles semble stupide. J'ai donc décidé d'utiliser une classe de base abstraite qui ajouterait ces champs. Le problème est que les champs hérités de la classe de base abstraite viennent en premier dans la liste des champs dans admin. Déclarer l'ordre des champs pour chaque classe ModelAdmin n'est pas une option, c'est encore plus de code en double qu'avec une déclaration de champ manuelle.Réorganisation des champs dans le modèle Django

Dans ma solution finale, j'ai modifié constructeur modèle pour réorganiser les champs _meta avant de créer une nouvelle instance:

class MyModel(models.Model): 
    # Service fields 
    notes = my_fields.NotesField() 
    created_at = models.DateTimeField(auto_now_add=True) 
    updated_at = models.DateTimeField(auto_now=True) 

    class Meta: 
     abstract = True 

    last_fields = ("notes", "created_at", "updated_at") 
    def __init__(self, *args, **kwargs): 
     new_order = [f.name for f in self._meta.fields] 
     for field in self.last_fields: 
      new_order.remove(field) 
      new_order.append(field) 
     self._meta._field_name_cache.sort(key=lambda x: new_order.index(x.name)) 
     super(MyModel, self).__init__(*args, **kwargs) 

class ModelA(MyModel): 
    field1 = models.CharField() 
    field2 = models.CharField() 
    #etc ... 

Il fonctionne comme prévu, mais je me demande, est-il une meilleure façon de acheive mon objectif ?

Répondre

5

Si vous avez principalement besoin de la commande de l'administrateur de Django, vous pouvez également créer votre classe "générique" -admin en sous-classant la classe d'administration de Django. Voir http://docs.djangoproject.com/en/dev/intro/tutorial02/#customize-the-admin-form pour personnaliser l'affichage des champs dans l'admin. Vous pouvez écraser le __init__ de l'administrateur pour configurer les champs/fieldsets lors de la création de l'instance d'admin comme vous le souhaitez. Par exemple. vous pourriez faire quelque chose comme:

class MyAdmin(admin.ModelAdmin): 
    def __init__(self, model, admin_site): 
     general_fields = ['notes', 'created_at', 'updated_at'] 
     fields = [f.name for f in self.model._meta.fields if f.name not in general_fields] 
     self.fields = fields + general_fields 
     super(admin.ModelAdmin, self).__init__(model, admin_site) 

plus que je pense que ce n'est pas une bonne pratique de modifier le (privé) _field_name_cache!

7

j'avais le même problème, mais je trouve ces solutions problématique, voici donc ce que je faisais:

class BaseAdmin(admin.ModelAdmin): 
    def get_fieldsets(self, request, obj = None): 
     res = super(BaseAdmin, self).get_fieldsets(request, obj) 
     # I only need to move one field; change the following 
     # line to account for more. 
     res[0][1]['fields'].append(res[0][1]['fields'].pop(0)) 
     return res 

Modification du fieldset dans l'admin a plus de sens pour moi, que de changer les champs dans le modèle.

0

Je n'aimais pas non plus les autres solutions, j'ai donc simplement modifié directement les fichiers de migrations. Chaque fois que vous créez une nouvelle table dans models.py, vous devrez exécuter "python manage.py makemigrations" (je crois que dans Django> = v1.7.5). Une fois cela fait, ouvrez le fichier migrations nouvellement créé dans le répertoire your_app_path/migrations/ et déplacez simplement les lignes dans l'ordre dans lequel vous voulez qu'elles se trouvent. Exécutez ensuite "python manage.py migrate". Voila! En allant dans "python manage.py dbshell" vous pouvez voir que l'ordre des colonnes est exactement comme vous les vouliez! Inconvénient de cette méthode: Vous devez le faire manuellement pour chaque table que vous créez, mais heureusement, la surcharge est minime. Et cela ne peut être fait que lorsque vous créez une nouvelle table, pas pour modifier une table existante.

Questions connexes