Search code examples
pythondjangodjango-modelsdjango-viewslegacy-database

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.


Solution

  • 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