tags:

views:

961

answers:

4

I want to apply the "ordering" Meta option to the Django model User from django.contrib.auth.models. Normally I would just put the Meta class in the model's definition, but in this case I did not define the model. So where do I put the Meta class to modify the User model?

+7  A: 

This is how the Django manual recommends you do it:

You could also use a proxy model to define a different default ordering on a model. The standard User model has no ordering defined on it (intentionally; sorting is expensive and we don't want to do it all the time when we fetch users). You might want to regularly order by the username attribute when you use the proxy. This is easy:

class OrderedUser(User):
    class Meta:
        ordering = ["username"]
        proxy = True

Now normal User queries will be unorderd and OrderedUser queries will be ordered by username.

Note that for this to work you will need to have a trunk checkout of Django as it is fairly new.

If you don't have access to it, you will need to get rid of the proxy part and implement it that way, which can get cumbersome. Check out this article on how to accomplish this.

Paolo Bergantino
Note that at this time, proxy models are only supported in the development (SVN) version of Django.
Ryan Duffield
I pointed that out in my answer, but I guess I will bold it as it is an important thing to be aware of.
Paolo Bergantino
+1 for proxies. I didn't even know that existed. 1.1 is going to be a nice release.
Soviut
Sorry, didn't notice that at first; you got my +1 anyways. Proxies are awesome. :-)
Ryan Duffield
+3  A: 

You can either subclass User:

class OrderedUser(User):
    class Meta:
        ordering = ['-id', 'username']

Or you could use the ordering in ModelAdmin:

class UserAdmin(admin.ModelAdmin):
    ordering = ['-id', 'username']

# unregister user since its already been registered by auth
admin.site.unregister(User)
admin.site.register(User, UserAdmin)

Note: the ModelAdmin method will only change the ordering in the admin, it won't change the ordering of queries.

Soviut
+1: Fix the admin. You left off adding ordering to the relevant view queries for custom view functions.
S.Lott
A: 

Contact the author and ask them to make a change.

S.Lott
I think when he said "I do not define it" he meant that it's the Django model and the code is in the core.
Paolo Bergantino
I didn't downvote, though.
Paolo Bergantino
+4  A: 

Paolo's answer is great; I wasn't previously aware of the new proxy support. The only issue with it is that you need to target your code to the OrderedUser model - which is in a sense similar to simply doing a User.objects.filter(....).order_by('username'). In other words, it's less verbose but you need to explicitly write your code to target it. (Of course, as mentioned, you'd also have to be on trunk.)

My sense is that you want all User queries to be ordered, including in third party apps that you don't control. In such a circumstance, monkeypatching the base class is relatively easy and very unlikely to cause any problems. In a central location (such as your settings.py), you could do:

from django.contrib.auth.models import User
User.Meta.ordering = ['username']
Daniel
That code fails; you will want to do this instead: User._meta.ordering = ['username'].
Ryan Duffield
Did you test it? If you do it in settings.py, before the app models in INSTALLED_APPS are initialized, I think it ought to work..
Daniel
Ah, I only tested it in a console. Still, I think I'd recommend changing _meta if monkeypatching.
Ryan Duffield
Ryan's approach is better. Importing models in settings.py is very bad practice and likely to lead to breakage.
Carl Meyer
I respectfully disagree... it's better to hook into the model before django does it's metaprogramming magic and transforms the class into something other than what's well documented
Daniel
-1 then -- settings.py is no place for this, either.
Ryan Duffield
what!? then where would you put it?
Daniel
As I said, I would use _meta instead of Meta so that it doesn't matter where I put it.
Ryan Duffield
.. which has an underscore for a reason. if you want to be certain that the behavior is as documented (and will be into the future), it doesn't make sense to hook into the internals of a class when there is a documented option available. that's the kind of monkeypatching that people criticize..
Daniel
I understand that. I'm saying that if one is monkeypatching, I feel this is the lesser evil as it doesn't require having to put anything in totally disparate files like settings.py. I'll retract the -1.
Ryan Duffield