There is a pretty nice example using BlendDataLibraries and a relative path in the API: https://docs.blender.org/api/current/bpy.types.BlendDataLibraries.html
Example script to append all objects named Cube...
from a blend file called link_library.blend
in the same folder as the script:
import bpy
import os
# "//" prefix is a Blender specific identifier for the current blend file
#filepath = "//link_library.blend"
#abs_filepath = bpy.path.abspath(filepath) # returns the absolute path
# os.path.abspath(__file__) returns path to the script
filepath = os.path.join(os.path.dirname(os.path.abspath(__file__)), "link_library.blend")
# link all objects starting with 'Cube'
with bpy.data.libraries.load(filepath, link=False) as (data_from, data_to):
data_to.objects = [name for name in data_from.objects if name.startswith("Cube")]
# link object to scene collection
for obj in data_to.objects:
if obj is not None:
bpy.context.collection.objects.link(obj)
Assuming the folder structure is like:
my_folder/
├── my_script.py
├── link_library.blend/
├── Objects
├── Cube
Further reading:
Can be wrapped into an operator easily. I suggest declare at least two StringProperties, one to hold the name of the blend and another one for the actual object name, which basically allows to pass arguments when calling the operator or when adding the operator to any layout:
class MY_OT_custom_append(bpy.types.Operator):
...
blend = StringProperty(name="Library Blend File")
object_name = StringProperty(name="Object Name")
...
# On a panel
class MY_PT_custom_panel(Panel):
...
row = layout.row()
props = row.operator(MY_OT_custom_append.bl_idname)
props.blend = "link_library.blend"
props.object_name = "Cube"
...
...
# Test call
bpy.ops.scene.custom_append(blend="link_library.blend", object_name="Cube")
Read: How to pass multiple operator properties via UI layout?
custom_append.py
Panel and operator example to append given/known objects from another blend file next to the Add-on (see the folder structure above):
bl_info = {
"name": "Custom Append Add-on",
"description": "",
"author": "",
"version": (0, 1),
"blender": (2, 80, 0),
"location": "3D View > Tools",
"warning": "", # used for warning icon and text in addons panel
"wiki_url": "",
"tracker_url": "",
"category": "Development"
}
import bpy
import os
from bpy.props import StringProperty
from bpy.types import Panel, Operator
# ------------------------------------------------------------------------
# Append Operator
# ------------------------------------------------------------------------
class MY_OT_custom_append(bpy.types.Operator):
bl_idname = "scene.custom_append"
bl_label = "Custom Append Operator"
bl_options = {'REGISTER'}
blend = StringProperty(name="Library Blend File")
object_name = StringProperty(name="Object Name")
def execute(self, context):
# os.path.abspath(__file__) returns path to the addon
filepath = os.path.join(os.path.dirname(os.path.abspath(__file__)), self.blend)
# -> Test whether the file exist
if not os.path.isfile(filepath):
self.report({'WARNING'},"{} does not exist".format(self.blend))
return {'CANCELLED'}
# link all objects starting with 'Cube'
with bpy.data.libraries.load(filepath, link=False) as (data_from, data_to):
data_to.objects = [name for name in data_from.objects if name == self.object_name]
# -> Test whether the obejct exist
if not data_to.objects:
self.report({'WARNING'},"{} not found in {}".format(self.object_name, self.blend))
return {'CANCELLED'}
# link object to scene collection
for obj in data_to.objects:
if obj is not None:
# Append to active collection
active_coll = context.view_layer.active_layer_collection
active_coll.collection.objects.link(obj)
# Append to main collection
# context.collection.objects.link(obj)
return {'FINISHED'}
# ------------------------------------------------------------------------
# Panel in Object Mode
# ------------------------------------------------------------------------
class MY_PT_custom_panel(Panel):
bl_idname = "OBJECT_PT_my_panel"
bl_label = "My Panel"
bl_space_type = "VIEW_3D"
bl_region_type = "UI"
bl_category = "Tools"
bl_context = "objectmode"
def draw(self, context):
layout = self.layout
file_name = "link_library.blend"
object_name_01 = "Cube"
object_name_02 = "Sphere"
row = layout.row()
props = row.operator(MY_OT_custom_append.bl_idname, text="Append {}".format(object_name_01))
props.blend = file_name
props.object_name = object_name_01
row = layout.row()
props = row.operator(MY_OT_custom_append.bl_idname, text="Append {}".format(object_name_02))
props.blend = file_name
props.object_name = object_name_02
layout.separator()
# ------------------------------------------------------------------------
# Registration
# ------------------------------------------------------------------------
classes = (
MY_OT_custom_append,
MY_PT_custom_panel
)
def register():
from bpy.utils import register_class
for cls in classes:
register_class(cls)
def unregister():
from bpy.utils import unregister_class
for cls in reversed(classes):
unregister_class(cls)
if __name__ == "__main__":
register()
Further reading: How to create a custom UI?