简体   繁体   中英

Error saving django model with OneToOne field - Column specified twice

This question has been asked before, but the answers there do not solve my problem.

I am using a legacy database, nothing can be changed

Here are my django models, with all but the relevant fields stripped off, obviously class meta has Managed=False in my actual code:

class AppCosts(models.Model):
    id = models.CharField(primary_key=True)
    cost = models.DecimalField()

class AppDefs(models.Model):
    id = models.CharField(primary_key=True)
    data = models.TextField()
    appcost = models.OneToOneField(AppCosts, db_column='id')

class JobHistory(models.Model):
    job_name = models.CharField(primary_key=True)
    job_application = models.CharField()
    appcost = models.OneToOneField(AppCosts, to_field='id', db_column='job_application')
    app = models.OneToOneField(AppDefs, to_field='id', db_column='job_application')

The OneToOne fields work fine for querying, and I get the correct result using select_related()

But when I create a new record for the JobHistory table, when I call save(), I get:

DatabaseError: (1110, "Column 'job_application' specified twice")

I am using django 1.4 and I do not quite get how this OneToOneField works. I can't find any example where primary keys are named differently and has this particular semantics

I need the django model that would let me do this SQL:

 select job_history.job_name, job_history.job_application, app_costs.cost from job_history, app_costs where job_history.job_application = app_costs.id;

You have defined appcost and app to have the same underlying database column, job_application , which is also the name of another existing field: so three fields share the same column. That makes no sense at all.

OneToOneFields are just foreign keys constrained to a single value on both ends. If you have foreign keys from JobHistory to AppCost and AppDef, then presumably you have actual columns in your database that contain those foreign keys. Those are the values you should be using for db_field for those fields, not "job_application".

Edit I'm glad you said you didn't design this schema, because it is pretty horrible: you won't have any foreign key constraints, for example, which makes referential integrity impossible. But never mind, we can actually achieve what you want, more or less.

There are various issues with that you have, but the main one is that you don't need the separate "job_application" field at all. That is, as I said earlier, the foreign key, so let it be that. Also note it should be an actual foreign key field, not a one-to-one, since there are many histories to one app.

One constraint that we can't achieve easily in Django is to have the same field acting as FK for two tables. But that doesn't really matter, since we can get to AppCosts via AppDefs.

So the models could just look like this:

class AppCosts(models.Model):
    app = models.OneToOneField('AppDefs', primary_key=True, db_field='id')
    cost = models.DecimalField()

class AppDefs(models.Model):
    id = models.CharField(primary_key=True)
    data = models.TextField()

class JobHistory(models.Model):
    job_name = models.CharField(primary_key=True)
    app = models.ForeignKey(AppDefs, db_column='job_application')

Note that I've moved the one-to-one between Costs and Defs onto AppCosts, since it seems to make sense to have the canonical ID in Defs.

Now, given a JobHistory instance, you can do history.app to get the app instance, history.app.cost to get the app cost, and use the history.app_id to get the underlying app ID from the job_application column.

If you wanted to reproduce that SQL output more exactly, something like this would now work:

JobHistory.objects.values_list('job_name', 'app_id', 'app__appcosts__cost')

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM