我使用Flask和mongoengine创建了一个博客,也使用了Flask-Admin。当我在shell中创建帖子时,评论按预期工作,我可以从博客添加评论。当我从管理界面创建帖子时,我在尝试从博客添加评论时收到此错误:
ValidationError: ValidationError (Post.BlogPost:5616ab2478a3fd1b48a64d12) (Invalid embedded document instance provided to an EmbeddedDocumentField: ['comments'])
import datetime
from flask import url_for
from the_app.blog import db
class Comment(db.EmbeddedDocument):
created_at = db.DateTimeField(default=datetime.datetime.now,required=True)
body = db.StringField(verbose_name="Comment",required=True)
author = db.StringField(verbose_name="Name",max_length=255,required=True)
class Post(db.Document):
created_at = db.DateTimeField(default=datetime.datetime.now,required=True)
title = db.StringField(max_length=255,required=True)
slug = db.StringField(max_length=255,required=True)
body = db.StringField(required=True)
comments = db.ListField(db.EmbeddedDocumentField('Comment'))
def get_absolute_url(self):
return url_for('post',kwargs={"slug":self.slug})
def __unicode__(self):
return self.title
@property
def post_type(self):
return self.__class__.__name__
meta = {
'allow_inheritance':True,
'indexes':['-created_at','slug'],
'ordering':['-created_at']
}
class BlogPost(Post):
body = db.StringField(required=True)
class Video(Post):
embed_code = db.StringField(required=True)
class Image(Post):
image_url = db.StringField(required=True,max_length=255)
class Quote(Post):
body = db.StringField(required=True)
author = db.StringField(verbose_name="Author Name",required=True,max_length=255)
from flask import Blueprint, render_template, request, redirect, url_for
from flask.views import MethodView
from models import Comment, Post, BlogPost, Video, Image, Quote
from flask.ext.mongoengine.wtf import model_form
posts = Blueprint("posts",__name__,template_folder="templates")
class ListView(MethodView):
def get(self):
posts = Post.objects.all()
return render_template('list.html',posts=posts)
class DetailView(MethodView):
form = model_form(Comment, exclude=['created_at'])
def get_context(self,slug):
post = Post.objects.get_or_404(slug=slug)
form = self.form(request.form)
context = {
"post":post,
"form":form
}
return context
def get(self, slug):
context = self.get_context(slug)
return render_template('detail.html', **context)
def post(self, slug):
context = self.get_context(slug)
form = context.get('form')
if form.validate():
comment = Comment()
form.populate_obj(comment)
post = context.get('post')
post.comments.append(comment)
post.save()
return redirect(url_for('posts.detail', slug=slug))
return render_template('detail.html',**context)
# Register the urls
posts.add_url_rule('/',view_func=ListView.as_view('list'))
posts.add_url_rule('/<slug>/',view_func=DetailView.as_view('detail'))
from flask import Blueprint, request, redirect, render_template, url_for
from flask.views import MethodView
from flask.ext.mongoengine.wtf import model_form
from blog.auth import requires_auth
from blog.models import Comment, Post, BlogPost, Video, Image, Quote
admin = Blueprint("admin",__name__,template_folder='templates')
class List(MethodView):
decorators = [requires_auth]
cls = Post
def get(self):
posts = self.cls.objects.all()
return render_template('admin/list.html',posts=posts)
class Detail(MethodView):
decorators = [requires_auth]
# Map post types to models
class_map={
'post': BlogPost,
'video': Video,
'image': Image,
'quote': Quote,
}
def get_context(self,slug=None):
if slug:
post = Post.objects.get_or_404(slug=slug)
cls = post.__class__ if post.__class__ != Post else BlogPost
form_cls = model_form(cls, exclude=('created_at', 'comments'))
if request.method == 'POST':
form = form_cls(request.form, initial=post._data)
else:
form = form_cls(obj=post)
else:
cls = self.class_map.get(request.args.get('type', 'post'))
post = cls()
form_cls = model_form(cls, exclude=('created_at', 'comments'))
form = form_cls(request.form)
context = {
"post": post,
"form": form,
"create": slug is None
}
return context
def get(self, slug):
context = self.get_context(slug)
return render_template('admin/detail.html',**context)
def post(self,slug):
context = self.get_context(slug)
form = context.get('form')
if form.validate():
post = context.get('post')
form.populate_obj(post)
post.save()
return redirect(url_for('admin.index'))
return render_template('admin/detail.html',**context)
admin.add_url_rule('/admin/',view_func=List.as_view('index'))
admin.add_url_rule('/admin/create/',defaults= {'slug':None},view_func=Detail.as_view('create'))
admin.add_url_rule('/admin/<slug>/',view_func=Detail.as_view('edit'))