Craig Otis
Craig Otis

Reputation: 32054

Django default model properties based on existing property values?

I have a simple data model in Django, with classes Department and Role. (For example sake.)

A Department has a one-to-many relationship with Role, and the Role class contains an ID that is being used to identify particular instances. For example:

> Department: Sales
>> Role (1): Accounts
>> Role (3): Closing

> Department: Maintenance
>> Role (2): IT
>> Role (4): Equipment

The downside to this is that each role is using its own global ID. So if you were to create a large number of Sales roles, and then create an additional Maintenance role, that new Maintenance role would have an incredibly large ID, and would seem "out-of-sync."

Thus, I would like to create a department-specific ID for each Role as well, like so:

class Role(models.Model):
    department_id = models.IntegerField()

The downside is that I can't find a way to either:

1) Have existing Roles transfer their existing IDs to the new department_id field, leaving the gaps but preventing future gaps from appearing:

> Department: Sales
>> Role (1): Accounts
>> Role (3): Closing
>> Role (4): *New Sales Role*

> Department: Maintenance
>> Role (2): IT
>> Role (4): Equipment
>> Role (5): *New Maintenance Role*

2) Or, dynamically assign the default value to a method that scans the table for all the Roles of each department, and assigns them new IDs:

> Department: Sales
>> Role (1): Accounts
>> Role (2): Closing
>> Role (3): *New Sales Role*

> Department: Maintenance
>> Role (1): IT
>> Role (2): Equipment
>> Role (3): *New Maintenance Role*

I'm using South to handle schema migrations.

Upvotes: 0

Views: 191

Answers (1)

Florian Apolloner
Florian Apolloner

Reputation: 543

You will need three migrations (Taking approach two):

  1. Add a new field to Roles (I'll call it user_id since it's the user visible id I assume…) -- This is done via a schema migration
  2. Create a data migration which loops over all departments, fetches the roles for each department and renumbers them into the new user_id field (a simple counter in the inner loop should suffice, probably order the roles by the current primary key)
  3. Add another schema migration which adds a unique_together constraint to department_id, user_id -- you don't want duplicate user_ids in one department.

Add a new default method to the user_id field which fetches the data as needed (Take care to not run into ugly edge cases -- I would use a SlugField with the role name instead of integer ids)

You obviously won't get rid of the existing pk since Django doesn't support compound primary keys (like over department_id, user_id) but you don't have to display it anywhere.

That said; if it's just to get "nice" ids I would choose slugs instead of numbers.

Upvotes: 1

Related Questions