home / django_tickets / tickets

tickets: 10961

This data as json

id created changetime last_pulled_from_trac stage status component type severity version resolution summary description owner reporter keywords easy has_patch needs_better_patch needs_tests needs_docs ui_ux
10961 2009-04-30 02:27:48 2021-11-05 23:26:54 2022-03-06 03:48:42.647889 Accepted new Database layer (models, ORM) New feature Normal dev   Allow users to override forward and reverse relationships on proxy models with !ForeignKey fields. I have a few generic models with foreign keys (simplified for this example): {{{ class Country(turbia_models.Model): name = turbia_models.CharField(max_length=50, unique=True) class State(turbia_models.Model): name = turbia_models.CharField(max_length=50) country = models.ForeignKey(Country) class Region(turbia_models.Model): name = turbia_models.CharField(max_length=50) state = models.ForeignKey(State) class Suburb(turbia_models.Model): name = turbia_models.CharField(max_length=50) region = models.ForeignKey(Region) }}} I want to create proxy models for each of these when used with particular applications: {{{ class Venue(models.Model): name = models.CharField(max_length=50) slug = models.SlugField() suburb = models.ForeignKey(Suburb) class CountryProxy(Country): class Meta: proxy = True @property def venue_set(self): return Venue.objects.filter(suburb__region__state__country=self) def get_absolute_url(self): return '/directory/%s/' % self.slug class StateProxy(State): class Meta: proxy = True @property def venue_set(self): return Venue.objects.filter(suburb__region__state=self) def get_absolute_url(self): return '%s%s/' % (self.country.get_absolute_url(), self.slug) class RegionProxy(Region): class Meta: proxy = True @property def venue_set(self): return Venue.objects.filter(suburb__region=self) def get_absolute_url(self): return '%s%s/' % (self.state.get_absolute_url(), self.slug) class SuburbProxy(Suburb): class Meta: proxy = True @property def venue_set(self): return Venue.objects.filter(suburb=self) def get_absolute_url(self): return '%s%s/' % (self.region.get_absolute_url(), self.slug) }}} This works if I never use the !ForeignKey fields or reverse relationship managers to get related objects. E.g. if `state` is a !StateProxy object and I try `state.country`, I'll end up with a !Country object instead of a !CountryProxy object. Likewise if `country` is a !CountryProxy object and I try `country.state_set.all()`, I'll end up with a queryset of !State objects instead of !StateProxy objects. This can be worked around with queries like `Country.objects.get(pk=state.country.pk)` and `State.objects.filter(country=country)`, but this kinda defeats the purpose of the ORM, and is not practical inside templates. Where you should be able to just pass a single !CountryProxy object to your template and do: {{{ <h1>{{ country }}</h1> {% for state in country.state_set.all %} <h2>{{ state }}</h2> {% for region in state.region_set.all %} <h3>{{ region }}</h3> <p> {% for suburb in region.suburb_set.all %} <a href="{{ suburb.get_absolute_url }}">{{ suburb }}</a><br> {% endfor %} </p> {% endfor %} {% endfor %} }}} You need to pass all these objects and querysets from the view into the template context in some kind of nested structure. {{{ def directory(request, slug): country = get_object_or_404(CountryProxy, slug=slug) state_data = ((state, ( (region, SuburbProxy.objects.filter(region=region)) for region in RegionProxy.objects.filter(state=state) )) for state in StateProxy.objects.filter(country=country)) render_to_response('directory.html', {'country': country, 'data': data}) }}} and: {{{ <h1>{{ country }}</h1> {% for state, region_data in state_data %} <h2>{{ state }}</h2> {% for region, suburb_set in region_data %} <h3>{{ region }}</h3> <p> {% for suburb in suburb_set %} <a href="{{ suburb.get_absolute_url }}">{{ suburb }}</a><br> {% endfor %} </p> {% endfor %} {% endfor %} }}} nobody mrmachine proxy ForeignKey reverse relationship manager 0 0 0 0 0 0
Powered by Datasette · Queries took 1.453ms