How to create a Collection inside another existing Collection with Python?
2 Answers
Each collection has a children
(collection) property. Easy to figure out using the python console:
>>> C.scene.collection.
all_objects
animation_data_clear(
animation_data_create(
as_pointer(
bl_rna
bl_rna_get_subclass(
bl_rna_get_subclass_py(
children
...
To get the first level of all sub-collections, you can just iterate through the list:
>>> for coll in C.scene.collection.children:
... print (coll.name)
...
Collection
Collection 2
Collection 3
...
To add a new collection, create a new data-block and then use .link(collection)
method to add it to whatever your main collection is:
>>> C.scene.collection.children.link(
link()
CollectionChildren.link(child)
Add this collection as child of this collection
>>> my_sub_coll = bpy.data.collections.new("My Sub Collection")
>>> C.scene.collection.children.link(my_sub_coll)
The same principle applies to all collections, no matter the collection is on the first or any other level. Example on how to add a new (sub) collection to the active collection:
>>> active_coll = C.view_layer.active_layer_collection.collection
>>> active_coll.children.link(my_sub_coll)
You can also specify the each collection by its name C.scene.collection.children["Collection"]
or you can even use the index operator C.scene.collection.children[0]
but that's error prone. In case the name of the collection or the scene hierarchy changes you're lost. Better practice is using pythons get()
method to basically perform a search for the collection in the first place:
>>> C.scene.collection.children.get("Collection")
bpy.data.collections['Collection']
Basic example using .get()
:
import bpy
C = bpy.context
main_coll = C.scene.collection.children.get("Collection")
if main_coll:
# Create the new collection
my_sub_coll = bpy.data.collections.new("My Sub Collection")
# Add it to the found collection
main_coll.children.link(my_sub_coll)
Advanced example on how to add a new collection to an arbitrary collection in the scene using a recursive loop based on https://blender.stackexchange.com/a/137866:
import bpy
def traverse_tree(t):
yield t
for child in t.children:
yield from traverse_tree(child)
coll = bpy.context.scene.collection
for c in traverse_tree(coll):
if c.name == "MyCollection": # Specify the name of you main collection here
my_sub_coll = bpy.data.collections.new("My Sub Collection")
# Add it to the main collection
c.children.link(my_sub_coll)
Notice that you add objects to the collection(s) the same way by just passing an object when calling the .link(object)
method on the actual object (collection) property, which is actually pretty nice and convenient:
>>> my_sub_coll.objects.link(C.object)
-
1
-
1$\begingroup$ Do you think this makes it easier to read for beginners? @batFINGER $\endgroup$ Feb 19, 2020 at 16:35
-
2$\begingroup$ Possibly not. IMO It is easier to sniff around in console without typing in print and its braces. Prob realize: I'm a fan of answers explaining via use of console $\endgroup$ Feb 19, 2020 at 16:41
-
3$\begingroup$ The OP should be able to apply the principle to whatever collection based on this answer "then use .link(collection) method to add it to whatever your main collection is". Specifying the name is bad practice IMO, I added an example using
get()
for completeness @Pisurquatre $\endgroup$ Feb 20, 2020 at 14:06 -
1
posting how I do this in blender 2.90 for others in case it's useful.
doing it like this doesn't require context or ui polling.
import bpy
#create scene collection
shared_assets_collection_name = "Shared Assets"
shared_assets_collection = bpy.data.collections.new(shared_assets_collection_name)
bpy.context.scene.collection.children.link(shared_assets_collection)
#create subcollection
cname = "Actors"
c = bpy.data.collections.new(cname)
bpy.data.collections.get(shared_assets_collection_name).children.link(c)
-
$\begingroup$ How this is different to my answer? ... Apparently nothing changed. Also you're linking a new collection to the scene collection in context -> *"this doesn't require context or ui polling." not sure what you mean by that. $\endgroup$ Jun 3, 2020 at 8:35
-
$\begingroup$ yeah you're right they are both similiar. I couldn't find a 3 line solution that compiled so I thought I'd post one. although a two line version might have been better.
my_collection = bpy.data.collections.new("My Collection Name Here") bpy.context.scene.collection.children.link(my_collection)
$\endgroup$ Jun 4, 2020 at 5:48 -
1$\begingroup$ For a minimal example see Basic example using .get() in my answer. Consider that your version of it:
bpy.data.collections.get(shared_assets_collection_name).children.link(c)
can error. $\endgroup$ Jun 4, 2020 at 7:16
bpy.context.scene.collection.children['Collection'].children.link(bpy.data.collections.new('Sub Collection'))
$\endgroup$