2009-09-24 10 views
18

J'ai une application qui utilise le UserProfile de Django pour étendre le modèle intégré Django User. On dirait un peu comme:Django Admin: Commande des relations ForeignKey et ManyToManyField faisant référence Utilisateur

class UserProfile(models.Model): 
    user = models.ForeignKey(User, unique=True) 
    # Local Stuff 
    image_url_s = models.CharField(max_length=128, blank=True) 
    image_url_m = models.CharField(max_length=128, blank=True) 

    # Admin 
    class Admin: pass 

J'ai ajouté une nouvelle classe à mon modèle:

class Team(models.Model): 
    name = models.CharField(max_length=128) 
    manager = models.ForeignKey(User, related_name='manager') 
    members = models.ManyToManyField(User, blank=True) 

Et il est inscrit dans l'Admin:

class TeamAdmin(admin.ModelAdmin): 
    list_display = ('name', 'manager') 

admin.site.register(Team, TeamAdmin) 

Hélas, dans le inteface admin Lorsque je sélectionne un responsable dans la liste déroulante ou que je sélectionne des membres de l'équipe via le champ de sélection multiple, ils sont classés par ID utilisateur. Pour la vie de moi, je n'arrive pas à comprendre comment les trier.

J'ai une classe similaire avec:

class Meta: 
    ordering = ['name'] 

Cela fonctionne très bien! Mais je ne le fais pas "propre" la User classe, et quand j'essayer cette astuce dans UserAdmin:

class Meta: 
    ordering = ['username'] 

Je reçois:

django.core.management.base.CommandError: One or more models did not validate: events.userprofile: "ordering" refers to "username", a field that doesn't exist.

user.username ne fonctionne pas non plus. Je pourrais spécifier, comme image_url_s si je voulais. . . comment puis-je dire à l'administrateur de trier mes listes d'utilisateurs par username? Merci!

Répondre

24

Une façon serait de définir une forme personnalisée à utiliser pour votre modèle d'équipe dans l'admin, et passer outre le champ manager d'utiliser un queryset avec le bon ordre:

from django import forms 

class TeamForm(forms.ModelForm): 
    manager = forms.ModelChoiceField(queryset=User.objects.order_by('username')) 

    class Meta: 
     model = Team 

class TeamAdmin(admin.ModelAdmin): 
    list_display = ('name', 'manager') 
    form = TeamForm 
+0

Merci, Daniel! – dannyman

+2

Depuis django 1.8, vous avez également besoin de 'fields = '__all __'' dans 'Meta' de classe. – Flash

26

Ce

class Meta: 
    ordering = ['username'] 

devrait être

ordering = ['user__username'] 

si elle est dans votre classe UserProfile admin. Cela arrêtera l'exception, mais je ne pense pas que cela vous aide.

La commande du modèle User comme décrit est assez compliquée, mais voir http://code.djangoproject.com/ticket/6089#comment:8 pour une solution.

3

Cela pourrait être dangereux pour une raison quelconque, mais cela peut être fait en une seule ligne dans votre projet de fichier models.py:

User._meta.ordering=["username"] 
1

Pour moi, la seule solution de travail était d'utiliser Proxy Model.Comme il est indiqué dans la documentation, vous pouvez créer vos propres modèles de proxy pour les modèles même intégrés et personnaliser quelque chose comme dans les modèles réguliers:

class OrderedUser(User): 
    class Meta: 
     proxy = True 
     ordering = ["username"] 
    def __str__(self): 
     return '%s %s' % (self.first_name, self.last_name) 

Après cela, dans votre modèle il suffit de changer de clé étrangère à:

user = models.OneToOneField(OrderedUser, unique=True) 

ou même plus approprié

user = models.OneToOneField(OrderedUser, unique = True, parent_link = True) 
Questions connexes