Django IntegrityError while updating a record - python

I have a model with double columns as primary key. I do a filter on it and get the records I want, change a field and save it. As I know save will update the record and does not create a new instance of the model in db. so It should be all okay but I'm stuck with an integrityError Duplicate entry '10-2' for key 'PRIMARY' when I try to save the record
Here is the code snippet:
analysis = AnalysisResult.objects.filter(request=req.request_id)
for anal in analysis:
anal.analysisresult_path = some_string
anal.save() #this line is where the error occurs
And here is my model:
class AnalysisResult(models.Model):
analysisresult_path = models.CharField(db_column='analysisResult_path', max_length=255, blank=True,
null=True) # Field name made lowercase.
detectionresult_path = models.CharField(db_column='detectionResult_path', max_length=255, blank=True,
null=True) # Field name made lowercase.
targetcode = models.ForeignKey('TagetCode', models.DO_NOTHING,
db_column='targetCode_id') # Field name made lowercase.
request = models.ForeignKey('Request', models.DO_NOTHING, primary_key=True)
class Meta:
managed = False
db_table = 'analysis_result'
unique_together = (('request', 'targetcode'),)

Ah, yes, welcome to one of django's strongest opinions: all tables/models should have a single primary key field that can be used for updates. If you don't have this, you must write raw SQL for the update since save will assume that there is an implicit primary key field called id to use in the where clause.

Related

Django MultipleObjectsReturned while using a legacy database

I am using Djano to develop a simple web app to display and manage database data. I hooked up a MySQL db and used inspectdb to auto generate a model based on the database tables and this is what I got back, which looks good.
# This is an auto-generated Django model module.
# You'll have to do the following manually to clean this up:
# * Rearrange models' order
# * Make sure each model has one field with primary_key=True
# * Make sure each ForeignKey has `on_delete` set to the desired behavior.
# * Remove `managed = False` lines if you wish to allow Django to create, modify, and delete the table
# Feel free to rename the models, but don't rename db_table values or field names.
from __future__ import unicode_literals
from django.core.exceptions import MultipleObjectsReturned
from django.db import models
class Booking(models.Model):
class Meta:
managed = False
db_table = 'Booking'
unique_together = (('hotelno', 'guestno', 'datefrom'),)
hotelno = models.OneToOneField('Hotel', models.DO_NOTHING, db_column='hotelNo', primary_key=True) # Field name made lowercase.
guestno = models.IntegerField(db_column='guestNo') # Field name made lowercase.
datefrom = models.DateTimeField(db_column='dateFrom') # Field name made lowercase.
dateto = models.DateTimeField(db_column='dateTo', blank=True, null=True) # Field name made lowercase.
roomno = models.OneToOneField('Room', models.DO_NOTHING, db_column='roomNo') # Field name made lowercase.
list_display =
#def __str__(self):
# return ("".join(hotelno) + "".join(guestno) + "".join(datefrom))
class Guest(models.Model):
guestno = models.AutoField(db_column='guestNo', primary_key=True) # Field name made lowercase.
guestname = models.CharField(db_column='guestName', max_length=255) # Field name made lowercase.
guestaddress = models.CharField(db_column='guestAddress', max_length=255, blank=True, null=True) # Field name made lowercase.
class Meta:
managed = False
db_table = 'Guest'
class Hotel(models.Model):
hotelno = models.AutoField(db_column='hotelNo', primary_key=True) # Field name made lowercase.
hotelname = models.CharField(db_column='hotelName', max_length=255, blank=True, null=True) # Field name made lowercase.
city = models.CharField(max_length=255, blank=True, null=True)
class Meta:
managed = False
db_table = 'Hotel'
class Room(models.Model):
roomno = models.IntegerField(db_column='roomNo', primary_key=True) # Field name made lowercase.
hotelno = models.ForeignKey(Hotel, models.DO_NOTHING, db_column='hotelNo') # Field name made lowercase.
type = models.CharField(max_length=255, blank=True, null=True)
price = models.IntegerField(blank=True, null=True)
class Meta:
managed = False
db_table = 'Room'
unique_together = (('roomno', 'hotelno'),)
In the admin.py file for this app I included the models like so, so that I could at least see the data up there.
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.contrib import admin
# Register your models here.
from .models import Hotel, Room, Guest, Booking
admin.site.register(Hotel)
admin.site.register(Room)
admin.site.register(Guest)
admin.site.register(Booking)
When I access the default Django admin page, I'll see the tables registered on admin page.
I click on Bookings and see the multiple records, without names (for other reasons), but if I click on one of them I get the MultipleObjectsReturned Error
I've read everything I could find, and the closest thing to a reason I could find for why this is happening has to do with there being composite keys in some of the models. But, again, I don't know if that's the actual reason, I could also be missing something? I don't know.
I guess the reason is that data of Booking table not consistent with your model declaration. Django's admin detail view retrieves model by primary key.
You marked hotelno as PK:
hotelno = models.OneToOneField('Hotel', models.DO_NOTHING, db_column='hotelNo', primary_key=True)
Since some data already exists in Booking table, you have to make sure that hotelno values (hotelNo column) are unique or you will get MultipleObjectsReturned exception for non-unique pk values. Also make sure you've read this part of the documentation https://docs.djangoproject.com/en/1.11/ref/models/options/#managed
It looks like your booking table does not have a primary key and inspectdb guessed wrong when affecting it to the hotelno column of your booking table.
When the admin try to get the record by it's id it get multiple result since different booking can reference the same hotel multiple time.
What I would do on the booking model :
change hotelno and roomno to ForeignKey
remove the primary on hotelno
The new problem is now you have a model with no primary key. Django does not allow that. If you can alter the MySQL table add a primary key column to it and alter the booking model accordingly. If you can't alter the table I see no easy way to make it works.

Django - create unique key that contains other models field

I'm trying to create 'unique_together' meta for a model, but instead of two fields from the current model, one of them is a field of other model (which is a foreign key in the current model):
I want the 'Item' model to have unique_together that contains both its 'identifier' field and the Spec's container_id. a Spec is foreign key in 'Item'.
Tried something like this, but I get "Unresolved reference spec..."
class Spec(BaseModel):
title = models.CharField(max_length=200)
identifier = models.IntegerField(unique=True)
container = models.ForeignKey(Container, related_name='specs')
class Item(SubmittalsBaseModel, BaseModel, DirtyFieldsMixin):
title = models.CharField(max_length=200)
identifier = models.CharField(max_length=200, unique=True)
spec = models.ForeignKey(Spec, related_name='items')
class Meta:
container_id = spec.container
unique_together = ('identifier', 'container_id')
You can't do that.. (at least I think)..
The unique_together clause is directly translated to the SQL unique index. And you can only set those on columns of a single table, not a combination of several tables.
You can add validation for it yourself though, simply overwrite the validate_unique method and add this validation to it.
Docs: http://docs.djangoproject.com/en/dev/ref/models/instances/#django.db.models.Model.validate_unique

Foreign Key to single attribute from another entity in Django

I want to create database model in django and define a foreign key. All the example I see in internet have following syntax.
attr = models.ForeignKey(Entity)
However I want a foreign key to be linked with single attribute from another entity and not the whole entity.
I have following models:
class User(models.Model):
user_id = models.PositiveIntegerField(primary_key=True)
password = models.CharField(max_length=20)
email = models.EmailField()
........
class ContentItem(models.Model):
content_id = models.PositiveIntegerField(primary_key=True)
title = models.CharField(max_length=100)
description = models.TextField()
.........
author_id = models.ForeignKey(User, on_delete= models.CASCADE)
Here, I want ContentItem.author_id to be foreign key for User.user_id and not the whole User model. While entering value for author_id, I simply want to enter plain id (1,2,3) and not all the instance of User
Sorry if the question is very general and thanks in advance
You should name your fk field like:
author = models.ForeignKey(User, on_delete= models.CASCADE)
because Django will create the attribute author_id automagically and
content_item.author_id
will give you access to the id of the user directly without an extra db hit. With your naming, you can access the id directly through author_id_id.
You have to override the str(self) method inside your models class.
Ex.
models.py
class User(models.Model):
.
.
.
def __str__(self):
return f”{self.attribute-name}
Where attribute-name is name of attribute you want to reference.
Enjoy the coding 😊👍

Django Foreign Key automatically filled based off of another field on model

So I currently have an "Account" Model and "Account Comments" Model -- keep in mind, that I can't really control the scheme of the database, and I'm writing a wrapper around existing DB.
Under the AccountComments Model, there is a field called "Data". It is where the AccountComments actually are and I'm trying to basically create a foreign key on the Account model without actually having to redesign and add a "AccountComments" field on Account that holds the AccountID.
class Account(models.Model):
AccountID = models.AutoField(editable=False, db_column='AccountID', verbose_name='ID',
primary_key=True)
acctno = models.IntegerField(editable=True, unique=True, db_column='ACCTNO', verbose_name='Acct #', blank=True,
null=True) # Field name made lowercase.
accountComments = models.ForeignKey('accountComments',to_field='accountID',db_column='Data')
def __str__(self):
return str(self.acctno)
class Meta:
managed = False
db_table = 'Account'
class accountComments(models.Model):
accountCommentID = models.AutoField(db_column='AccountCommentID', primary_key=True) # Field name made lowercase.
accountID = models.IntegerField(db_column='AccountID') # Field name made lowercase.
EntryUserID = models.IntegerField(db_column='EntryUserID') # Field name made lowercase.
EntryStamp = models.DateTimeField(db_column='EntryStamp', ) # Field name made lowercase.
Data = models.TextField(db_column='Data') # Field name made lowercase.
guid = models.CharField(db_column='guid', max_length=255) # Field name made lowercase.
class Meta:
managed = False
db_table = 'AccountComment'
ultimately, want accountComments on the Account Model to use 'AccountID' to do a lookup onto accountComments.accountID and then provide back 'Data'.
I know that I can use
def accountComments(self):
return str(accountComment.objects.get(accountID = self.AccountID).Data)
but I want it to work with Django Admin, so I need it to be an integrated part of the model.
Thanks if anyone can point me in the right direction.
You're trying to do too much with a foreign key. Following a foreign key in Django should return the model instance, not a particular field from the model instance.
The db_column should be the column in the Account table that stores the id, e.g.
accountComments = models.ForeignKey('accountComments',to_field='accountID',db_column='AccountID')
Then, to get the Data for a particular account instance, you would do:
account.accountComments.Data

OneToOneField with null=True doesn't allow empty field

I've got these two classes:
class Bill(models.Model):
date = models.DateField()
total_amount_chf = models.DecimalField('Cost (in CHF)', max_digits=10, decimal_places=2)
class ProjectParticipation(models.Model):
project = models.ForeignKey('Project')
user = models.ForeignKey(User)
is_admin = models.BooleanField()
bill = models.OneToOneField(Bill, on_delete=models.SET_NULL, null=True, blank=True)
When I'm now constructing the SQL-database I get the following field in the table for the ProjectParticipation:
bill_id integer NOT NULL,
CONSTRAINT expenses_projectparticipation_bill_id_fkey FOREIGN KEY (bill_id)
REFERENCES expenses_bill (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION DEFERRABLE INITIALLY DEFERRED,
And now when I want to insert a ProjectParticipation without Bill I get a "null value in column "bill_id" violates not-null constraint".
What to do against it?
May be you have added the Null Constraint later after syncing the database. Delete the database and re-sync the database (if you are not using Django-South otherwise make sure you have migrated the schema changes)

Categories