首页 > 解决方案 > Djongo数据库引擎上的Django Admin外键错误

问题描述

我正在将djongo包用于数据库后端引擎,以便连接到 MongoDB 并在其上定义我的模型。

设置.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'
    }
  }
}

模型.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)

和 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']

它适用于使用 SQLite 后端,并且在没有外键字段的 djongo 后端时可以正常工作,但是在使用djongo 后端并具有外键字段时给我一个错误。它说:

错误图像

如上图所示,它可以从数据库中加载对象并正确检测关系,但无法保存。

而且我无法创建与另一个对象相关的新对象。我该如何解决这个问题?

更新


我可以使用这样的代码创建对象,问题似乎来自 Django 管理站点

e = EventModel.objects.first()
CalendarModel.objects.create(name="test", color="red", event=e)

标签: djangomongodbormdjongo

解决方案


我注意到,当您尝试使用PK 保存对象的实例时 ObjectId将其转换为字符串,因此不再对应于对象的实例,因此通过覆盖POST中的get_form方法,您可以截获这个数据并将字符串更改为 ObjectId,但正如您在Django 文档中看到的那样:

request.POSTrequest.GETQueryDict在正常的请求/响应周期中访问时将是不可变的。

因此您可以使用同一文档中的建议:

要获得可变版本,您需要使用QueryDict.copy()

或者......使用一个小技巧,例如,如果您出于某种原因需要保留对对象的引用或保持对象不变:

# 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

哪里数据是你的QueryDicts

在这种情况下:

@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)

推荐阅读