Django MultipleObjectsReturned while using a legacy database - python

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.

Related

It is impossible to add a non-nullable field 'id' to video without specifying a default

This is my models.py
from ast import Delete
from email.policy import default
from django.db import models
from django.contrib.auth.models import User
class Video(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
title=models.CharField(max_length=100, null=False)
description=models.TextField(max_length=1000,null=True)
video=models.FileField(upload_to="video/%y",null=False)
def __str__(self):
return self.title
class Euser(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
phone = models.CharField(max_length=10,null=True)
birthdate = models.DateField(null=True,)
profile_pic = models.ImageField(null=True, )
cover_pic = models.ImageField( null=True, upload_to="images/%y")
def __str__(self):
return self.phone
when i try to makemigrations
It is impossible to add a non-nullable field 'id' to video without specifying a default. This is because the database needs something to populate existing rows.
Please select a fix:
Provide a one-off default now (will be set on all existing rows with a null value for this column)
Quit and manually define a default value in models.py.
This error occurs...
Please suggest me what should i do
and also suggest me about any changes in model
For a particular model, in the database, if records already exist and add new fields to the model then it shows such an error. To overcome this problem, you have to set the new field as blank=True and null=True or you can set some default value to the new field using default='some_value'.

Converting IntegerField to ForeignKey from recovered database in Django

I'm working with a MySQL database that I connected to my django project (using python manage.py inspectdb > app/models.py) but it's not reading the relationships correctly. The ForeignKeys are IntegerFields so I cannot use the handy Django ORM lookup. Here's an example:
class ChileStudents(models.Model):
""" simplified version of the model """
otec = models.IntegerField(blank=True, null=True) # Here's the issue
# More stuff goes here
updated_at = models.DateTimeField(blank=True, null=True)
class Meta:
managed = True
db_table = 'chile_students'
class Otecs(models.Model):
""" Also a simplified version """
name = models.CharField(max_length=45, blank=True, null=True)
updated_at = models.DateTimeField(blank=True, null=True)
class Meta:
managed = True
db_table = 'otecs'
As shown in the example above, the IntegerField points to the OTEC id, this is a simple one-to-many relationship. I tried converting the field into a ForeignKey like this:
otec = models.ForeignKey('Otecs', on_delete=models.SET_NULL,blank=True, null=True, db_column="otec_id")
But when migrating it just sets the column otec_id to NULL.
Is there any way I can "convert" the field into a ForeingKey?
You can specify that the name of the database column is otec with db_column='otec':
class ChileStudents(models.Model):
otec = models.ForeignKey(db_column='otec', blank=True, null=True)
# More stuff goes here
updated_at = models.DateTimeField(blank=True, null=True)
class Meta:
managed = False
db_table = 'chile_students'
But since the table already exists, you can not make it managed = True, since then Django will try to create the table at the database side, create/remove columns, etc. Since here the table already exists, you can not let Django handle that, since then it will aim to create a table that already exists.

Django IntegrityError while updating a record

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.

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

Not able to use foreign key from another app?

travelers.models
from django.db import models
class ShortInfoTraveler(models.Model):
name = models.CharField(max_length=200, blank=True)
email = models.EmailField(blank=True)
blogs.models
from django.db import models
from travelers.models import ShortInfoTraveler
class Title(models.Model):
shortinfotraveler = models.ForeignKey('ShortInfoTraveler')
title_text = models.CharField(max_length=255)
description = models.CharField(max_length=255, null=True, blank=True)
And When I run makemigrations, Terminal show following-
ERRORS: blogs.Title.shortinfotraveler: (fields.E300) Field defines a relation with
model 'blogs.ShortInfoTraveler', which is either not installed, or is abstract.
You should be setting your foreign key like this:
models.ForeignKey('travelers.ShortInfoTraveler')
If you want to use a string to set the foreign key relation.
Or you should just set ShortInfoTraveler without it being a string since you've imported it.
Setting it to "ShortInfoTraveler" is looking for the model in the current models file instead of your other app which you can see in the error message output back.

Categories