Skip to main content
 首页 » 编程设计

python之模型表单在 django 中的外键上崩溃

2025年05月04日6JeffreyZhao

所以我正在尝试在管理页面中创建一个新的提要及其 因错误 IntegrityError 崩溃:lifestream_feed.lifestream_id 可能不为 NULL,已设置 form['lifestream'] 但 form.instance.lifestream 不是。

form.fields 甚至显示 lifestream 是一个 django.forms.models.ModelChoiceField

代码如下:

class FeedCreationForm(forms.ModelForm): 
    class Meta: 
        model = Feed 
        exclude = ['name', 'domain', 'fetchable'] 
 
    def parse_feed(self, feed_url): 
        feed = feedparser.parse(feed_url) 
 
        # Does the feed have errors 
        if feed['bozo']: 
            if feed['feed'].has_key("links"): 
                for link in feed['feed']['links']: 
                    if link["type"] == "application/rss+xml": 
                        feed = self.parse_feed(link['href']) 
                        if not feed['bozo']: 
                            return feed 
        else: 
            return feed 
 
        return None 
 
    def clean(self): 
        """ 
        Checks to make sure a feed url is valid and gets the feed 
title 
        and domain. 
        """ 
        feed_url = self.cleaned_data.get('url') 
        if not feed_url: 
            # Feed url was not validated by the field validator 
            return 
        feed = self.parse_feed(feed_url) 
        if feed: 
            feed_url = feed['url'] 
            self.cleaned_data['url'] = feed_url 
        else: 
            # the feed was not parsed correctly. 
            import logging 
 
            self._errors['url'] = ErrorList(["This is not a valid 
feed: %s" % feed['bozo_exception']]) 
            logging.error(feed['bozo_exception']) 
            # This field is no longer valid. Remove from cleaned_data 
            del self.cleaned_data['url'] 
            return 
 
        # Check if the feed has a title field 
        feed_info = feed.get('feed') 
        if not feed_info.get('title'): 
            self._errors['url'] = ErrorList(["This is not a valid 
feed: The feed is empty"]) 
            # This field is no longer valid. Remove from cleaned_data 
            del self.cleaned_data['url'] 
            return 
        self.cleaned_data['name'] = feed_info['title'] 
        self.instance.name = self.cleaned_data['name'] 
        self.cleaned_data['domain'] = get_url_domain(feed_url) 
        self.instance.domain = self.cleaned_data['domain'] 
 
        return self.cleaned_data 
 
class FeedAdmin(admin.ModelAdmin): 
    list_display    = ('name', 'lifestream', 'domain', 'fetchable') 
    list_filter     = ('domain', 'lifestream') 
    actions         = ['make_fetchable', 'make_unfetchable'] 
 
    add_form = FeedCreationForm 
    model = Feed 
 
    def make_unfetchable(self, request, queryset): 
        queryset.update(fetchable=False) 
    make_unfetchable.short_description = _(u"Mark as unfetchable") 
 
    def make_fetchable(self, request, queryset): 
        queryset.update(fetchable=True) 
    make_fetchable.short_description = _(u"Mark as fetchable") 
 
    def add_view(self, request): 
        if not self.has_change_permission(request): 
            raise PermissionDenied 
        if request.method == 'POST': 
            form = self.add_form(request.POST) 
            if form.is_valid(): 
                new_feed = form.save() 
                msg = _('The %(name)s "%(obj)s" was added 
successfully.') % {'name': 'user', 'obj': new_feed} 
                self.log_addition(request, new_feed) 
                if "_addanother" in request.POST: 
                    request.user.message_set.create(message=msg) 
                    return HttpResponseRedirect(request.path) 
                elif '_popup' in request.REQUEST: 
                    return self.response_add(request, new_feed) 
                else: 
                    request.user.message_set.create(message=msg + ' ' 
+ ugettext("You may edit it again below.")) 
                    # TODO: use reversed url 
                    return HttpResponseRedirect('../%s/' % 
new_feed.id) 
        else: 
            form = self.add_form() 
 
        return render_to_response('admin/lifestream/feed/ 
add_form.html', { 
            'title': _('Add feed'), 
            'form': form, 
            'is_popup': '_popup' in request.REQUEST, 
            'add': True, 
            'change': False, 
            'has_add_permission': True, 
            'has_delete_permission': False, 
            'has_change_permission': True, 
            'has_file_field': False, 
            'has_absolute_url': False, 
            'auto_populated_fields': (), 
            'opts': self.model._meta, 
            'save_as': False, 
            #'username_help_text': self.model._meta.get_field 
('username').help_text, 
            'root_path': self.admin_site.root_path, 
            'app_label': self.model._meta.app_label, 
        }, context_instance=template.RequestContext(request)) 
 
    def queryset(self, request): 
        return self.model.objects.feeds() 
 
admin.site.register(Feed, FeedAdmin) 
 
class Lifestream(models.Model): 
    """ 
    A lifestream. Lifestreams can be created per user. 
    """ 
    site = models.ForeignKey(Site, verbose_name=_(u"site")) 
    user = models.ForeignKey(User, verbose_name=_(u"user")) 
    slug = models.SlugField(_("slug"), help_text=_('Slug for use in 
urls (Autopopulated from the title).'), blank=True) 
    title = models.CharField(_("title"), max_length=255) 
 
    def __unicode__(self): 
        return self.title 
 
class FeedManager(models.Manager): 
    ''' Query only normal feeds. ''' 
 
    def feeds(self): 
        return super(FeedManager, self).get_query_set() 
 
    def fetchable(self): 
        return self.feeds().filter(fetchable=True) 
 
class Feed(models.Model): 
    '''A feed for gathering data.''' 
    lifestream = models.ForeignKey(Lifestream, verbose_name=_ 
('lifestream')) 
    name = models.CharField(_("feed name"), max_length=255) 
    url = models.URLField(_("feed url"), help_text=_("Must be a valid 
url."), verify_exists=True, max_length=1000) 
    domain = models.CharField(_("feed domain"), max_length=255) 
    fetchable = models.BooleanField(_("fetchable"), default=True) 
 
    # The feed plugin name used to process the incoming feed data. 
    plugin_class_name = models.CharField(_("plugin name"), 
max_length=255, null=True, blank=True, choices=getattr(settings, 
"PLUGINS", PLUGINS)) 
 
    objects = FeedManager() 
 
    def __unicode__(self): 
        return self.name  

它不返回空返回,它到达返回 self.cleaned_data:

-> return self.cleaned_data 
(Pdb) list 
 85             self.cleaned_data['name'] = feed_info['title'] 
 86             self.instance.name = self.cleaned_data['name'] 
 87             self.cleaned_data['domain'] = get_url_domain(feed_url) 
 88             self.instance.domain = self.cleaned_data['domain'] 
 89      
 90  ->         return self.cleaned_data 
 91      
 92     class FeedAdmin(admin.ModelAdmin): 
 93         list_display    = ('name', 'lifestream', 'domain', 'fetchable') 
 94         list_filter     = ('domain', 'lifestream') 
 95         actions         = ['make_fetchable', 'make_unfetchable'] 
(Pdb) self.cleaned_data 
{'url': u'http://twitter.com/statuses/user_timeline/6166742.rss', 'domain': u'twitter.com', 'lifestream': <Lifestream: Social>, 'name': u'Twitter / sontek', 'plugin_class_name': u'lifestream.plugins.twitter.TwitterPlugin'} 

请您参考如下方法:

我认为问题出在您的 clean() 方法中。

一般的 clean() 方法(与 clean_domain() 等字段特定的清理方法相对)必须返回 cleaned_data 字典(减去任何未验证的字段),并且您的 clean 方法中至少有 3 个不返回任何内容的返回值。

参见 here