Django QuerySet order_by string evaluation
I'm trying to sort my QuerySet based on how the objects in the QuerySet are evaluated as Strings.
So my model looks something like this:
class System(models.Model):
operating_system = models.CharField(...)
language = models.CharField(...)
locale = models.CharField(...)
def __unicode__(self):
def __clean(orig, new):
if orig is None or orig == "":
if new is None or new == "":
return ""
else:
return str(new)
else:
if new is None or new == "":
return str(orig)
else:
return str(orig) + " " + str(new)
name = None
for attr in System._meta.fields:
if attr.name != "id":
name = __clean(name, getattr(self, attr.name))
for m2mfield in System._meta.many_to_many:
for object in getattr(self, m2mfield.name).all():
name = __clean(name, object)
if name == "":
return "Undefined"
return name
And, I'd like to be able to make a query something like:
System.objects.filter(...)开发者_开发知识库.order_by('__unicode__')
I'm wondering if there's a way to do this without a custom manager.
Thanks!
In __unicode__
you eventually end up with a single string that represents a System object. Instead of calculating it every time you need it, calculate it once and save it onto the model.
class System(models.Model):
operating_system = models.CharField(...)
language = models.CharField(...)
locale= models.CharField(...)
name = models.CharField(editable=False, ...)
def save(self, *args, **kwargs):
self.name = self._calculate_name()
super(System, self).save(*args, **kwargs)
def __unicode__(self):
return self.name
def _calculate_name(self):
# all that string manipulation and relationship stuff
Now you can order by this name easily
System.objects.filter(...).order_by('name')
There are some caveats to this approach, it really depends on the usage of System. Also, do NOT worry about the space, that's my opinion!
Expanding on caveats
Since this field is 'denormalized', it suffers from the same problems other relational data that isn't normalized face. Denormalization can introduce update anomalies (a field or relation that name
depends on can change without a change to name
if the change happens through some other route than the System
model's save()
method. It can also slow down writes (in this case probably by a very small amount), it can increase space requirements (again not a problem here in my opinion), and a whole wack of other stuff that Google would love to tell you about I'm sure.
I think all you have to be careful about is updating .name
whenever it should be, so consider carefully under what conditions your 'cleaning' code will produce different results. If, for example, you had an OS table where you can change the description of an OS without touching the System table, then you have to realize your .name
will not be updated by a save to OS, it will require recalculation. There are mechanisms to help with this like signals and overriding more save()
methods. You could also batch update them as necessary.
It really depends heavily on your use case, which is not fully illustrated here. SO is full of people that could help you narrow down the best solution if you present your use case more completely.
精彩评论