How can I patch the User model while keeping existing data? - python

I have a big Django application, currently trying to upgrade from 1.6 to 1.7 (there's been attempts to upgrade straight to 1.11, but it was too much trouble, so my plan is to do it one minor at a time).
I'm following the Upgrade from South instructions, and deleted all previous migrations, but I can't get makemigrations to work. The current problem is that the auth.User model has been patched to include two new fields:
User.add_to_class('profile',
models.ForeignKey('access.Profile', null=True, blank=True,
related_name='user_foreignkey'))
User.add_to_class('profiles',
models.ManyToManyField('access.Profile', null=True,
blank=True))
This patch was made in a separate app. If I just leave it where it is, I get the following error when running python manage.py makemigrations:
ValueError: Lookup failed for model referenced by field auth.User.profiles:
access.Profiles
I tried moving the add_to_class calls to the same file where Profile is defined, (after the definition), but got the same error. I also tried changing the syntax from 'access.Profile' to Profile, to no effect. Is there something else that could make this work?
If not, since I'm adding fields to the model, I figure the correct approach would be extend the AbstractUser model, as suggested by this guide. The problem with this is that the new initial migration will create a table access_user instead of using the existing auth_user. Would it be safe to simply rename auth_user to access_user and fake the migration?
Any other suggestions on how to overcome this with the least refactoring possible (management always thinks there are more urgent things than the upgrade) are welcome.

tl, dr; I removed auth migrations and ran makemigrations again, that seems to have solved the problem.
I had decided to give option 2 a try. I removed the add_to_class patches, created a new class User(AbstractUser) with the new fields, removed all the existing migrations and ran makemigrations again. I got the exact same error, which made no sense because there was no longer any code relating auth.User to Profile, so I decided to investigate auth migrations. I ran
$ python migrate --list settings=settings.mysettings
and it showed a suspicious migration for auth, with yesterday's date, probably when I first tried to make migrations.
Tutorials on "how to reset all migrations" do not mention third-party installed apps, but thanks to this thread I knew where Django stored the auth migrations, so I removed both of them (the initial and the suspicious one) and reordered the INSTALLED_APPS so that access is now before django.contrib.auth. Then ran makemigrations again, and it got through access and auth migrations successfully.
I'm now getting other problems with migrations in other apps, but they don't seem to be related with this.
It might be nice to have a more intuitive way to reset all existing migrations, not only those from your repo. But then again, I don't think the add_to_class patches are the proper way to do what we wanted.

Related

Should I avoid using models in django migrations?

I am working on an existing Django project that contains migration code like:
someFluffyModel.objects.all().delete()
or
someModel = SomeModel(....)
someModel.save()
Now wherever there is such code and newer migrations change the schema that reflect the current version of the model, there is an issue in applying migrations from scratch.
As I understand the reason is that the model used in the migration doesn't reflect the model used in the migration at that point in time. As I have found fixtures can help in loading data but how about deletion?
Is the preferred way to manually delete data from the database?
Sorry forgot to answer my own old question it's been years now but just in case anybody is curious in your migrations you should always be using historical models. The reason is that you get the model at a point in time(reconstructed incrementally base on schema migrations).
def forwards_func(apps, schema_editor):
# We get the model from the versioned app registry;
# if we directly import it, it'll be the wrong version
Country = apps.get_model("myapp", "Country")
This way if you try to re-run your migrations at some point in the future with model schema x'' old migrations will be run using x' and x depending on their dependencies.
Avoid importing models to your migrations directly at any cost.
It is always important to be able to rer-run you migrations since that allows you to migrate forwards backwards between your environments roll back faulty deployments and above all run your tests. If you are doing it wrong your tests will fail at some point when you'll get to schema x' and you'll have to follow the correct approach mentioned above to fix them.
Thanks to #Daniel Roseman for giving me some pointers that day.

Django skips particular migration(No Migrations to apply)

I am working on an app at Django 1.9
I created altered one field from User model (max_length to 120 from 40).
I know the migration has not run and i can see that it is skipped obviously.
I can't seem to understand why this is happening.
I made sure that the dependencies are in place as well.
Things i tried:
1- Verified that the database does not say it as run(django_migrations table):
See there is no 0021_alter_user_lms_user_id
2- i check if django is able to see migration file:
I am very surprised with this outcome.
I cannot purge my migrations nor the database because this is a deployed app with data.
Any help is appreciated
Note: I checked all related questions i could find before posting this question.
I fixed it myself and hoping this helps others experiencing same or similar issue with Django.
It seems like Django does not just check whether a migration has run by file name but also it pays attention on the order of the file by the leading numbers in filenames(At least in my experience).
History of steps:
git branch a: creates migrations for 0021_alter_user_lms_user_id and has not been merged into master yet.
git branch b: created migration for 0022_toolconsumer_is_vericite_enabled (thinking i should follow the order and manually prefix file name with 0022_)
Now at this point i merge git branch b into master and run migrations.
So now when i merge git branch a into master and want to run migrations, django sees file but since 0022_ is supposingly after 0021_, skips the file instead actually checking whether it is applied to db.
Fix: I basically renamed file name from 0021_alter_user_lms_user_id to 0023_alter_user_lms_user_id(don't forget to update dependencies ) and ran ./manage.py migrate and worked with no issues. See the image.
Hope this helps somebody.

Edit database outside Django ORM

If one is using Django, what happens with changes made directly to the database (in my case postgres) through either pgadmin or psql?
How are such changes handled by migrations? Do they take precedence over what the ORM thinks the state of affairs is, or does Django override them and impose it's own sense of change history?
Finally, how are any of these issues effected, or avoided, by git, if at all?
Thanks.
You can exclude a model completely from the django migrations, and then you are responsible to adjust the schema to the django code (or the django code to the existing schema):
class SomeModel(models.Model):
class Meta:
managed = False
db_table = "some_table_name"
name = models.Fields....
Note that you can't have it both ways, so migrations are preferred when possible. You can always define a custom SQL migration, that will save the need for external changes. However, sometimes you do need to handle the schema elsewhere instead of migrations, and then use managed=False
The migrations system does not look at your current schema at all. It builds up its picture from the graph of previous migrations and the current state of models.py. That means that if you make changes to the schema from outside this system, it will be out of sync; if you then make the equivalent change in models.py and create migrations, when you run them you will probably get an error.
For that reason, you should avoid doing this. If it's done already, you could apply the conflicting migration in fake mode, which simply marks it as done without actually running the code against the database. But it's simpler to do everything via migrations in the first place.
git has no impact on this at all, other than to reiterate that migrations are code, and should be added to your git repo.

Related model cannot be resolved

I am using Django 1.8b1
There are two models in two apps called accounts and products
products/models.py
class ChecklistEnterpriseType(models.Model):
checklist_enterprise_type = models.CharField('Type of Enterprise', max_length=50, choices=zip(ENTERPRISE_CHOICES, ENTERPRISE_CHOICES))
def __unicode__(self):
return self.checklist_enterprise_typ
And the another model is
accounts/models.py
class sample(models.Model):
enterprise_type = models.ForeignKey(ChecklistEnterpriseType, related_name='enterprise_type')
def __unicode__(self):
return self.enterprise_type
When I do python manage.py makemigrations, it will add the migration file. But when I do python manage.py migrate it raises me the error like:
raise ValueError('Related model %r cannot be resolved' % self.rel.to)
ValueError: Related model u'products.ChecklistEnterpriseType' cannot be resolved
How can I resolve this.
Appreciated the answers :)
A very delayed response... but I just had a similar issue that was very hard to track down, but eventually did, so am putting a pointer here in case anyone else gets hit by it. I was adding testing to a several year old Django webapp, and found that ./manage.py test was failing. I had never run ./manage.py migrate on an empty database!
At some stage in the early days of Django 1.7 migrations were generated that had failed circular dependency detection, so you could update from a newer version but not the first migrations. See https://code.djangoproject.com/ticket/22319 for the bug report.
I still had to work out how to fix it without throwing away all my migrations and generating them fresh.
So to fix, I went through all the migrations (it was only 5 affected files). Some models were required by earlier migrations, but they weren't included due to individual fields depending on later migrations. So I brought the whole migrations.CreateModel for the model back to an earlier migration, but took those fields and used migrations.AddField in the later migration (where the model had been put originally).
Hopefully that explains it, but if anyone runs into this issue sometime in the future, feel free to comment if it needs further elaboration.
I think this line:
checklist_enterprise_type = models.CharField('Type of Enterprise', max_length=50, choices=zip(ENTERPRISE_CHOICES, ENTERPRISE_CHOICES))
Should Be:
checklist_enterprise_type = models.CharField(verbose_name='Type of Enterprise', max_length=50, choices=zip(ENTERPRISE_CHOICES, ENTERPRISE_CHOICES))

What migration order does South follow across different apps?

I've recently begun using South for migrations in my Django project. All was going well until recently when I ran into a peculiar issue.
I have two apps in my project, say, App-A and App-B. A model in App-A has a foreign key to a model in App-B. When I've been trying to build my system, I ran syndb which created all the auth_ and the south_ tables. Then I ran migrate which threw up errors. When it tried creating the model from App-A, which referenced a model from App-B, the model App-B wasn't migrated/created as yet and therefore the error.
In order to resolve this, I had to manually migrate App-B first and then App-A. Am i doing something wrong here? How is South supposed to know the migration order across apps?
Thanks.
This explained it https://south.readthedocs.io/en/latest/dependencies.html.
Migrations for apps are nice ‘n all, but when you start writing a
large project, with a lot of apps, you realise you have foreign key
relationships between apps and working out what order migrations would
need to be applied in for each app is just painful.
Luckily, we also had this problem, so South has a dependency system.
Inside a migration, you can declare that it depends on having another
app having run a certain migration first; for example, if my app
“forum” depends on the “accounts” app having created its user profile
table, we can do:
# forum/migrations/0002_post.py class Migration:
depends_on = (
("accounts", "0003_add_user_profile"),
)
def forwards(self):
Then, if you try and migrate to or beyond 0002_post in the forum app, it will first make sure accounts is migrated at least
up to 0003_add_user_profile, and if not will migrate it for you.
Dependencies also work in reverse; South knows not to undo that
0003_add_user_profile migration until it has undone the 0002_post
migration.
You can have multiple dependencies, and all sorts of wacky structures;
there are, however, two rules:
No circular dependencies (two or more migrations depending on each
other) No upwards dependencies in the same app (so you can’t make
0002_post in the forum app depend on 0003_room in the same app, either
directly or through a dependency chain.
South migrates apps in the order they appear in the INSTALLED_APPS tuple in settings.py. So just make sure App-B comes before App-A in your settings.py, and it should work :)

Categories

Resources