keredson / peewee

a small, expressive orm -- supports postgresql, mysql and sqlite
http://docs.peewee-orm.com/
MIT License
13 stars 4 forks source link

null FKs return non-null objects with all-null attributes #4

Closed keredson closed 8 years ago

keredson commented 8 years ago

clone of https://github.com/coleifer/peewee/issues/1012:

when doing a left join across a nullable FK, peewee 2.8.1 populates an empty object where the null is, rather than putting a None in the attribute. example:

import logging, os, sys
import peewee as pw

logger = logging.getLogger('peewee')
logger.setLevel(logging.DEBUG)
logger.addHandler(logging.StreamHandler())

db_fn = 'example.db'
if os.path.exists(db_fn): os.remove(db_fn)
db = pw.SqliteDatabase(db_fn)

class Person(pw.Model):
  name = pw.CharField()
  class Meta:
    database = db

class Pet(pw.Model):
  name = pw.CharField()
  owner = pw.ForeignKeyField(db_column='owner_id', rel_model=Person, to_field='id', null=True)
  class Meta:
    database = db

db.connect()
db.create_tables([Person, Pet])

Pet.create(name='Chance', owner=None)

chance = Pet.select(Pet, Person).join(Person, join_type=pw.JOIN.LEFT_OUTER, on=Pet.owner).get()
print 'chance', chance
print 'chance.owner_id', chance.owner_id
print 'chance.owner', chance.owner
print 'chance.owner.id', chance.owner.id

output:

$ python test_join_null_fk.py 
('CREATE TABLE "person" ("id" INTEGER NOT NULL PRIMARY KEY, "name" VARCHAR(255) NOT NULL)', [])
('CREATE TABLE "pet" ("id" INTEGER NOT NULL PRIMARY KEY, "name" VARCHAR(255) NOT NULL, "owner_id" INTEGER, FOREIGN KEY ("owner_id") REFERENCES "person" ("id"))', [])
('CREATE INDEX "pet_owner_id" ON "pet" ("owner_id")', [])
('INSERT INTO "pet" ("name", "owner_id") VALUES (?, ?)', [u'Chance', None])
('SELECT "t1"."id", "t1"."name", "t1"."owner_id", "t2"."id", "t2"."name" FROM "pet" AS t1 LEFT OUTER JOIN "person" AS t2 ON ("t1"."owner_id" = "t2"."id") LIMIT 1 OFFSET 0', [])
chance <__main__.Pet object at 0x7f9b3c249950>
chance.owner_id None
chance.owner <__main__.Person object at 0x7f9b3c249b90>
chance.owner.id None

is this the intended behavior? consensus here is this is a bug and that:

  1. chance.owner should be None, not an empty Person object with all null attributes
  2. chance.owner.id should throw AttributeError: 'NoneType' object has no attribute 'id'

we couldn't find any documentation about what this should do one way or the other, nor any old issues that address this.

coleifer commented 8 years ago

Fixed in master, see: