New item created using plone.api.content.create() is not showing in portal

This a browser view that is supposed to migrate files to a new content type "material"
It returns output, suggesting that it was successful, but there are no signs of the new item that it should have created. What could be the problem?

import os
from plone import api
from Products.Five import BrowserView

class PDFToMaterialContentType(BrowserView):
    def __call__(self):
        return self.convert_pdf_to_materials()

    def all_files(self):
        """ return all files in the current context """
        return api.content.find(

    def convert_pdf_to_materials(self):
        properties = ['file','description']
        out = []
        for item in self.all_files():
            item = item.getObject()
            # migrate File to Material
            new_item = api.content.create(
            for property in properties:
                setattr(new_item, property, getattr(item, property))
            out.append(f"new item: {new_item.title},{new_item.file}::{new_item.absolute_url()}")
        return {"output":out}    

pdb is your friend.

No quarrels there.

It was due to CSRF protection.
To test it I launched my dev instance with the env var set as PLONE_CSRF_DISABLED=1

I'll work out the best way forward based on this knowledge.

It's just but responsibilities doing basic debugging and providing reasonable insights.
Throwing code at the community is unlikely helpful for getting reasonable help.

Absolutely fair, there were definitely gaps in what I communicated. @zopyx, your prompt was helpful and nudged me towards some additional actions, which allowed me to isolate the issue.

Here's the background etc.. (for others and my future self):

  1. My code includes a corresponding configure.zcml file which registers the browserview. Here's the snippet from the file.
  1. Calling the url of my registered browserview directly triggered Plone's built-in cross site request protection (CSRF). This effectively prevented the creation of the content.
  2. I was using a docker container and the output was not verbose enough for me to pick up the error (or I was reading the wrong logs).
  3. I was able to find the error after recreating my setup outside of docker (there's well-written mxdev documentation on managing packages in a non-dockerised setup, see: Manage add-ons and packages – Install — Plone Documentation v6.0)
  4. The following output in the console tipped me off:
aborting transaction due to no CSRF protection on url http://localhost:8080/Plone/migrate_pdfs_to_materials 
  1. For the sake of testing, I launched my backend with CSRF disabled
make start

With CSRF disabled, calling view successfully created the content.

:warning: :biohazard: DO NOT DISABLE CSRF IN PRODUCTION :warning: :biohazard: I only did this to isolate the issue in development. All of this was meant to be a quick proof of concept. I will use a different strategy to deal with the CSRF protection when I'm sorting out the final code.

Thanks @zopyx!

I'd use IDisableCSRFProtection .

The log message is from plone.protect/plone/protect/ at 27b125e22cf6a81ed5d53650e272e52d4ee3870e · plone/plone.protect · GitHub

My final implementation included a page template with a form and button. This removes the CSRF issues. This removes the need to disable the CSRF protection.

1 Like