Quick33
Quick33

Reputation: 37

Model instances without primary key value are unhashable with Djongo

I am getting the error Model instances without primary key value are unhashable when trying to remove a model instance from my admin panel.

models.py

from djongo import models
import uuid

PROPERTY_CLASSES = (
    ("p1", "Video Property"),
    ("p2", "Page Property"),
    ("trait", "Context Trait"),
    ("custom", "Custom Property")
)

EVENT_TYPES = (
    ("video", "Video Event"),
    ("track", "Track Event"),
    ("page", "Page Event")
)

class Device(models.Model):
    _id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    name = models.CharField(max_length=255)

class Platform(models.Model):
    _id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    name = models.CharField(max_length=255)
    app_name_possibilities = models.TextField(blank=True)


class EventPlatformDevice(models.Model):
    _id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    name = ""
    event_field = models.ForeignKey('Event', on_delete=models.CASCADE)
    applicable_apps = models.ManyToManyField('Platform', blank=True)
    applicable_devices = models.ManyToManyField('Device', blank=True)
    property_group = models.ManyToManyField('PropertyGroup', blank=True)
    custom_properties = models.ManyToManyField('Property', blank=True)
    

class Event(models.Model):
    _id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    name = models.CharField(max_length=255, unique=True)
    event_type = models.CharField(max_length=20, choices=EVENT_TYPES)
    

class PropertyGroup(models.Model):
    _id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    name = models.CharField(max_length=100)
    applicable_properties = models.ManyToManyField('Property')


class Property(models.Model):
    _id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    name = models.CharField(max_length=255) 
    property_class = models.CharField(max_length=20, choices=PROPERTY_CLASSES)
    format_example = models.TextField(blank=True)
    notes = models.TextField(blank=True)

The issue lies with the EventPlatformDevice model I believe. The issue I think is when I create a new entry in the Admin panel and setup the relationships between EventPlatformDevice.applicable_apps it gets saved into the MongoDB using a _id:ObjectId("61c25d36cdca07c8a6101044") since that is what Mongo uses. I changed all of my primary keys to use a UUID since that was the only way I could get it to work. Now I think it is having a issue that some of my items are using ObjectId while some are using the _id:Binary('7w6NaYCQQn6BS7jaOXUNZw==', 3) that I am getting from uuid.

Is it possible to define what type the _id field is for everything? That way I can set it to use UUID.

Attached are images showing the data in Compass.

first second

When I did not specify the _id in all my models, I was getting errors when deleting and accessing. It was like Django did not know how to reference the ObjectId. That is why I went with UUID. But since I cannot control the dd.parsers_eventplatformdevice_applicable_apps (2nd pic) it is having issues deleting it.

Upvotes: 1

Views: 1421

Answers (1)

Kamu
Kamu

Reputation: 23

Is it possible to define what type the _id field is for everything?

I am afraid not. Each driver implementations may implement UUID serialization and deserialization logic differently, which may not be fully compatible with other drivers. (docs).

First, You can configure a UUID Representation, since PyMongo is using a legacy method to encode and decode UUID (0x03 subtype), you can change to cross-language compatible Binary 0x04 subtype. To do so in Djongo, just provide uuidRepresentation in the database settings as a standard (docs):

DATABASES = {
    'default': {
        'ENGINE': 'djongo',
        'NAME': 'dd',
        'ENFORCE_SCHEMA': False,
        'CLIENT': {
            'host': 'mongodb://localhost:27017',
            'uuidRepresentation': 'standard',
            'waitQueueTimeoutMS': 30000
        },
    },
}

Second, I would definitely try to make _id works. So the cration of the _id field will be provided by MongoDB server. If that does not work for you:

_id = models.ObjectIdField(primary_key=True)

then you could try this one:

_id = models.AutoField(auto_created=True, primary_key=True, unique=True)

Upvotes: 2

Related Questions