IntegrityError Null constraint violation - django

I have three models in my django app...a members model, an application model and an applications review model.
My members model looks like this...
class Members(models.Model):
TITLES = (
('chairman', 'Chairman'),
('secretary', 'Secretary')
)
user = models.OneToOneField(User, on_delete=models.CASCADE)
title = models.CharField(max_length=10, choices=TITLES, default='secretary')
My Applications model...
class Application(models.Model):
firstname = models.CharField(max_length=20)
middlename = models.CharField(max_length=20)
lastname = models.CharField(max_length=20)
dob = DateField()
The applications review model...
class ApplicationsReview(models.Model):
APPLICATION_STATUS = (
('pending', 'Pending Review'),
('approved', 'Approved'),
('rejected', 'Rejected')
)
applicant = models.OneToOneField(Application, on_delete=models.CASCADE, primary_key=True)
chairman = models.ForeignKey(Members, related_name='chairs', on_delete=models.CASCADE)
secretary = models.ForeignKey(Members, related_name='secretaries', on_delete=models.CASCADE)
application_status = models.CharField(max_length=10, choices=APPLICATION_STATUS, default='pending')
status_justification = models.TextField()
date = models.DateTimeField(auto_now_add=True)
When an application is created, I would like its review instantiated as well, hence, I have the following signal right below the applications review model...
# When an application is created, create with it an application review and associate it with the application instance
#receiver(post_save, sender=Application)
def create_application_review(sender, **kwargs):
instance = kwargs['instance']
created = kwargs['created']
if created:
ApplicationReview.objects.create(applicant=instance)
However, when I try to add an application in django admin I get the error
null value in column "chairman_id" violates not-null constraint
DETAIL: Failing row contains (3, pending, 2019-02-08 03:26:04.643452+00, null, null).
The error seems to be as a result of the signal trying to instantiate an ApplicationsReview instance without providing the values for the chairman and secretary. Even setting those to allow null fields doesn't get rid of the error. Is there something I'm missing here?

Creating ApplicationsReview requires you to pass the following details - chairman, secretary, status_justification But while creating ApplicationReview in the signal you are just passing value of applicant, So Django is assuming the values of chairman, secretary, status_justification fields as Null that is why you are getting this error.
If you want to make these field Non-compulsory you can pass null=True, Blank=True while defining the field in the model.
Something like this:
chairman = models.ForeignKey(Members, null=True, blank=True, related_name='chairs', on_delete=models.CASCADE)
# End
You can refer this answer to get more understanding of when to use null=True, blank=True or both.
https://stackoverflow.com/a/8609425/6280433

Related

django get_or_create throws Integrity Error

I have read this thread:
get_or_create throws Integrity Error
But still not fully understand when get_or_create returns False or IntegrityError.
I have the following code:
django_username = 'me'
user = get_user_model().objects.filter(username=django_username).first()
action_history, action_added = ActionModel.objects.get_or_create(
date=date_obj, # date object
account_name=unique_name, # e.g. account1234
target=follower_obj, # another model in django
user=user, # connected django user
defaults={'identifier': history['user_id']}
)
While the model looks like:
class ActionModel(models.Model):
"""
A model to store action history.
"""
identifier = models.BigIntegerField(
_("identifier"), null=True, blank=True) # target id
account_name = models.CharField(_("AccountName"), max_length=150, null=True, blank=True) # account name of the client
date = models.DateField(_("Date"), auto_now=False, auto_now_add=False) # action date
target = models.ForeignKey(Follower, verbose_name=_("Target"), on_delete=models.CASCADE) # username of the done-on action
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
null=True,
editable=False,
db_index=True,
) # django user that performed the action
class Meta:
verbose_name = _("Action")
verbose_name_plural = _("Actions")
unique_together = [
['account_name','date','target'],
]
Sometimes it return IntegrityError, and sometimes (when unique constrain exists it will return False on created).
You have unique_together constraint.
Lets imagine you have object in db with following data
account_name='bob', date='2020-12-12', target='b', user='12'
In you get_or_create method you are doing this
ActionModel.objects.get_or_create(
date='2020-12-12',
account_name='bob',
target='b',
user="13"
)
you providing exactly this three parameters with this data, but user this time is 13, so django could not find any object and it tries to create one, but with this parametres you cant create object because there is unique constraint
OK.
I figured it out, I sent:
account_name = 'adi'
date = '07-02-21'
target = 'nana1'
user = 'me'
While it was not exist with the specific user = 'me' but with user = None:
account_name = 'adi'
date = '07-02-21'
target = 'nana1'
user = None
So the get was failing and the created try to duplicate the unique_together = ['account_name','date','target'].

Getting a column instead of an object when relating with PrimaryKeyRelatedField in Django-Rest-Framework

I have a model for applications, which among many attributes have a category. This category is in fact a key to another model that has the category ID, its name, and so on.
class Application(models.Model):
title = models.CharField(max_length=50)
vendor = models.CharField(max_length=50, default="Unknown", null=False)
.
.
.
category = models.ForeignKey('ApplicationCategory', related_name='applications', null=False, default=1, on_delete=models.SET_DEFAULT)
class ApplicationCategory(models.Model):
name = models.CharField(max_length=20, null=False)
description = models.CharField(max_length=200, null=False)
Then, on the Django REST serializers side I have the serializer for the applications:
class SoftwareSerializer(serializers.ModelSerializer):
category = serializers.PrimaryKeyRelatedField(queryset=ApplicationCategory.objects.all())
class Meta:
model = Application
fields = ['id', 'title', ... 'category']
Which is generating the expected API view, with a dropdown for the categories, but showing them as the ApplicationCategory objects and not giving me their name.
API showing Category dropdown with objects instead of names
Is there a way to access attributes of those objects to show the name in the dropdown, for usability sake?
I have also tried creating a CategorySerializer object (class CategorySerializer(serializers.ModelSerializer)) and then using it as category = CategorySerializer(many=False) but instead of dropdowns, I get open text fields for the attributes of the category.
Am I trying to do something that is not expected to work?
try to define the desired text in str method for your ApplicationCategory class:
class ApplicationCategory(models.Model):
name = models.CharField(max_length=20, null=False)
description = models.CharField(max_length=200, null=False)
#example
def __str__(self):
return '%s: %s' % (self.name , self.description)

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 cannot access model in admin site

I was trying to adjust a DateField in one of my models to also show the time (DateTimeField). I ended up also making timezone adjustments. After all I decided to not use the time and deleted the additional code and set the field back to DateField. Migrations are made and migrated. Now when trying to access an object from the model either via the page or admin page I receive the error:
invalid literal for int() with base 10: b'24 22:00:00'
So after trying a few things I just wanted to delete the objects in the model using the admin page. This also resulted in the above error.
It seems every page relying on an object from that model throws the error.
Is there a way to force delete objects?
Can you recommend any other clean up methods?
The model is defined as:
class PieceInstance(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, help_text='Unique ID for this particular Piece across whole system')
piece = models.ForeignKey('Piece', on_delete=models.SET_NULL, null=True)
version = models.CharField(max_length=200)
date_claimed = models.DateField(null=True, blank=True)
claimant = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True)
date_sent_to_claimant = models.DateField(null=True, blank=True)
PIECE_STATUS = (
('n', 'Not Claimable'),
('a', 'Available'),
('r', 'Reserved'),
('c', 'Claimed'),
)
status = models.CharField(
max_length=1,
choices=PIECE_STATUS,
blank=True,
default='a',
help_text='Piece Availability',
)
#property
def claimed_overdue(self):
days_till_claimed_overdue = 7
if self.date_claimed and date.today() > self.date_claimed + timedelta(days=days_till_claimed_overdue):
return True
return False
class Meta:
ordering = ['date_claimed']
permissions = (('can_mark_sent_to_claimant', 'Set Piece Instance as sent to claimant'),)
def __str__(self):
return f'{self.id} ({self.piece.title})'
Since my project is not big I decided to drop the whole database and set it up again from scratch.
I used the accepted answer of this question
Note that you also have to set up all users again (including the superuser)

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]
})