19👍
The correct way to do it would be to break this into three migrations:
- A first schema migration to add the new
IntegerField
field. - Followed by a data migration to convert the data originating from the
CharField
to theIntegerField
- And a final schema migration to remove the now unused
CharField
.
A fourth one might be required if you want your newly added IntegerField
to have the same name as the to-be-removed CharField
.
Given a project state where the IntegerField
is not yet added to you model file you should proceed by following these steps:
- Add the
IntegerField
to you model. - Create a schema migration for the application containing your model. You might need to specify a default value for your newly added field here if it’s not null.
- Create a data migration (using
datamigration
) for the application containing your model. In theforwards()
method of the newly createdDataMigration
class write down your logic to convert your data. Try to use theupdate
manager method instead of iterating overt all your database row if possible. If you declare your conversion logic using adict
(say{'L': 1, ...}
) it should be pretty easy to also implementbackwards()
at this time, given the operation is invertible. It’s also a good exercise to make sure you’ve not overlooked an edged case inforwards()
— it helped me quite a few times in the past. - Remove the
CharField
from your model. - Create a schema migration for the application containing your model in order to
DROP
the now unused column.
The fact that you broke this operation into three migrations instead of writing down your whole logic in a blank template have a couple advantages:
- Auto-generated DDL operations: The
ADD
/DROP
logic have been automatically generated by South and you don’t have to worry about introducing a typo in a database column. - Completely reversible operation: Given you’ve taken the time to implement
DataMigration.backwards()
for the conversion step you should be able to completely reverse the whole operation. This can be handy for testing purpose, if you need to rollback to a previous revision of your code and as safe net when updating a production code base. - Atomicity of operations: The fact that each operation is isolated and run in it’s own transaction won’t leave you in an inconsistent state between your database and your South migration. For example, if all operations were performed in a single migration (in the same
forwards()
method in this case) and an exception was raised during the data migration step (say aKeyError
because of an unhandled value in your conversiondict
). If you’re using aORDBMS
that doesn’t support transactional schema alteration you wouldn’t be able to re-run you migration immediately after fixing the data-migration part, you’d have to manually drop the newly addedIntegerField
column yourself. Again, that’s the kind of thing you don’t want to deal with when migrating a production database. - Ability to perform a dry-run: Also quite handy when migrating a production database.
1👍
for the same situation me followed just 3 steps .
1) changed file type from CharField to IntegerField,
2) ALTER TABLE the_table ALTER COLUMN col_name TYPE integer USING (col_name::integer);
or
ALTER TABLE the_table ALTER COLUMN col_name TYPE integer USING (trim(col_name)::integer); # in case if you having whitespace in your Char or Text field. and if you having data’s in your table, which should be string of integer.
3) Now apply migration.
- Selenium – python. how to capture network traffic's response
- Django render_to_string() ignores {% csrf_token %}