django


Django sharing anotations between related Items


Consider a room booking system. You might have a Building, Floor, Room models as well as a Booking. We give the room a name based on its building and floor:
class Room(models.Model):
number = models.PositiveIntegerField()
name = models.CharField(..)
floor = models.ForeignKey('Floor')
def __str__(self):
return '%s, #%d Floor %d, %s' % (
self.name,
self.number,
self.floor.number,
self.floor.building.name
)
This is woefully inefficient when you're doing hundreds of them (eg admin list, big reports, etc.) so I've taken to writing managers like this:
class RoomManager(models.Manager):
def get_queryset(self):
return super().get_queryset().annotate(
roomname=Concat(
'name',
V(', #'),
'number'
V(' Floor '),
'floor__number'
V(', '),
'floor__building__name',
output_field=models.CharField()
),
)
And that works. It does everything I wanted it to. It's fast and I've reworked the __str__ to do a if hasattr(self, 'roomname'): return self.roomname before it does the horrendous multi-query string builder.
But now on top of this, I have Booking. Each Booking instance is linked to a single room. There are many cases where to list Bookings, I actually also list room names.
What I've done is write a BookingManager:
class RoomManager(models.Manager):
def get_queryset(self):
return super().get_queryset().annotate(
roomname=Concat(
'room__name',
V(', #'),
'room__number'
V(' Floor '),
'room__floor__number'
V(', '),
'room__floor__building__name',
output_field=models.CharField()
),
)
But what the hell? I'm repeating myself. Django is all about DRY and here I am copy and pasting a huge messy annotation around. It's disgusting.
My question is... Is there another way?
While writing this I had an idea, I could write a method that allowed a prefix to be passed in for the relation to room. That way I could call it from anything that was related to room, and it would get the right stuff:
class RoomManager(models.Manager):
def get_queryset(self):
return super().get_queryset().annotate(
roomname=RoomManager.roomname()
)
#staticmethod
def roomname(prefix=''):
return Concat(
prefix + 'name',
V(', #'),
prefix + 'number'
V(' Floor '),
prefix + 'floor__number'
V(', '),
prefix + 'floor__building__name',
output_field=models.CharField()
)
And in the BookingManager I can just annotate on RoomManager.roomname('room__')
It's cleaner and I'll use it elsewhere but it doesn't feel very clever.
How about something like this?
class Room(models.Model):
number = models.PositiveIntegerField()
name = models.CharField(..)
floor = models.ForeignKey('Floor')
def __str__(self):
return '%s, %s %s' % (
self.name,
self.number,
self.floor
)
class Floor(models.Model):
number = models.PositiveIntegerField()
building = models.ForeignKey('Building')
def __str__(self):
return 'Floor %d, %s' % (
self.number,
self.building
)
class Building(models.Model):
name = models.CharField(...)
def __str__(self):
return '%s' % (
self.name
)

Related Links

Django-REST frameowork restore_object attrs parameters
django tables2 checkbox
How can i get my south migrations to work?
Django, boto, S3 and easy_thumbnails not working in production environment
use reverse in a http response redirect in django
Django template and variable {% if x == “about” %} does not work
Difficulties pushing application to Heroku
Sphinx autodoc not importing modules
Tell Django's model to use as primary key a set of foreign keys
Django replace all occurrences [name] with auctual contact.name
How to store static, but user-generated files on Heroku/Django
Django-South not detecting addition of default value on field
How do i should i get sorl thumbnail to work?
Django - How ModelChoiceField queryset's works?
non-volunteer logout when linking between server and client django apps
Django models and admin panel

Categories

HOME
android
phantom-dsl
api
codenvy
apache-flink
android-studio-2.2
character-encoding
rendering
nsbundle
soa
alsa
permissions
3d-reconstruction
zip
nfs
octave
ibeacon-android
ipmitool
job-scheduling
vuejs
digital-signature
bourbon
kendo-mobile
babel
r-mice
direct3d11
expressionengine3
moses
maze
delimiter
oculus
firebase-analytics
ceylon
user-defined-functions
bioinformatics
mql
winpe
twiml
recurring-events
laravel-eloquent
android-gridview
gnat-gps
openwhisk
processwire
verifiable-c
diacritics
demo
numberpicker
magento-1.9.3
linter
vugen
page-replacement
truezip
filehandle
pdf-conversion
cpu-cache
change-tracking
cronexpression
cubism.js
greatest-n-per-group
i386
udpclient
hadoop-partitioning
fink
false-sharing
concept-insights
highland.js
terracotta
fuelcms
slash
mod-proxy
iced-coffeescript
ansi
bcache
jbake
xml-namespaces
wxformbuilder
synapse
syndicationfeed
scriptaculous
model-driven-development
jeromq
observium
neos-server
stacky
apache-abdera
device-width
dopostback
xcode3.2
mapping-by-code
usertype
role
workflow-services
matlab-load
uipagecontrol
inline-formset
delimited-text
escrow

Resources

Encrypt Message