Foreign key relationship with peewee and python
Asked Answered
B

2

5

I'm trying to set up a database ORM with peewee and am not clear on the use of foreign key relationships.

from peewee import *

db = SqliteDatabase('datab.db')

class datab(Model):
    class Meta:
        database = db

class Collection(datab):
    identifier = CharField()
    title = CharField()

class File(datab):
    identifier = ForeignKeyField(Collection, related_name='files')
    name = CharField()

Later, I do an import of "Collections"

for value in collection:
Collection(**value).save()

Finally, where I am having trouble is adding the Files to the collections

for value in collectionFiles:
    File(**value).save()

Within the value dict, there is a keyword pair with key of "identifier" and a value that should associate with the Collection identifier keyword.

However I get an error message:

ValueError: invalid literal for int() with base 10: 'somevalue'

If I change the File(datab): identifier Type to VarChar, it saves the data.

I'm realizing I'm doing it wrong. My assumption was that the unique identifier value in each table would apply the foreign key. After reading the documentation, it looks like the foreign key setup is a bit different. Do I need to do something like

Collections.File.files(**values).save() ? In other words, instead of doing a data import, loading the collection object and then adding the file associated fields through peewee?

Values that make up class File

{'crc32': '63bee49d',
 'format': 'Metadata',
 'identifier': u'somevalue',
 'md5': '34104ffce9e4084fd3641d0decad910a',
 'mtime': '1368328224',
 'name': 'lupi.jpg_meta.txt',
 'sha1': '1448ed1159a5d770da76067dd1c53e94d5a01535',
 'size': '1244'}
Borderline answered 11/6, 2013 at 2:43 Comment(0)
B
7

I think the naming of your fields might be part of the confusion. Rather than calling the foreign key from File -> Collection "identifier", you might call it "collection" instead.

class File(datab):
  collection = ForeignKeyField(Collection, related_name='files')
  name = CharField()

Peewee prefers that, when setting the value of a Foreign Key, it be a model instance. For example, rather than doing:

File.create(collection='foobar', name='/secret/password')

It is preferable to do something like this:

collection = Collection.get(Collection.identifier == 'foobar')
File.create(collection=collection, name='/secret/password')

As a final note, if the Collection "identifier" is the unique primary key, you can set it up thus:

class Collection(datab):
  identifier = CharField(primary_key=True)
  title = CharField()
Blepharitis answered 11/6, 2013 at 21:28 Comment(1)
Thanks, I saw something about the foreign keys being a model instance, but was unclear on the implementation. There are more fields for collection and file models than what I showed here - which is why I am using the kwargs. I think with the two answers here I'll be able to figure this out.Borderline
P
1

(I'm not familiar with peewee, but if it's like Django then this should work.)

class File has a ForeignKeyField and a CharField, so you can't simply save a pair of strings with File(**value). You need to convert a string to a key first, like this:

for value in collectionFiles:
    identifier = value['identifier']
    name = value['name']
    collection_entity = Collection.objects.filter(identifier=identifier).get()
    File(identifier=collection_entity, name=name).save()
Procambium answered 11/6, 2013 at 4:30 Comment(4)
Hmm my dict appears to have the correct keypair value combinations in it before I try the save function.Borderline
@Justin, I think the reason you get the ValueError is because it's expecting an integer for the identifier, not u'somevalue'. The integer is the ID of the related Collection with that identifier (that's how a database links a ForeignKeyField).Procambium
I noticed that the code wasn't quite right and I fixed it to use collection_entityProcambium
ah I see, for some reason I thought it was just looking for uniqueness in the key / value between the tables. Will try this out in a bitBorderline

© 2022 - 2024 — McMap. All rights reserved.