Django - Foreign key constraint fails on delete with through model - mysql

I am working on a REST api using Django Rest and one endpoint involves deleting a Contact model, which can have multiple Addresses associated with it via ContactAddress through model.
The Contact model looks like this:
class Contact(AuditModel):
contact_id = models.AutoField(primary_key=True)
address = models.ManyToManyField('Address', through='ContactAddress')
name_first = models.CharField(max_length=100)
name_last = models.CharField(max_length=100)
ContactAddress looks like this:
class ContactAddress(models.Model):
contact = models.ForeignKey('Contact', on_delete=models.CASCADE)
address = models.ForeignKey('Address', on_delete=models.CASCADE)
is_billing = models.BooleanField(null=True, default=False)
is_shipping = models.BooleanField(null=True, default=False)
And the Address model looks like this:
class Address(AuditModel):
address_id = models.AutoField(primary_key=True)
postcode = models.CharField(max_length=30, blank=True, null=True)
region = models.CharField(max_length=100, blank=True, null=True)
street_line_1 = models.CharField(max_length=500, blank=True, null=True)
street_line_2 = models.CharField(max_length=500, blank=True, null=True)
street_line_3 = models.CharField(max_length=500, blank=True, null=True)
And when trying to delete the contact like so with contact.delete() I get the following MySQL error:
django.db.utils.IntegrityError: (1451, 'Cannot delete or update a parent row: a foreign key constraint fails (`mnghub`.`contact_addresses`, CONSTRAINT `contact_addresses_contact_id_cadc11a0_fk_contacts_contact_id` FOREIGN KEY (`contact_id`) REFERENCES `contacts` (`contact_id`))')
I get this error despite the contact having no addresses associated with it. I assume the constraint is because the relationship is many-to-many, but I want to be able to delete related models if they are only related with one object

Related

Django - filtering on foreign key on third table

I'm trying to filter a table in Django based on the value of a particular field of a ForeignKey which is a filed of a third table ForignKey.
class A(models.Model):
user_type = models.CharField(blank=True, max_length=32)
description = models.CharField(blank=True,max_length=512)
class B(models.Model):
user = models.OneToOneField(User, on_delete=models.PROTECT)
name = models.CharField(max_length=32, blank=True)
surname = models.CharField(max_length=32, blank=True)
user_type = models.ForeignKey(A,on_delete=models.SET_NULL, null=True)
class C(models.Model):
user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
user_profile = models.ForeignKey(B,on_delete=models.SET_NULL, null=True)
test = models.CharField(blank=False,max_length=512)
here is the query that I wish to make :
I want to query on the C and find the user_type_id on the B then filter user_type value on A
something like this (just for showing what I want):
models.C.objects.filter(test="test").filter(B__user_type_id__A__user_type = 1)
final result:
I want to get all of the data that test="test" in table C and user_type = 1 in table A
Since the user_type field on the A model is a CharField. So you can not filter on a number. You can however filter on a value of that user_type field:
C.objects.filter(test='test', b__user_type__user_type='my_user_type_value')
Or you can filter on the primary key of the A object:
C.objects.filter(test='test', b__user_type_id=1)

How to keep original ID using UUID as primary key in Django RF project?

I'd like to use two different primary keys in my DRF database app. By default Django "create" id as PK but when I'm trying to define new field in model (uuid = models.UUIDField (primary_key=True, default=uuid.uuid4, editable=False), default id field is not defined (in DB exist only uuid).
How can I initialize both of them?
I can mention that I didn't define id field in my model because it is (or should be - as I suppose) adding by DRF.
class Store(models.Model):
uuid = models.UUIDField(primary_key=True, default=uuid.uuid4,
editable=False)
name = models.CharField(max_length=100, blank=False)
url = models.URLField(max_length=300, blank=False)
country = models.CharField(max_length=100, blank=True)
Primary key
In the relational model of databases, a primary key is a specific choice of a minimal set of attributes (columns) that uniquely specify a tuple (row) in a relation (table).
So, you can either use default primary key id or uuid (your choice).
If you want both then use unique=True instead.
class Store(models.Model):
uuid = models.UUIDField(unique=True, default=uuid.uuid4, editable=False)
name = models.CharField(max_length=100, blank=False)
url = models.URLField(max_length=300, blank=False)
country = models.CharField(max_length=100, blank=True)
For your case you can change your model as
from django.db.models.fields import AutoField
from django.db.models.fields import checks
from django import models
class AutoFieldNonPrimary(AutoField):
def _check_primary_key(self):
if self.primary_key:
return [
checks.Error(
"AutoFieldNonPrimary must not set primary_key=True.",
obj=self,
id="fields.E100",
)
]
else:
return []
class Store(models.Model):
id = models.AutoFieldNonPrimary(unique=True)
uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
name = models.CharField(max_length=100, blank=False)
url = models.URLField(max_length=300, blank=False)
country = models.CharField(max_length=100, blank=True)

Django add field to query set

Hi i have 3 models in my django projects, when user send request i have his dealer_id i need return query set with info about material from Material table and for each row add discount_percent from last model where dealer_id = current dealer_id and row id. Please help me if you have answer.
models
class Material(models.Model):
id = models.AutoField(primary_key=True)
color = models.IntegerField()
name = models.CharField(max_length=100)
material_width = models.IntegerField()
price = models.BigIntegerField(default=0)
class Dealer(models.Model):
id = models.AutoField(primary_key=True)
dealer_name = models.CharField(max_length=100)
dealer_phone = models.CharField(max_length=13, unique=True)
dealer_email = models.CharField(max_length=150, null=False, unique=True)
dealer_firm_name = models.CharField(max_length=100, null=True)
dealer_address = models.CharField(max_length=100, null=True)
dealer_unp = models.CharField(max_length=9, null=True)
dealer_amount = models.FloatField(default=0.0)
user_id = models.BigIntegerField(unique=True)
class MaterialDealerPrice(models.Model):
id = models.AutoField(primary_key=True)
dealer_id = models.BigIntegerField(null=False)
material_id = models.BigIntegerField(null=False)
discount = models.FloatField(null=True, default=0.0)
This looks like a set of models that were automatically created by running inspectdb. You should always treat that output as a first draft; there is a lot that needs to be done manually to tidy it up.
Firstly, your MaterialDealerPrice model needs to have foreign keys to Dealer and Material:
class MaterialDealerPrice(models.Model):
dealer = models.ForeignKey('Dealer', null=False)
material = models.ForeignKey('Material', null=False)
discount = models.FloatField(null=True, default=0.0)
Secondly, you should recognise that this model is in fact the through table of a many-to-many relationship.
class Material(models.Model):
...
dealers = models.ManyToManyField('Dealer', through='MaterialDealerPrice')
Now, you should be able to follow these relationships in your query. Unfortunately your question is not clear enough to know what you actually want to do; you should give an example of the desired output.
Annotate can be used for this purpose. https://docs.djangoproject.com/en/1.11/topics/db/aggregation/

How to create a table with non-unique id and have it as foreign key in another table?

I have the following tables in models.py:
class Part(models.Model):
partno = models.CharField(max_length=50, unique=True)
partdesc = models.CharField(max_length=50, default=None, blank=True, null=True)
class Price(models.Model):
part = models.ForeignKey(Part, on_delete=models.CASCADE, null=True)
supplier = models.ForeignKey(Supplier, on_delete=models.CASCADE)
qty = models.IntegerField(default=1)
price = models.DecimalField(max_digits=9, decimal_places=2)
currency = models.ForeignKey(Currency, on_delete=models.CASCADE)
datestart = models.DateTimeField(auto_now_add=True, blank=False, null=False)
class Meta:
unique_together = (('supplier', 'part'),)
This is properly working. The problem is I have many part numbers which are their replacements. For example part 1001-01, 1001-02, 1001-03 are all the same part. Still, I have all of them in my Part table.
I need to match them in another table, so I don't need to enter price for each of them separately. There must be a unique key representing all of these three items.
Question: How do I setup a "part number match table" and have a foreign key to this table in my Price table?
(Rest is optional to read which are my opinions/problems so far, might help though)
1: I tried to setup the table like this:
class PartMatch(models.Model):
id = models.IntegerField(primary_key=True, unique=False, null=False, db_index=True)
part = models.ForeignKey(Part, unique=False, on_delete=models.CASCADE)
I don't get an error while migrating but when I try to use the same id for PK, it doesn't allow me.
2: I left the pk alone and tried to setup another field to match parts:
class PartMatch(models.Model):
part = models.ForeignKey(Part, on_delete=models.CASCADE)
partmatchid = models.IntegerField(null=True, unique=False, db_index=True)
I don't get any error while migrating but when I try to use partmatchid as a foreign key in my Price table like this:
partmatch = models.ForeignKey(PartMatch, to_field="partmatchid",
db_column="partmatchid",
on_delete=models.CASCADE)
I get an error saying foreign key must be unique while migrating.
Well in this case I am out of solutions. I wonder how you guys handle this?
Your Part model can have a foreign key to PartMatch, not the other way around.
Your model can be Part *<-->1 PartMatch and PartMatch 1<-->1 Price
For example:
class Price(models.Model):
price = models.DecimalField(max_digits=9, decimal_places=2)
class PartMatch(models.Model):
price = models.OneToOneField(Price, primary_key=True)
class Part(models.Model):
partno = models.CharField(max_length=50, unique=True)
partMatch = models.ForeignKey(PartMatch)
If you want to get all parts with some price, some_price.partmatch.part_set.all() will do the job.

Django Admin ManyToMany error

I'm using the the built in django admin site to save instances of a model that has a ManyToMany field. If I save, not update, a model in the admin site without setting a value for the ManyToMany field it saves fine. I can also come back and set the ManyToMany field after saving the model and that works. However, if I try to save a new instance of my model, Exercise, that has the ManyToMany field, Exercise.muscles, set I get the following error:
(1452, 'Cannot add or update a child row: a foreign key constraint fails
(vitality.projectvitality_exercise_muscles, CONSTRAINT exercise_id_refs_exercise_id_a5d4ddd6 FOREIGN KEY (exercise_id) REFERENCES projectvitality_exercise (exercise_id))')
My mysql tables are set to INNODB.
My models are as follows:
class Muscle(models.Model):
def format(self):
return "name:{0}:".format(self.name)
def __unicode__(self):
return unicode(self.name)
muscle_id = UUIDField(primary_key = True)
name = models.CharField(max_length=30, blank=False, default="")
medical = models.CharField(max_length=150, blank=True, default="")
description = models.TextField(blank=True, default="")
class Exercise(models.Model):
def format(self):
return "name:{0}".format(self.name)
def __unicode__(self):
return unicode(self.name)
ISOLATION_TYPE = "isolation"
COMPOUND_TYPE = "compound"
FULL_BODY_TYPE = "full"
EXERCISE_TYPES = (
(ISOLATION_TYPE, "Isolation"),
(COMPOUND_TYPE, "Compound"),
(FULL_BODY_TYPE, "Full Body")
)
UPPER_BODY_GROUP = "upper"
LOWER_BODY_GROUP = "lower"
GROUP_CHOICES = (
(UPPER_BODY_GROUP, "Upper Body"),
(LOWER_BODY_GROUP, "Lower Body")
)
exercise_id = UUIDField(primary_key=True)
name = models.CharField(max_length=30, default="", blank=False)
description = models.TextField(blank=True, default="")
group = models.CharField(max_length=255,
choices=GROUP_CHOICES,
blank=False,
default=UPPER_BODY_GROUP)
exercise_type = models.CharField(max_length=255,
choices=EXERCISE_TYPES,
blank=False,
default=ISOLATION_TYPE)
muscles = models.ManyToManyField('Muscle', blank=True, null=True)
class Meta:
verbose_name = "Exercise"
verbose_name_plural = "Exercises"
After several days of debugging I found the issue. In my code I use UUIDField, from django-extensions library, as a primary key. When saving a new instance of Exercise model it is able to generate, set and save the primary key. However, when saving a new instance of Exercise that has the ManyToMany field set, UUIDField isn't generated in time. This leads to the Django admin attempting to insert a null/empty primary key, the UUIDField in Exercise model, into the join table which triggers the Foreign Key constraint failure.