Is this a OneToOne or something else?

7 views
Skip to first unread message

Hanne Moa

unread,
Feb 12, 2008, 6:11:29 AM2/12/08
to django...@googlegroups.com
Just starting out with Django here...

In an existing database whose existing table-structure must remain
unchanged by django, I have several cases of what looks like a
OneToOne, for instance:

The table/class org has a field region which points to the id on the
table/class region (dump from postgres):

CREATE TABLE org (
..
region integer,
..
);

CREATE TABLE region (
id integer NOT NULL,
region character varying(32) NOT NULL, -- county, state
location character varying(32) NOT NULL -- location within region
);

ALTER TABLE ONLY org
ADD CONSTRAINT "$5" FOREIGN KEY (region) REFERENCES region(id);

Each org only has a single region, and in the old web-interface the
region-data is shown as a drop-down-list (<select>) where you can
choose one and only one. So: org.region == region.id, there can be
many orgs in a region but only one region per org.

Basically, tables like "region" act as helpers for the "real" tables
like "org", by limiting what region can be filled out for the org. The
"region"-table is basically readonly, as the only way to change
anything in it is to do so manually, with the right privileges,
directly with sql-commands.

This looks like a OneToOne to me, but OneToOnes are not to be used, so
what to do instead?

(Oh, and having a way to make a model inherit from another (single
inheritance is fine) would be swell. The obvious way didn't work.)


HM

Malcolm Tredinnick

unread,
Feb 12, 2008, 6:16:15 AM2/12/08
to django...@googlegroups.com

On Tue, 2008-02-12 at 12:11 +0100, Hanne Moa wrote:
> Just starting out with Django here...
>
> In an existing database whose existing table-structure must remain
> unchanged by django, I have several cases of what looks like a
> OneToOne, for instance:
>
> The table/class org has a field region which points to the id on the
> table/class region (dump from postgres):
>
> CREATE TABLE org (
> ..
> region integer,
> ..
> );
>
> CREATE TABLE region (
> id integer NOT NULL,
> region character varying(32) NOT NULL, -- county, state
> location character varying(32) NOT NULL -- location within region
> );
>
> ALTER TABLE ONLY org
> ADD CONSTRAINT "$5" FOREIGN KEY (region) REFERENCES region(id);
>
> Each org only has a single region, and in the old web-interface the
> region-data is shown as a drop-down-list (<select>) where you can
> choose one and only one. So: org.region == region.id, there can be
> many orgs in a region but only one region per org.

Which means it's many-to-one, not one-to-one. If you were to draw a
picture of your table rows, many rows would (potentially) be pointing to
a single row in the org table. That's many-to-one.

In Django a many-to-one relation is represented by a ForeignKey field.

[...]


> (Oh, and having a way to make a model inherit from another (single
> inheritance is fine) would be swell. The obvious way didn't work.)

Two minutes searching for "model inheritance" in the archives reveals
that it is work in progress.

If you're just starting out, you're going to want to spend a bit of time
searching in the django-users archives (or just searching in Google and
making sure "django" is in the query). There are very few 'new'
questions of this nature.

Regards,
Malcolm

--
If you think nobody cares, try missing a couple of payments.
http://www.pointy-stick.com/blog/

Hanne Moa

unread,
Feb 12, 2008, 6:44:23 AM2/12/08
to django...@googlegroups.com
On Feb 12, 2008 12:16 PM, Malcolm Tredinnick <mal...@pointy-stick.com> wrote:
> On Tue, 2008-02-12 at 12:11 +0100, Hanne Moa wrote:
> > Each org only has a single region, and in the old web-interface the
> > region-data is shown as a drop-down-list (<select>) where you can
> > choose one and only one. So: org.region == region.id, there can be
> > many orgs in a region but only one region per org.
>
> Which means it's many-to-one, not one-to-one. If you were to draw a
> picture of your table rows, many rows would (potentially) be pointing to
> a single row in the org table. That's many-to-one.
>
> In Django a many-to-one relation is represented by a ForeignKey field.

I'm using a ForeignKey-field for it now, but I don't see anywhere how
to make it behave as in the old system: in Django's admin-interface
for org the foreignkey is shown as a drop-down *but with nothing
selected*.

When looking at the examples in the tutorial: Poll/Choice, a Poll can
have several Choices, but a Choice can have only a single Poll. But
org->region is *the other way around*. One Poll containing many
Choices vs. one org having one region. The fact that one region have
many orgs is irrelevant as region will never be editable or visible
anywhere else but as linked from org.

So, how do I do that?

> If you're just starting out, you're going to want to spend a bit of time
> searching in the django-users archives (or just searching in Google and
> making sure "django" is in the query). There are very few 'new'
> questions of this nature.

Then where's the FAQ?


HM

Malcolm Tredinnick

unread,
Feb 12, 2008, 6:51:33 AM2/12/08
to django...@googlegroups.com

On Tue, 2008-02-12 at 12:44 +0100, Hanne Moa wrote:
> On Feb 12, 2008 12:16 PM, Malcolm Tredinnick <mal...@pointy-stick.com> wrote:
> > On Tue, 2008-02-12 at 12:11 +0100, Hanne Moa wrote:
> > > Each org only has a single region, and in the old web-interface the
> > > region-data is shown as a drop-down-list (<select>) where you can
> > > choose one and only one. So: org.region == region.id, there can be
> > > many orgs in a region but only one region per org.
> >
> > Which means it's many-to-one, not one-to-one. If you were to draw a
> > picture of your table rows, many rows would (potentially) be pointing to
> > a single row in the org table. That's many-to-one.
> >
> > In Django a many-to-one relation is represented by a ForeignKey field.
>
> I'm using a ForeignKey-field for it now, but I don't see anywhere how
> to make it behave as in the old system: in Django's admin-interface
> for org the foreignkey is shown as a drop-down *but with nothing
> selected*.
>
> When looking at the examples in the tutorial: Poll/Choice, a Poll can
> have several Choices, but a Choice can have only a single Poll. But
> org->region is *the other way around*. One Poll containing many
> Choices vs. one org having one region. The fact that one region have
> many orgs is irrelevant as region will never be editable or visible
> anywhere else but as linked from org.
>
> So, how do I do that?

Put the ForeignKey on the "many" side of the relation. In your case, it
looks like it goes on the "org" model, since there are many orgs to a
region.

>
> > If you're just starting out, you're going to want to spend a bit of time
> > searching in the django-users archives (or just searching in Google and
> > making sure "django" is in the query). There are very few 'new'
> > questions of this nature.
>
> Then where's the FAQ?

http://www.google.com/search?q=django+FAQ

Regards,
Malcolm

--
For every action there is an equal and opposite criticism.
http://www.pointy-stick.com/blog/

Hanne Moa

unread,
Feb 12, 2008, 7:36:21 AM2/12/08
to django...@googlegroups.com

I already have:

class Region(models.Model):
id = models.IntegerField(unique=True, primary_key=True)
region = models.CharField(maxlength=32)
location = models.CharField(maxlength=32)
class Meta: db_table = 'region'

def __str__(self):
return '%s (%s)' % (self.region, self.lokasjon)

class Org(models.Model):
id = models.IntegerField(unique=True, primary_key=True)
..
region = models.ForeignKey(Region, db_column = 'id') #x, Region.id
..
class Admin: pass

... and in the admin-interface for Org I see Region: '----------'
instead of the expected Region: 'someregion (somelocation)'. If I add
'class Admin: pass' to Region I get to add more Regions to the Org,
which I never want. If I do the other examples in the tutorial I also
get to add more regions, which I never want.

I might have been unclear so I'll try again:
1. how do I get "Region: 'someregion (somelocation)'" in the admin
interface instead of "Region: '---------'"?
2. ...while at the same time ensuring that another Region can never be
added to that particular Org? Changed, yes, added, no.

> > > There are very few 'new' questions of this nature.
> >
> > Then where's the FAQ?
>
> http://www.google.com/search?q=django+FAQ

http://www.djangoproject.com/documentation/faq/

This FAQ, which I read before I came here, and which I assume is
pretty official, doesn't contain answers to my type of question. So,
is there another FAQ for such? The obvious google didn't find any.


HM

Malcolm Tredinnick

unread,
Feb 12, 2008, 7:56:35 AM2/12/08
to django...@googlegroups.com

Here's the problem: your __str__ method will be throwing an exception
because the lokasion attribute doesn't exist.

>
> class Org(models.Model):
> id = models.IntegerField(unique=True, primary_key=True)
> ..
> region = models.ForeignKey(Region, db_column = 'id') #x, Region.id

By default, ForeignKeys refer to the primary key of the related model.
So you can do away with the db_column attribute here if you want to be
more succient.

[...]


> http://www.djangoproject.com/documentation/faq/
>
> This FAQ, which I read before I came here, and which I assume is
> pretty official, doesn't contain answers to my type of question. So,
> is there another FAQ for such? The obvious google didn't find any.

Any FAQ file is a subset of frequently ask questions. It doesn't contain
every single question ever asked. Not even every question asked more
than once. However a lot of questions of already been asked previously
on this very mailing list. So I am suggesting that you do the natural
things and search the mailing list archives (or just use Google and
don't even restrict it to the django-user archives). View the mailing
list as an ever-growing, live list of frequently asked questions (and
multiple answers).

Regards,
Malcolm

--
Borrow from a pessimist - they don't expect it back.
http://www.pointy-stick.com/blog/

Hanne Moa

unread,
Feb 12, 2008, 8:13:07 AM2/12/08
to django...@googlegroups.com
On Feb 12, 2008 1:56 PM, Malcolm Tredinnick <mal...@pointy-stick.com> wrote:
> On Tue, 2008-02-12 at 13:36 +0100, Hanne Moa wrote:
> > class Region(models.Model):
> > id = models.IntegerField(unique=True, primary_key=True)
> > region = models.CharField(maxlength=32)
> > location = models.CharField(maxlength=32)
> > class Meta: db_table = 'region'
> >
> > def __str__(self):
> > return '%s (%s)' % (self.region, self.lokasjon)
>
> Here's the problem: your __str__ method will be throwing an exception
> because the lokasion attribute doesn't exist.

I knew you'd say that as soon as I sent it in when I noticed I hadn't
Anglified the "lokasjon"-attribute everywhere (why'd I do such a thing
in the first place? To make it easier for you, of course.)

Now, that typo isn't there in the actual running code. I don't get any
exceptions or errors when running it. I'll repeat my question:

1. how do I get "Region: 'someregion (somelocation)'" in the admin
interface instead of "Region: '---------'"?
2. ...while at the same time ensuring that another Region can never be
added to that particular Org? Changed, yes, added, no.

By subclassing ForeignKey or is there a parameter/flag/option to set somewhere?

> > class Org(models.Model):
> > id = models.IntegerField(unique=True, primary_key=True)
> > ..
> > region = models.ForeignKey(Region, db_column = 'id') #x, Region.id
>
> By default, ForeignKeys refer to the primary key of the related model.
> So you can do away with the db_column attribute here if you want to be
> more succient.

Good to know.

> > http://www.djangoproject.com/documentation/faq/
> >
> > This FAQ doesn't contain answers to my type of question.


>
> a lot of questions of already been asked previously
> on this very mailing list. So I am suggesting that you do the natural
> things and search the mailing list archives (or just use Google and
> don't even restrict it to the django-user archives). View the mailing
> list as an ever-growing, live list of frequently asked questions (and
> multiple answers).

I'll take this as a suggestion to make a FAQ for these types of
questions as I detest having to only depend on search through a
mailinglist/wiki/bbs/irclog/whatever, then finding an answer from last
century with a solution that no longer works. Or a solution written in
a language I don't read. Or a solution to the wrong problem, or...

I'll even strive to make this FAQ a proper Django app, now there's a
win-win for us all.


HM

Malcolm Tredinnick

unread,
Feb 12, 2008, 8:23:09 AM2/12/08
to django...@googlegroups.com

On Tue, 2008-02-12 at 14:13 +0100, Hanne Moa wrote:
> On Feb 12, 2008 1:56 PM, Malcolm Tredinnick <mal...@pointy-stick.com> wrote:
> > On Tue, 2008-02-12 at 13:36 +0100, Hanne Moa wrote:
> > > class Region(models.Model):
> > > id = models.IntegerField(unique=True, primary_key=True)
> > > region = models.CharField(maxlength=32)
> > > location = models.CharField(maxlength=32)
> > > class Meta: db_table = 'region'
> > >
> > > def __str__(self):
> > > return '%s (%s)' % (self.region, self.lokasjon)
> >
> > Here's the problem: your __str__ method will be throwing an exception
> > because the lokasion attribute doesn't exist.
>
> I knew you'd say that as soon as I sent it in when I noticed I hadn't
> Anglified the "lokasjon"-attribute everywhere (why'd I do such a thing
> in the first place? To make it easier for you, of course.)
>
> Now, that typo isn't there in the actual running code. I don't get any
> exceptions or errors when running it. I'll repeat my question:
>
> 1. how do I get "Region: 'someregion (somelocation)'" in the admin
> interface instead of "Region: '---------'"?

I don't know why this is happening. ForeignKeys normally just work
properly. It should be working as you expect.

Try using your models to create fresh database tables (against a new
database, of course) to see how they should be working. When you add a
region to an org, when you subsequently go back and edit the org it will
show the region as selected. So there's something slightly amiss with
the way things are matched up in your retrofitted models. You could also
try comparing the output of "manage.py sql <app_name>" to the actual
database tables to make sure the reference is pointing to the right
field, etc.

> 2. ...while at the same time ensuring that another Region can never be
> added to that particular Org? Changed, yes, added, no.

That just means not having an Admin inner class on the Region model.

Regards,
Malcolm

--
If it walks out of your refrigerator, LET IT GO!!
http://www.pointy-stick.com/blog/

Hanne Moa

unread,
Feb 12, 2008, 8:51:23 AM2/12/08
to django...@googlegroups.com
On Feb 12, 2008 2:23 PM, Malcolm Tredinnick <mal...@pointy-stick.com> wrote:
> On Tue, 2008-02-12 at 14:13 +0100, Hanne Moa wrote:
> > 1. how do I get "Region: 'someregion (somelocation)'" in the admin
> > interface instead of "Region: '---------'"?
>
> I don't know why this is happening. ForeignKeys normally just work
> properly. It should be working as you expect.
>
> [..] So there's something slightly amiss with

> the way things are matched up in your retrofitted models. You could also
> try comparing the output of "manage.py sql <app_name>" to the actual
> database tables to make sure the reference is pointing to the right
> field, etc.

I checked the generated sql. No wonder it went wrong. With db_column
in the ForeignKey, the attribute Org.region in python became org.id in
the sql, meaning there were several fields "id" in the same table!
When I removed db_column in ForeignKey, the Python attribute
Org.region became org.region_id in the table and hence not matching
the existing table. Too much automagic or what?

In case you wondered: inspectdb croaks on this monster so the models
are all hand-made.

So, new question: how do I prevent the python-attribute in the
Org-class from being renamed in the sql? Now, if I had made the
underlying sql I would never have called every primary key the same
though, because if you don't, you get to use natural joins, which
rocks when it comes to readability/maintenance of sql... but that's
just me.


HM

Malcolm Tredinnick

unread,
Feb 12, 2008, 8:58:29 AM2/12/08
to django...@googlegroups.com

On Tue, 2008-02-12 at 14:51 +0100, Hanne Moa wrote:
> On Feb 12, 2008 2:23 PM, Malcolm Tredinnick <mal...@pointy-stick.com> wrote:
> > On Tue, 2008-02-12 at 14:13 +0100, Hanne Moa wrote:
> > > 1. how do I get "Region: 'someregion (somelocation)'" in the admin
> > > interface instead of "Region: '---------'"?
> >
> > I don't know why this is happening. ForeignKeys normally just work
> > properly. It should be working as you expect.
> >
> > [..] So there's something slightly amiss with
> > the way things are matched up in your retrofitted models. You could also
> > try comparing the output of "manage.py sql <app_name>" to the actual
> > database tables to make sure the reference is pointing to the right
> > field, etc.
>
> I checked the generated sql. No wonder it went wrong. With db_column
> in the ForeignKey, the attribute Org.region in python became org.id in
> the sql, meaning there were several fields "id" in the same table!
> When I removed db_column in ForeignKey, the Python attribute
> Org.region became org.region_id in the table and hence not matching
> the existing table.

Use db_column="region".

Cheers,
Malcolm

--
Quantum mechanics: the dreams stuff is made of.
http://www.pointy-stick.com/blog/

Hanne Moa

unread,
Feb 12, 2008, 9:26:20 AM2/12/08
to django...@googlegroups.com
On Feb 12, 2008 2:58 PM, Malcolm Tredinnick <mal...@pointy-stick.com> wrote:
> On Tue, 2008-02-12 at 14:51 +0100, Hanne Moa wrote:
> > On Feb 12, 2008 2:23 PM, Malcolm Tredinnick <mal...@pointy-stick.com> wrote:
> > > On Tue, 2008-02-12 at 14:13 +0100, Hanne Moa wrote:
> > > > 1. how do I get "Region: 'someregion (somelocation)'" in the admin
> > > > interface instead of "Region: '---------'"?
> > >
> > > [..] So there's something slightly amiss with
> > > the way things are matched up in your retrofitted models. You could also
> > > try comparing the output of "manage.py sql <app_name>" to the actual
> > > database tables to make sure the reference is pointing to the right
> > > field, etc.
> >
> > I checked the generated sql. No wonder it went wrong. With db_column
> > in the ForeignKey, the attribute Org.region in python became org.id in
> > the sql, meaning there were several fields "id" in the same table!
> > When I removed db_column in ForeignKey, the Python attribute
> > Org.region became org.region_id in the table and hence not matching
> > the existing table.
>
> Use db_column="region".

Ah! We have liftoff! I thought db_column referenced the foreign table.
Well, I keep mixing up the order of arguments in split() and join()
to...


HM

Reply all
Reply to author
Forward
0 new messages