Hardcoded things in migrations - django

Could you tell me why Django hardcodes the business logic into migrations?
We can formulate the question the other way. Let's have a look at valitadors and upload_to. These all is hardcoded into migrations.
But if we show SQL that a migration produces, no validators or upload_to will be there.
So, why are they hardcoded? Validators and upload_to are already mentioned in models. DRY principle is violated.
Any change in the code ruins migrations. For example renaming of upload_to will result in the project's blowing up.
Validators and upload_to are just examples. There are more things of the kind. Anyway, they don't influence the database. So, why do we need them in migrations?
Could you comment?

Related

What's the Django 1.7+ equivalent to South's add_ignored_fields()?

Back in previous versions of Django, we all used South to do migrations, and because it wasn't as smart as we might have liked, we sometimes needed to tell it to explicitly ignore some fields because such fields were too complicated for it to handle. We did this with add_ignored_fields and everything pretty much worked.
In our case, we have a "field" on our model that's a subclass of CharField that actually attaches two additional fields to the model via the contribute_to_class method. It's kind of a weird process, but it makes sense for our use case and worked just fine until we upgraded to Django 1.7.
However, with the new migrations system, our use of add_ignored_fields() no longer works and our unit tests are exploding as it tries to create a test database table with these fields. Specifically it says:
django.db.utils.OperationalError: duplicate column name: our_column_name
In this case our_column_name is one of the fields this special CharField subclass creates.
In a perfect world, we could have the migration code handle these fields properly, but I'd settle for the 1.7 version of add_ignored_fields() if it exists.
I should also point out that we've found the explanation for deconstruct in the Django documentation, but I'm afraid that it doesn't make any sense to me. I can't figure out if it applies to this situation or not.
We've discovered this Django ticket that pretty much states that this is a design pattern that the devs aren't supporting, so we're just going to have to rewrite the model to explicitly create the other fields on the model and then reference said fields from the "parent" field a la ImageField.

Django (South): change model application

I have defined some models within an application, call it "blog".
djangoproject
/blog
models.py
I now want to change the models location, for example put them here:
djangoproject
/blog
xxx
/all_models
models.py
From the code point of view, this is pretty trivial, but the I guess there will be problems on the database since all the tables Django and South created are now called blog_posts blog_comments, Django relies on this naming convention and I don't want to lose the data already present in the database.
How to do this?
The easiest thing is not to bother changing the tables at all, but the code. Inside the Meta class of each of your models, put the declaration db_table = "blog_tablename", and Django will find them without problems.
You can solve this in two ways.
The first and easier one is to provide a db_table in Meta class of each of your models. The other is create a migration to apply the change.
As far as I know south doesn't support table rename, so you should do it as a three way migration:
Move de models, and create migration (now you have both tables old and new)
Create a data migration and iterate over the former table, copying objects to later
Remove the former model, and create a migration for it.
You can read a little bit more about the second way in south docs

Django South migrate model file backwards

I'm using South for migrations. I can't seem to work out if South can also be used to amend the models themselves. Upon returning to a previous model state, am I to manually alter the code?
Thanks
South does not modify your models.py. It only alters the database. It is generally used in conjunction with version control software (such as git) that would allow you to revert your models.py to match the south migration.
am I to manually alter the code?
Yes. South altering models code seems for me not like a good idea. Only you know what where exact code changes because of your migration.
And for me, I performed backwards migration couple times and in most cases didn't wanted the model to change to previous state.

What is the use of models attribute in South SchemaMigration class?

In every generated migration files by South manage.py schemamigration, there usually will be a subclass of the south.v2.SchemaMigration. The class would contain forwards() and backwards() methods and also models attribute. How does South use the models attribute?
This is called ORM freezing.
We also use a human-readable format that’s easy to change; since South relies on the frozen models not only for reacreating the ORM but also for detecting changes, it’s really useful to be able to edit them now and again (and also serves as a valuable debugging tool if you attach failing migrations to a ticket).
http://south.aeracode.org/docs/ormfreezing.html

How do I make changes to a model in Django?

How does Django handle changes to my Model? Or, what help does it offer me to do this?
I am thinking of a situation where I have already have published data to my DB which I don't want to lose, but I need to make changes to my data model - for example, adding extra fields to a particular class, changing the types of fields, etc. My understanding is that syncdb won't ever alter tables that already exist in the DB.
For example, let's say I have the following model:
class Person(models.Model):
name = models.CharField(max_length=200)
phone_number=models.CharField(max_length=200)
hair_colour=CharField(max_length=50)
Things I might want to do to Person off the top of my head:
I wish to add an 'age' field.
I realise I want to use IntegerField instead of CharField for phone_number (whether this is a good idea or not, is out of scope...) - assuming it's possible.
I realise that I no longer wish to define hair_colour 'inline' within Person, because several people share the same hair colour - I wish instead to change this to be a foreign key to some other model.
Whilst I can imagine some of these are tough/impossible for the framework to 'guess' exactly what needs to be done to my data if all I do is update the models.py, I can imagine that there might still be some tooling to help enable it - does it exist?
In particular I imagine there must be some good patterns for option 1.
I'm very new to Django and have no experience with any other ORM-type stuff, which I think this is - I've always been a bit suspicious of ORMs, mainly for the reasons above :)
Django itself will not attempt to modify an already created database table. What you are trying to do is typically called "Migration" and there are a couple of different Database Migration tools available for Django.
South
Schema Migrations
Data Migrations
Backwards Migrations
Nash Vegas
Schema Migrations
Data Migrations
Django Evolution
Schema Migrations
Data Migrations (Unknown)
Backwards Migrations (Unknown)
Of the three South is probably the most widely used but they each have different ways of dealing with migrations. You can see more details on the comparison on Django Packages.
Much of what you're asking about can be done with the django project South. You add it as an INSTALLED_APP. Create a baseline, then as your model changes it creates SQL statements to convert your tables and the rows with-in the tables to the new model format.