Django 1.11 admin:创建 OneToOne 关系,它是 admin 中的对象

Posted

技术标签:

【中文标题】Django 1.11 admin:创建 OneToOne 关系,它是 admin 中的对象【英文标题】:Django 1.11 admin: Create a OneToOne relationship and it's object in the admin 【发布时间】:2018-11-20 11:34:25 【问题描述】:

我有一个简单的应用程序(关于二维码),其中有两个模型。第一个用于定义二维码,第二个用于赋予其功能。 (对于那些想知道的人:我把它分成两个模型,因为我们的二维码很复杂,有时缺少功能并且是只读的。我想让我们的数据库尽可能地标准化)。

这是模型(models.py):

from django.core.exceptions import ObjectDoesNotExist
from django.db import models
from django.utils.translation import ugettext_lazy as _

from core.behaviors import QRCodeable, UniversallyUniqueIdentifiable
from core.utils import QR_CODE_FUNCTIONS
from model_utils.fields import StatusField
from model_utils.models import SoftDeletableModel, TimeStampedModel

QR_CODE_PREFIX = "QR Code"
QR_CODE_FUNCTION_PREFIX = "Function"
QR_CODE_FUNCTION_MIDFIX = "for"


class QRCode(
    UniversallyUniqueIdentifiable,
    SoftDeletableModel,
    TimeStampedModel,
    models.Model
):
    @property
    def function(self):
        try:
            return self.qrcodefunction.qr_code_function
        except ObjectDoesNotExist:
            return ""

    class Meta:
        verbose_name = _('QR code')
        verbose_name_plural = _('QR codes')

    def __str__(self):
        return f'QR_CODE_PREFIX self.uuid'


class QRCodeFunction(
    UniversallyUniqueIdentifiable,
    SoftDeletableModel,
    TimeStampedModel,
    QRCodeable,
    models.Model
):
    QR_CODE_FUNCTIONS = QR_CODE_FUNCTIONS
    qr_code_function = StatusField(choices_name="QR_CODE_FUNCTIONS")

    class Meta:
        verbose_name = _('QR code function')
        verbose_name_plural = _('QR code functions')

    def __str__(self):
        return f'QR_CODE_FUNCTION_PREFIX self.qr_code_function QR_CODE_FUNCTION_MIDFIX self.qr_code'

mixin QRCodeable 是一个抽象基类,它为函数提供与 QR 码的 OneToOne 关系。 mixin UniversallyUniqueIdentifiable 给它一个 uuid。

无论如何,我现在希望能够在 Django 管理员中创建具有功能的二维码。所以我写了自己的管理类(admin.py):

from django.contrib import admin

from .models import QRCode, QRCodeFunction


class QRCodeFunctionInline(admin.TabularInline):
    model = QRCodeFunction
    extra = 0


@admin.register(QRCode)
class QRCodeAdmin(admin.ModelAdmin):
    save_on_top = True
    search_fields = ['qrcodefunction__qr_code_function']
    list_display = (
        '__str__',
        'function',
    )
    inlines = [
        QRCodeFunctionInline,
    ]

此代码导致以下管理界面:

如果我现在点击add another QR code function,选择一个函数并点击保存,新的二维码函数实例不会创建!这是为什么?如何编写此模型管理员,以便我可以在二维码管理员中为二维码创建函数?

【问题讨论】:

您是在编辑那个二维码还是在添加?你能测试这个例子吗? simpleisbetterthancomplex.com/tutorial/2016/11/23/… 那里的示例使用stackedinline,我没有看到“添加另一个”,因为是一对一的。 这是你完整的admin.py 还是你遗漏了什么? OneToOneField 不接受空值。你照顾好了吗? @daniel-hepper 这是目前完整的 admin.py。 @sylvain-biehler 我不确定你的意思。 OneToOneField 在我的定义中不能为空,也不能为空。 【参考方案1】:

这可能与Django Admin not saving pre-populated inline fields which are left in their initial state 重复。您的内联将仅使用默认值,但如果一个或多个字段已更改,则默认情况下 Django 的管理员实际上不会创建实例。这是一个痛苦的经历,但 Django 在这里谨慎行事。最好不要创建,而不是创建并必须删除。

根据您的上下文调整该问题的答案是:

from django.contrib import admin
from django.forms.models import ModelForm

class AlwaysChangedModelForm(ModelForm):
    def has_changed(self):
        """ Should returns True if data differs from initial. 
        By always returning true even unchanged inlines will get validated and saved."""
        return True


class QRCodeFunctionInline(admin.TabularInline):
    model = QRCodeFunction
    form = AlwaysChangedModelForm
    extra = 0

【讨论】:

以上是关于Django 1.11 admin:创建 OneToOne 关系,它是 admin 中的对象的主要内容,如果未能解决你的问题,请参考以下文章

在 Django 1.11 admin 中创建新对象时评估只读字段

Django 1.11 admin list_filter 在另一个模型中包含字段

在 Django 1.11 中使用 MySQL 连接器/Python 时出错

Django集成TinyMCE(admin后台+前台)

Django 1.11 使用来自应用程序的模板作为管理模板

除非输入搜索查询,否则隐藏 Django admin 中的所有记录[关闭]