Django - 管理后台中的一对一字段内联表单

7 投票
3 回答
7478 浏览
提问于 2025-04-18 12:26

你好,这个问题已经被问过很多次了,但很遗憾我找不到一个真正有效的答案。下面是我的模型:

class Person(models.Model):
    name = models.CharField(max_length=100)
    ...

class Address(models.Model):
    person = models.OneToOneField(Person)
    ...

然后在管理后台我有:

class AddressInline(admin.StackedInline):
    model = Address


class PersonAdmin(admin.ModelAdmin):
    inlines = (AddressInline)

admin.site.register(Person, PersonAdmin)

接着我遇到了这个臭名昭著的错误:

<class 'address.models.Address'> has no ForeignKey to <class 'person.models.Person'>

我尝试过:

  • django-reverse-admin。可惜在Django 1.6上不管用,而且我也不太懂怎么让它在1.6上工作。
  • 在Stack Overflow上看到的几种建议,比如使用代理模型和抽象基类,但这些也没用。

如果有人能帮我找到解决办法,我将非常感激。

3 个回答

0

对于那些在寻找Django 2.0解决方案的人:你可以直接使用这个库:https://pypi.org/project/django-reverse-admin/

对我来说效果很好。

3

我安装了:

  • Django==1.6.5
  • MySQL-python==1.2.4
  • South==0.8.1

下面的代码对我来说是有效的:

models.py

# -*- coding: utf-8 -*-

from django.db import models

class Person(models.Model):
    name = models.CharField(max_length=100)


class Address(models.Model):
    person = models.OneToOneField(Person)
    street = models.CharField(max_length=100)

admin.py

# -*- coding: utf-8 -*-
from django.contrib import admin

from .models import *


class AddressInline(admin.StackedInline):
    model = Address


class PersonAdmin(admin.ModelAdmin):
    inlines = (AddressInline,)

admin.site.register(Person, PersonAdmin)
admin.site.register(Address)

这是管理界面:

admin interface

10

我没有尝试过,但这个内容看起来是基于django-reverse-admin的代码,只不过更新到了Django 1.6版本:

https://gist.github.com/mzbyszewska/8b6afc312b024832aa85

注意,这段示例代码有问题:

class AddressForm(models.Form):
    pass

...你需要在最上面加上from django import forms,然后做类似这样的事情:

class AddressForm(forms.ModelForm):
    class Meta:
        model = Address

示例代码的第46行还有另一个问题:

inline_reverse = ('business_addr', ('home_addr', AddressForm), ('other_addr' (
    'form': OtherForm
    'exclude': ()
)))

可能应该改成:

inline_reverse = ('business_addr', ('home_addr', AddressForm), ('other_addr', {
    'form': OtherForm,
    'exclude': ()
}))

注意,它展示了三种不同的方式来指定一个内联...第一种方式就是直接用字段名'business_addr',也就是说如果你不需要为内联模型定制表单的话。

撰写回答