Администратор Django 1.11: создайте отношение OneToOne и его объект в админке

У меня есть простое приложение (о QR-кодах), в котором у меня есть две модели. Первый предназначен для определения QR-кода, а второй — для придания ему функции. (Для тех, кто интересуется: я разделил его на две модели, потому что наши QR-коды сложны и иногда лишены функций и доступны только для чтения. Я хотел, чтобы наша база данных была максимально нормализована).

Вот модель (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}'

Миксин QRCodeable — это абстрактный базовый класс, который дает функции отношение OneToOne к QR-коду. Миксин UniversallyUniqueIdentitude дает ему uuid.

В любом случае, теперь я хочу иметь возможность создавать QR-коды с функциями в админке 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,
    ]

Этот код приводит к следующему интерфейсу администратора:

Административный интерфейс QR-кода в админке Django.

Если я сейчас нажму на add another QR code function, выберу функцию и нажму "Сохранить", новый экземпляр функции QR-кода НЕ будет создан! Почему это? Как я могу написать эту модель администратора, чтобы я мог создавать функции для QR-кода в администраторе QR-кодов?


person J. Hesters    schedule 11.06.2018    source источник
comment
Вы редактируете этот Qr-код или добавляете? вы можете проверить этот пример? simpleisbetterthancomplex.com/ tutorial/2016/11/23/ В этом примере используется stackedinline, и я не видел «добавить еще», потому что это один к одному.   -  person Diego Puente    schedule 14.06.2018
comment
Это ваше полное admin.py или вы что-то пропустили?   -  person Daniel Hepper    schedule 15.06.2018
comment
OneToOneField не принимает нулевое значение. Вы позаботились об этом?   -  person Sylvain Biehler    schedule 15.06.2018
comment
@ daniel-hepper это полный admin.py в его нынешнем виде.   -  person J. Hesters    schedule 16.06.2018
comment
@ sylvain-biehler Я не понимаю, что вы имеете в виду. OneToOneField не должен быть пустым и не должен иметь значение null в моем определении.   -  person J. Hesters    schedule 16.06.2018
comment
@ J.Hesters А как создается связанный QR Code? Можете ли вы добавить код из QRCodeable в вопрос?   -  person Sylvain Biehler    schedule 17.06.2018
comment
@J.Hesters FWIW, я не смог воспроизвести вашу проблему на минимальном примере, см. dhepper/a656de16297dee6fe53e90fae58c0bf7 покажите нам больше кода   -  person Daniel Hepper    schedule 18.06.2018


Ответы (1)


Вероятно, это дубликат Администратор Django не сохраняет предварительно заполненные встроенные поля, оставленные в исходном состоянии. Ваша встроенная строка будет использовать только значения по умолчанию, но администратор 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
person schillingt    schedule 23.03.2019