Reputation: 31
I'm using djongo package for a database backend engine in order to connect to MongoDB and define my models on it.
settings.py:
DATABASES = {
# 'default': {
# 'ENGINE': 'django.db.backends.sqlite3',
# 'NAME': str(BASE_DIR / 'db.sqlite3'),
# },
'default': {
'ENGINE': 'djongo',
'NAME': 'djongo-db',
'ENFORCE_SCHEMA': False,
'CLIENT': {
'host': 'localhost',
'port': 27017,
'username': 'root',
'password': 'root',
'authSource': 'admin',
'authMechanism': 'SCRAM-SHA-1'
}
}
}
models.py:
class EventModel(BaseModel)
name = models.CharField(max_length=20)
class CalendarModel(BaseModel):
name = models.CharField(max_length=20)
color = models.CharField(max_length=20)
event = models.ForeignKey(to=EventModel, on_delete=models.SET_NULL, null=True)
and admin.py:
from django.contrib import admin
from .models import CalendarModel, EventModel
@admin.register(CalendarModel)
class CalendarAdmin(admin.ModelAdmin):
exclude = ['_id']
@admin.register(EventModel)
class EventAdmin(admin.ModelAdmin):
exclude = ['_id']
It works fine with using SQLite backend and it's working when djongo backend without foreign key field but gives me an error when using the djongo backend and has foreign key field. It said:
As you can see in the image above, it can load objects from the database and detects the relation correctly, but it can't save it.
And I can't create a new object with relation to another object. How I can fix this?
Update
I can create objects using code like this, the problem seems to be from Django admin site
e = EventModel.objects.first()
CalendarModel.objects.create(name="test", color="red", event=e)
Upvotes: 3
Views: 534
Reputation: 21
I noticed that when you try to save an instance of an object with PK an ObjectId that it is transformed into a string and consequently no longer corresponds to an instance of an object, so with the override of the get_form method in POST you can intercept this data and change the string to ObjectId, but as you can see in the Django documentation:
The QueryDicts at request.POST and request.GET will be immutable when accessed in a normal request/response cycle.
so you can use the recommendation from the same documentation:
To get a mutable version you need to use QueryDict.copy()
or ... use a little trick, for example, if you need to keep a reference to an object for some reason or leave the object the same:
# remember old state
_mutable = data._mutable
# set to mutable
data._mutable = True
# сhange the values you want
data['param_name'] = 'new value'
# set mutable flag back
data._mutable = _mutable
where data it is your QueryDicts
In this case:
@admin.register(CalendarModel)
class CalendarModelAdmin(admin.ModelAdmin):
list_display = ('....')
....
def get_form(self, request, obj, change, **kwargs):
if request.POST:
# remember old state
_mutable = request.POST._mutable
# set to mutable
request.POST._mutable = True
# сhange the values you want
request.POST['event'] = ObjectId(request.POST['event'])
# set mutable flag back
request.POST._mutable = _mutable
return super().get_form(request, obj=obj, change=change, **kwargs)
Upvotes: 1