Django admin - OneToOneField inline throws“没有ForeignKey”例外 [英] Django admin - OneToOneField inline throws "has no ForeignKey" exception
问题描述
我这样做的原因是,我可以将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 = Contentfields =('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屋!