Django admin - OneToOneField inline throws“没有ForeignKey”例外 [英] Django admin - OneToOneField inline throws "has no ForeignKey" exception

查看:99
本文介绍了Django admin - OneToOneField inline throws“没有ForeignKey”例外的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个非常简单的应用程序,它现在声明了两个模型:一个被称为内容,简单地保存内容数据,另一个是页面,其中包含内容作为OneToOneField。



我这样做的原因是,我可以将Page作为我使用的实际具体类,当我计划的其他模块中的其他模型需要页面数据时,他们可以只需将内容作为OneToOneField。我这样做是为了避免继承和使用组合。



models.py:

 从django.db导入模型

类内容(models.Model):
其他模块可以使用的基本页面数据
title = models.CharField(max_length = 200)
html_title = models.CharField(max_length = 200)
meta_desc = models.CharField(max_length = 200)
keywords =模型。 CharField(max_length = 200)
content = models.TextField()

类页面(models.Model):
由管理员管理的基本页面的具体实现
slug = models.SlugField()
content = models.OneToOneField(Content)

def __str __(self):
return self.content.title

admin.py:

$ el = Content
fields =('title','html_title','meta_desc','keywords','content')

class PageAdmin(admin.ModelAdmin):
fields =('slug',)
inlines = [ContentInline]

在页面上管理我得到这个例外:

  / admin / content / page / add / 
< class'内容的异常。 models.Content'>没有ForeignKey到< class'content.models.Page'>

当然说什么是正确的,但我似乎找不到一种做我想要的方式,其中包括关系的非限定方面的内联。我不想声明内容的关系,因此我必须在该类中定义每个单独的关系,这将会引入依赖关系到其他模块,在我看来,它不应该什么都不了解。 >

在Python 3.3上使用Django 1.6。



编辑:如意见所示,我我们决定使用遗产。我最初的关注是,我希望灵活性能够从多个其他类组成课程。然而,由于Django ORM确实支持多重继承,如果我意识到这个方法被称为mixins(Python是新的),那么我将会有更多的东西。



示例mixins与模型:

 从django.db导入模型

类内容(模型。
其他模块可以使用的基本页面数据
title = models.CharField(max_length = 200)
html_title = models.CharField(max_length = 200 )
meta_desc = models.CharField(max_length = 200)
keywords = models.CharField(max_length = 200)
content = models.TextField()

def __str__ (self):
return self.title

class Meta:
abstract = True

class数据(models.Model):
data_name = models.CharField(max_length = 200)

class Meta:
abstract = True

类页面(内容,数据):
具体执行基本页面管理b y管理员
slug = models.SlugField()

然后我可以只需将其用作admin.py中的一个模型。

解决方案

另一个解决方案是移动 OneToOneField 内容页面

  class Content(models.Model):
其他模块可以使用的基本页面数据
title = models.CharField(max_length = 200)
html_title = models.CharField(max_length = 200)
meta_desc = models.CharField(max_length = 200)
keywords = models.CharField(max_length = 200)
content = models.TextField()
page = models.OneToOneField(Page,primary_key = True,related_name =content)

类页(models.Model):
由管理员管理的基本页面的具体实现
slug = models.SlugField()

def __str __(self):
return self .CO ntent.title

您仍然可以执行 page.content 和内联表格将开箱即用



编辑:



该方法的一个缺点是它将允许用户创建一个页面而不向其分配任何内容(在这种情况下, page.content 将崩溃)



通过创建自定义表单非常容易克服这个问题

  class ContentAdminForm 

def __init __(self,* args,** kwargs):
kwargs [empty_permitted] = False
super(ContentAdminForm,self).__ init __ * args,** kwargs)

然后在管理页面

  class ContentInline(admin.TabularInline):

model = Content
form = ContentAdminForm
fields =('title','html_title','meta_desc','keywor ds','content')


I have a very simple app which at the moment declares two models: one is called "Content" and simply holds content data and the other is "Page" which includes "Content" as a OneToOneField.

The reason I've done this is so that I can have "Page" as an actual concrete class that I use and when other models in other modules I'm planning need page data, they can simply include "Content" as a OneToOneField. I've done it this way to avoid inheritance and use composition instead.

models.py:

from django.db import models

class Content(models.Model):
    """Basic page data which can be used by other modules"""
    title = models.CharField(max_length=200)
    html_title = models.CharField(max_length=200)
    meta_desc = models.CharField(max_length=200)
    keywords = models.CharField(max_length=200)
    content = models.TextField()

class Page(models.Model):
    """Concrete implementation of a basic page managed by the admin"""
    slug = models.SlugField()
    content = models.OneToOneField(Content)

    def __str__(self):
        return self.content.title

admin.py:

from django.contrib import admin
from content.models import Page, Content

class ContentInline(admin.TabularInline):
    model = Content
    fields = ('title', 'html_title', 'meta_desc', 'keywords', 'content')

class PageAdmin(admin.ModelAdmin):
    fields = ('slug',)
    inlines = [ContentInline]

On the page admin I get this exception:

Exception at /admin/content/page/add/
<class 'content.models.Content'> has no ForeignKey to <class 'content.models.Page'>

What is says of course is correct, but I cannot seem to find a way of doing what I want, which is to include an inline of the non-defining side of a relationship. I don't want to declare the relationship on "Content" as then I'd have to define every single relationship to it inside that class which would introduce dependencies to other modules, which in my opinion it should know nothing about.

Using Django 1.6 on Python 3.3.

Edit: As indicated in the comments, I've decided to use inheritance. My initial concern about this was that I wanted the flexibility to be able to compose classes from multiple other classes. However, since the Django ORM does support multiple inheritance and if I'd realised that method was called "mixins" (new to Python) I would have got somewhere a lot sooner.

Example mixins with models:

from django.db import models

class Content(models.Model):
    """Basic page data which can be used by other modules"""
    title = models.CharField(max_length=200)
    html_title = models.CharField(max_length=200)
    meta_desc = models.CharField(max_length=200)
    keywords = models.CharField(max_length=200)
    content = models.TextField()

    def __str__(self):
        return self.title

    class Meta:
        abstract = True

class Data(models.Model):
    data_name = models.CharField(max_length=200)

    class Meta:
        abstract = True

class Page(Content, Data):
    """Concrete implementation of a basic page managed by the admin"""
    slug = models.SlugField()

And then I can just use it as one model in admin.py.

解决方案

Another solution is moving the OneToOneField from Content to Page

class Content(models.Model):
    """Basic page data which can be used by other modules"""
    title = models.CharField(max_length=200)
    html_title = models.CharField(max_length=200)
    meta_desc = models.CharField(max_length=200)
    keywords = models.CharField(max_length=200)
    content = models.TextField()
    page = models.OneToOneField(Page, primary_key=True, related_name="content")

class Page(models.Model):
    """Concrete implementation of a basic page managed by the admin"""
    slug = models.SlugField()

    def __str__(self):
        return self.content.title

You can still do page.content and the inline form will work out of the box

EDIT:

One cons of that approach is that it will allow the user to create a page without assigning any content to it (in which case page.content will crash)

Its very easy to overcome this issue by creating custom form

class ContentAdminForm(forms.ModelForm):

    def __init__(self, *args, **kwargs):
        kwargs["empty_permitted"] = False
        super(ContentAdminForm, self).__init__(*args, **kwargs)

Then in the admin page

class ContentInline(admin.TabularInline):

    model = Content
    form = ContentAdminForm
    fields = ('title', 'html_title', 'meta_desc', 'keywords', 'content')

这篇关于Django admin - OneToOneField inline throws“没有ForeignKey”例外的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆