Ignore invalid foreign for django migrations? - django

I'm migrating an application from an old DB system to django. I've imported a bunch of legacy data. I used a script to convert the table schemas from the old system into Django models, as it had a lots of tables. Then I used another script to write the content of the old db into Django fixtures, which I then imported. That all worked fine, the data is served in the views etc.
However, I now noticed that some ForeignKey in the old system were not properly identified as FK and were simply put in as Char/Int fields into the djando models. So I updated a field from IntegerField to ForeignKey, but that being legacy data I had the following issue:
django.db.utils.IntegrityError: The row in table 'pickings_detpick' with primary key '17170' has an invalid foreign key: pickings_detpick.fk_ent_id contains a value '30223' that does not have a corresponding value in pickings_entpick.id.
So basically, there are a number of (unsure how many yet) foreign key references that point to objects that actually do not exist in the source data (for whatever reason, I don't know the hold system much).
Is there a way that I can simply tell Django to ignore those & set them as null or something? Or do I actually have to comb thru the data & fix them?

Not a long term fix, but on the narrow question to let the constraint slide the db_constraint attribute of the ForeignKey field would work (set it to False).
Not a good idea in production, and the underlying data still needs to be fixed.

Use
db_constraint=False,on_delete=models.SET_NULL,null=True,blank=True
Also if it still gives an error delete the last 1 or few migrations then do makemigrations and migrate it solved my problem.

Related

Django on_delete=CASCADE not working, can't delete parent row using raw SQL [duplicate]

I'm using Django 1.3 with the MySQL 5.5 database backend. My assumption was that Django by default emulates the ON DELETE CASCADE effect for related objects when building the database via syncdb. However, inspecting the database reveals that the ON DELETE property is in fact set to "RESTRICT". Is this a bug? As I'm unable to delete related records I keep getting the IntegrityError message in the djang-admin when deleting an object that has a related object.
Thanks
Django emulates ON DELETE CASCADE in Python -- that's why is doesnt need it set on the database tables. In fact, setting RESTRICT might even make sense, since it means that you can't accidentally delete any related objects without being warned about it in the admin.
In your case, it seems like you may have foreign key constraints set up that Django doesn't know about -- or possibly you are trying to delete through raw SQL; I can't tell from your question.
If the issue is that you can't delete from the admin, or from the ORM, then you need to make sure that your models are defined correctly. django will take care of collecting the related objects and performing the cascade itself.
If the issue is that deletes don't work from raw SQL, then you will either need to manually delete the related objects first, or relax the SQL constraint -- in that case, changing it to cascade may be the right solution.
It would seem that Django 1.3.1 for some reason fails to apply the ON DELETE CASCADE property to the table. It could possibly have something to do with the MySQL-python 1.2.3 interface running on Windows. The only other way to resolve this issue is via custom SQL.
Django does cascade by default. I'm not really sure why you're getting an ON DELETE RESTRICT. Django 1.3 does let you select alternate ON DELETE procedures (using the on_delete kwarg when defining a field), and it's possible that if you inherited the codebase, someone might have done that previously and then removed it from the code, but neglected to update the database.
I would suggest altering the column manually to set it back to ON DELETE CASCADE. And simply move on from there. Like I said, this is something that the developer has to tell Django not to do; it cascades by default.

How to replace a foreignkey with another using a migration

I'd like to replace an existing ForeignKey pointing at my User model with one pointing at a profile model.
The change in the model is:
created_by=models.ForeignKey(settings.AUTH_USER_MODULE)
To:
created_by=models.ForeignKey(settings.PROFILE_MODEL)
The auto-generated migration looks like (with constants subbed in):
migrations.AlterField(
model_name=MODEL,
name='created_by',
field=models.ForeignKey(to=settings.PROFILE_MODEL),
preserve_default=True,
),
I also have ManyToManyFields to deal with as well. What I have in my head is I'd like a function to run on each MODEL object to resolve the user object to the profile object. How would I go about doing this?
The relationship between user and profile is (and vice versa):
User.profile = Profile
Edit: Forgot to mention, if the auto-generated migration is run you get the following error:
ValueError: Lookup failed for model referenced by field
APP1.MODEL.created_by: APP2.PROFILE_MODEL
As I understand now you want to migrate only our app without expecting anything to be changed to the global auth User model. Then it's easy. Migrations work nice with symbolic settings names.
I tried it with Django 1.7. It is possible to switch between settings.AUTH_USER_MODEL and settings.PROFILE_MODEL back and forth without any problem. A migration can be created and applied after every change. The tested model had also a ManyToManyField and mutual relationships between User and Profile.
I see you have APP1 and APP2. Maybe you make migrations for both and they are circular dependent so that a part of other application migration should be applied before the current one migration can be completely applied and vice versa. It can be simplified by spliting a change to more smaller and making automatic migrations after every change so that they are less dependent. A OneToOneField is better than two mutual foreign keys and its reverse relation is even so useful. A foreign key can be changed temporarily to IntegerField(null=True) in the worst case in order to simplify data migration. It is really viable more or less nice.
The question looked nice initially, but the problem should be better specified to be reproducible.
Edited by removing the original text after reading information in comments:

Django not setting MySQL ON DELETE = CASCADE

I'm using Django 1.3 with the MySQL 5.5 database backend. My assumption was that Django by default emulates the ON DELETE CASCADE effect for related objects when building the database via syncdb. However, inspecting the database reveals that the ON DELETE property is in fact set to "RESTRICT". Is this a bug? As I'm unable to delete related records I keep getting the IntegrityError message in the djang-admin when deleting an object that has a related object.
Thanks
Django emulates ON DELETE CASCADE in Python -- that's why is doesnt need it set on the database tables. In fact, setting RESTRICT might even make sense, since it means that you can't accidentally delete any related objects without being warned about it in the admin.
In your case, it seems like you may have foreign key constraints set up that Django doesn't know about -- or possibly you are trying to delete through raw SQL; I can't tell from your question.
If the issue is that you can't delete from the admin, or from the ORM, then you need to make sure that your models are defined correctly. django will take care of collecting the related objects and performing the cascade itself.
If the issue is that deletes don't work from raw SQL, then you will either need to manually delete the related objects first, or relax the SQL constraint -- in that case, changing it to cascade may be the right solution.
It would seem that Django 1.3.1 for some reason fails to apply the ON DELETE CASCADE property to the table. It could possibly have something to do with the MySQL-python 1.2.3 interface running on Windows. The only other way to resolve this issue is via custom SQL.
Django does cascade by default. I'm not really sure why you're getting an ON DELETE RESTRICT. Django 1.3 does let you select alternate ON DELETE procedures (using the on_delete kwarg when defining a field), and it's possible that if you inherited the codebase, someone might have done that previously and then removed it from the code, but neglected to update the database.
I would suggest altering the column manually to set it back to ON DELETE CASCADE. And simply move on from there. Like I said, this is something that the developer has to tell Django not to do; it cascades by default.

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.

Django syncdb ignore a specific model

Is there a way to make syncdb ignore a specific table?
I decided to declare a M2M twice because from one model I wanted it to appear as a simple M2M that works with filter_horizontal. In another I added a through field and show it in an inline. I used db_table to make the simple one use the same through table. This all works well usually, BUT in syncdb I always get an error the first run because it thinks it must create the table twice, but it already exists the second time. Not a problem until I get to testing which creates the test database and fails. Maybe I'm just an idiot for using this hack. Is there anyway to make Django ignore this error or specify not to create the m2m through table the second time?
I ended up using the Model Meta option managed = False to make syncdb ignore the model. Then used initial sql data to create the sql for the table by hand. If I could tell django that only the manytomany field was not to be managed I wouldn't need to write custom SQL, but this can't be done.