7
$\begingroup$

How to create a Collection inside another existing Collection with Python? enter image description here

$\endgroup$
1
  • 4
    $\begingroup$ bpy.context.scene.collection.children['Collection'].children.link(bpy.data.collections.new('Sub Collection')) $\endgroup$ Feb 19, 2020 at 13:28

2 Answers 2

13
$\begingroup$

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)
$\endgroup$
6
  • 1
    $\begingroup$ Simply coll.name in console will print. $\endgroup$
    – batFINGER
    Feb 19, 2020 at 16:30
  • 1
    $\begingroup$ Do you think this makes it easier to read for beginners? @batFINGER $\endgroup$
    – brockmann
    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$
    – batFINGER
    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$
    – brockmann
    Feb 20, 2020 at 14:06
  • 1
    $\begingroup$ @brockmann Fair enough :) $\endgroup$ Feb 20, 2020 at 15:41
0
$\begingroup$

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)
$\endgroup$
3
  • $\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$
    – brockmann
    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$
    – spiraloid
    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$
    – brockmann
    Jun 4, 2020 at 7:16

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .