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
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)
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)
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/
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.
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.