Django addField ForeignKey during migrations create unusable constraint name - django

Env: Django 1.8.11 + Postgis
I'm adding some ForeignKeys on a MyModel.
The models pointed are in another schema ("cartography").
makemigrations
no errors
migrate
One error. Can't create the constraint because the generated name.
But I'm adding 10 fields, really similar between them. Only one is giving that stupid error.
I can't specify the constraint name anywhere.
class myModel(models.Model)
zps_calculated = models.ForeignKey( Cartography_zps, verbose_name="zps_calcolato", null=True, blank=True, on_delete=models.SET_NULL)
zsc_sic_sir_calculated = models.ForeignKey( Cartography_zsc_sic_sir, verbose_name="zsc_sic_sir_calcolato", null=True, blank=True, on_delete=models.SET_NULL)
manyothersdata = "xxx"
That is the slice of code generated from sqlmigrate (to inspect the code the migration generate).
As you see the name of the constraint is the error.
1 on 10 fields is giving the error
CREATE INDEX "segnalazioni_f38ba181" ON "segnalazioni" ("zps_calculated_id");
ALTER TABLE "segnalazioni" ADD CONSTRAINT "se_zps_calculated_id_6844dce0603174b2_fk_"cartography"."zps"_id" FOREIGN KEY ("zps_calculated_id") REFERENCES "cartography"."zps" ("id") DEFERRABLE INITIALLY DEFERRED;
CREATE INDEX "segnalazioni_eb52e53f" ON "segnalazioni" ("zsc_sic_sir_calculated_id");
ALTER TABLE "segnalazioni" ADD CONSTRAINT "cc6ce48808e3a5292779a9787d21e5ad" FOREIGN KEY ("zsc_sic_sir_calculated_id") REFERENCES "cartography"."zsc_sic_sir" ("id") DEFERRABLE INITIALLY DEFERRED;
That is the name giving the error: "se_zps_calculated_id_6844dce0603174b2_fk_"cartography"."zps"_id"
I think should be something like:
"6844dce0603174b2..."
the model NOT giving the error:
class Cartography_zsc_sic_sir(models.Model):
id = models.AutoField(primary_key=True)
slug = models.CharField(max_length=40, blank=True, null=True)
nome = models.CharField(max_length=60, blank=True, null=True)
the_geom = models.MultiPolygonField(srid=23032, blank=True, null=True )
objects = models.GeoManager()
class Meta:
managed = False
db_table = '"cartography"."zsc_sic_sir"'
verbose_name = 'Cartography - zsc_sic_sir'
verbose_name_plural = 'Cartography - zsc_sic_sir'
ordering = ["id","slug"]
def __unicode__(self):
return self.nome
that is the model giving the error:
class Cartography_zps(models.Model):
id = models.AutoField(primary_key=True)
slug = models.CharField(max_length=40, blank=True, null=True)
the_geom = models.MultiPolygonField(srid=23032, blank=True, null=True )
objects = models.GeoManager()
class Meta:
managed = False
db_table = '"cartography"."zps"'
verbose_name = 'Cartography - ZPS'
verbose_name_plural = 'Cartography - ZPS'
ordering = ["id","slug"]
def __unicode__(self):
return self.slug
Going further I'm investigating in Django code, backwards.
The
' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s)%s;' %
is in
/django/db/backends/base/creation.py row 180
using that
qn = self.connection.ops.quote_name
that SHOULD be the %s constraint name value:
qn(truncate_name(r_name, self.connection.ops.max_name_length()))
Anyone have an hint to help me?
I'm gonna look what qn does.
https://github.com/django/django/releases/tag/1.8.11

The problem was the attribute name (but I still dunno why):
zps_calculated = models.ForeignKey( Carto...
I renamed it to
zpsasd_calculated = models.ForeignKey( Carto
and the generated constraint name changed to (sqlmigrate):
a326518e5e22b0c2c1251e5bbb331adb
Wow!
Renamed the attribute zpsasd_calculated to zps_calculated, with another migration.
Worked.
Next time I will migrate with custom SQL
https://www.ralphlepore.net/custom-foreign-key-constraints-with-django/

Related

Django: IntegrityError null value violates not-null constraint

In my django app, there is something strange that's happening & i'm not understanding.
I have two different tables (employeeProfile & purchaserShippingDetail) each has a field with the relation OneToOneField but with the 1st table (employeeProfile) in the field user that uses OneToOneField i can pass a string representation say Michael using api & i don't get an error but in my 2nd table that has similar structure when i add a string representation to i get
IntegrityError at /api/clients/shipping/
null value in column "owner_id" violates not-null constraint
1st Table model (works fine)
class employeeProfile(models.Model):
image = models.ImageField(default='default.png',upload_to='employee_photos/%Y/%m/%d/')
user = models.OneToOneField(CustomUser, on_delete=models.CASCADE, related_name="employee_profile")
phone_no = models.CharField(max_length=10, unique=True)
def __str__(self):
return self.user.name
2nd Table Model (The one that throws the "owner_id" violates not-null constraint error)
class purchaserShippingDetail(models.Model):
frequent_customer = models.BooleanField(default=False)
owner = models.OneToOneField(Purchaser, on_delete=models.CASCADE, related_name="purchaser_shipping")
address = models.CharField(max_length=12, blank=True)
zip_code = models.CharField(max_length=12, blank=True)
location = models.CharField(max_length=255)
def __str__(self):
return self.owner.name
Purchaser Model
class Purchaser(models.Model):
name = models.CharField(max_length=50)
phone = models.CharField(max_length=20, unique=True)
email = models.EmailField(max_length=255, unique=True, blank=True)
data_added = models.DateField(default=datetime.date.today)
def __str__(self):
return self.name
serializer for purchaserShippingDetail model
class purchaserShippingDetailSerializer(serializers.ModelSerializer):
owner = serializers.StringRelatedField(read_only=True)
class Meta:
model = purchaserShippingDetail
fields = '__all__'
Views.py for purchaserShippingDetail model
class purchaserShippingDetailsListCreateView(ListCreateAPIView):
serializer_class = purchaserShippingDetailSerializer
queryset = purchaserShippingDetail.objects.all()
EDIT: Added Purchaser model table
Could you please post the Purchaser model as well? There is a referenced field owner_id that we can't see in your post, which will explain more.
Have you added the owner field in a recent migration? It could be that you are adding a non-nullable field to a Table with existing rows, making those rows fail to satisfy the non-nullable condition.
You cannot add a default value on a OneToOneField so in that case you have to first add the field as null=True.
Then create an empty migration file to instantiate all rows on that table so no rows have a null value. Normally you do this by manage.py makemigrations app_name --empty.
That file could look something like
from django.db import migrations
def instantiate_owner(apps, schema_editor):
purchaserShippingDetail = apps.get_model("appname", "purchaserShippingDetail")
Purchaser = apps.get_model("some_other_app", "Purchaser")
for detail in purchaserShippingDetail.objects.all():
owner = Purchaser.objects.get(some_unique_criteria=detail.unique_criteria)
detail.owner = owner
detail.save()
class Migration(migrations.Migration):
dependencies = [
...,
]
operations = [
migrations.RunPython(instantiate_owner),
]
After that is complete you can remove the null=True in your model and make another migration.

Django Models relation with primary key add extra "_id" to the column

These are my two models, when I try to open City page on Django I get an error: "column city.country_id_id does not exist". I don't know why python adds extra _id there.
class Country(models.Model):
country_id = models.CharField(primary_key=True,max_length=3)
country_name = models.CharField(max_length=30, blank=True, null=True)
class Meta:
managed = False
db_table = 'country'
class City(models.Model):
city_id=models.CharField(primary_key=True,max_length=3)
city_name=models.CharField(max_length=30, blank=True, null=True)
country_id = models.ForeignKey(Country, on_delete=models.CASCADE)
class Meta:
managed = False
db_table = 'city'
Because if you construct a foreign key, Django will construct a "twin field" that stores the primary key of the object. The foreign key itself is thus more a "proxy" field that fetches the object.
Therefore you normally do not add an _id suffix to the ForeignKey:
class City(models.Model):
city_id = models.CharField(primary_key=True,max_length=3)
city_name = models.CharField(max_length=30, blank=True, null=True)
country = models.ForeignKey(Country, on_delete=models.CASCADE)
class Meta:
managed = False
db_table = 'city'
It however might be better for unmanaged tables, to specify a db_column=… parameter [Djang-doc] in the ForeignKey:
class City(models.Model):
city_id = models.CharField(primary_key=True,max_length=3)
city_name = models.CharField(max_length=30, blank=True, null=True)
country = models.ForeignKey(Country, db_column='country_id', on_delete=models.CASCADE)
class Meta:
managed = False
db_table = 'city'
With this parameter you make it explicit how the column is named at the database side.
this is due to Django's behind the scenes magic.
The fields documentation is very clear about that and I highly recommend you read the Foreign Key section in the link below:
https://docs.djangoproject.com/en/3.0/ref/models/fields/#django.db.models.ForeignKey
Basically, when you want to access the Country reference in the if a City instance, you would do it like this:
city.country_id
I also recommend another naming convention for your Foreign Key fields. Instead of <modelname>_id = models.ForeignKey... just call it <modelname> = models.ForeignKey...
Hope this helps, happy coding

Django autofixture generating test data with foreign key

I have using django-autofixture to generate some random data for my database instance. My model is as follows:
class DummyModel(models.Model):
name = models.CharField(max_length=100)
description = models.CharField(max_length=150, blank=True)
time_points = models.PositiveIntegerField()
more_text = models.CharField(max_length=100, blank=True)
image_type = models.ForeignKey(ImageTypeModel, null=False, blank=False,
default='')
class Meta:
db_table = "dummy"
So, I have a foreign key which should always be present and it cannot be NULL. I also have created instances for this ImageTypeModel using the fixtures functionality in Django. I deleted everything and migrated fresh and verified that the ImageTypeModel database table exists and is populated. The ImageTypeModel is defined as:
class ImageTypeModel(models.Model):
name = models.CharField(max_length=100)
dims = models.IntegerField()
class Meta:
db_table = "imagetypes"
def __str__(self):
return self.name
def __unicode__(self):
return self.name
Now I attempt to create some random data using the command:
python manage.py loadtestdata myapp.DummyModel:30
However, this returns me this error:
django.db.utils.IntegrityError: NOT NULL constraint failed: dummy.image_type_id
I am at a loss as to why it should be and have tried deleting/replicating the project to a fresh location but no go.

Django get_or_create trying to create row, throwing IntegrityError?

I'm working in Django 1.7 and Postgres, and using the ORM to create some new rows. I am using get_or_create as follows:
p, created = Practice.objects.get_or_create(
code=row[1],
name=row[2],
address1=row[3],
address2=row[4],
address3=row[5],
address4=row[6],
postcode=row[7]
)
But when I try to run this I get:
django.db.utils.IntegrityError: duplicate key value violates unique constraint
DETAIL: Key (code)=(A82057) already exists
What's this about? I thought the point of get_or_create was to only try to create new rows if they didn't already exist.
My model looks like this:
class Practice(TimeStampedModel):
code = models.CharField(max_length=6, primary_key=True, db_index=True)
name = models.CharField(max_length=200)
address1 = models.CharField(max_length=200, null=True, blank=True)
address2 = models.CharField(max_length=200, null=True, blank=True)
address3 = models.CharField(max_length=200, null=True, blank=True)
address4 = models.CharField(max_length=200, null=True, blank=True)
postcode = models.CharField(max_length=9, null=True, blank=True)
def __str__(self):
return self.name
class Meta:
app_label = 'frontend'
ordering = ['name']
Is it something to do with the fact that I've set a manual primary key? I can't see anything in the Django docs about this restriction.
get_or_create attempts to do a get with all of the parameters you pass, not just the PK. So if there is an object with a matching PK but a different postcode, for example, the get will fail so a create will be attempted - but, since you have a manual PK, it will try to create a duplicate one using the data you have passed.
Generally speaking using a non-autoincrementing PK is a bad idea. But if you are just trying to look up against the PK only, use the defaults argument:
p, created = Practice.objects.get_or_create(
code=row[1],
defaults={
'name': row[2],
'address1': row[3],
'address2': row[4],
'address3': row[5],
'address4': row[6],
'postcode': row[7]
})

Django ForeignKey TemplateSyntaxError and ProgrammingError

This is are my models i want to relate. i want for collection to appear in the form of occurrence.
class Collection(models.Model):
id = models.AutoField(primary_key=True, null=True)
code = models.CharField(max_length=100, null=True, blank=True)
address = models.CharField(max_length=100, null=True, blank=True)
collection_name = models.CharField(max_length=100)
def __unicode__(self):
return self.collection_name
class Meta:
db_table = u'collection'
ordering = ('collection_name',)
class Occurrence(models.Model):
id = models.AutoField(primary_key=True, null=True)
reference = models.IntegerField(null=True, blank=True, editable=False)
collection = models.ForeignKey(Collection, null=True, blank=True, unique=True),
modified = models.DateTimeField(null=True, blank=True, auto_now=True)
class Meta:
db_table = u'occurrence'
Every time i go to check the Occurrence object i get this error
TemplateSyntaxError at /admin/hotiapp/occurrence/
Caught an exception while rendering: column occurrence.collection_id does not exist
LINE 1: ...LECT "occurrence"."id", "occurrence"."reference", "occurrenc..
And every time i try to add a new occurrence object i get this error
ProgrammingError at /admin/hotiapp/occurrence/add/
column occurrence.collection_id does not exist
LINE 1: SELECT (1) AS "a" FROM "occurrence" WHERE "occurrence"."coll...
What am i doing wrong? or how does ForeignKey works?
The problem is that you have not updated your database table definition since adding the ForeignKey. syncdb doesn't do this for you, as the documentation clearly states. You need to update the SQL manually, or use a tool like South.
Are you sure you mean
collection = models.ForeignKey(Collection, null=True, blank=True, unique=True),
Nullable and Unique? This may not be possible in some databases.
Generally, the unique constraint doesn't seem to make much sense here.
Are you trying to force a 1-to-1 relationship? Use the OneToOneField. http://docs.djangoproject.com/en/1.1/ref/models/fields/#django.db.models.OneToOneField