Export all drafting views in a Revit project as individual files

Has anyone come across, or created a script that can export all drafting views from a detail container file? I am trying to make the move to the Autodesk Content Catalog and have all views be searchable in there rather than opening and upgrading our detail container file every time someone needs to place a detail in a future version of revit, and since the content catalog have version management I figured it was worth a shot to ask.Saving out 400+drafting views from revit to individual files can be quite the time suck… Thanks in advance… I have been fighting and starting over for like 2 hours on this and made zero progress :slight_smile:

The exact method is not available in the API (at least not as far as I know).

However I believe you can utilize methods to create a new document from a file with minimal contwnt (ok no content) , and then copy a view from the current file into the new document, and save the new file as the view’s name.

I am not sure of any nodes or packages for this, but it is not too complex a Python script to write.

This Revit API forum post should give you some direction: Solved: Re: "Save to New File..." - Autodesk Community.

If they don’t have to be edited in your new project(s) you could make them DWGs and import those into your new project(s).

Hers’s a python script to transfer Drafting Views based on Revit SDK Samples - Duplicate Views

I’ve used the standard template - I would suggest creating a stripped back template for this

From my limited testing you may extend this by also transferring the view settings such as scale etc.

This code has a subclassed interface handler IDuplicateTypeNamesHandler it will only work in IronPython versions 2 or 3

import traceback

import clr

clr.AddReference("RevitServices")
from RevitServices.Persistence import DocumentManager

clr.AddReference("RevitAPI")
from Autodesk.Revit.DB import *


# Duplicate Type name handler
class HideAndAcceptDuplicateTypeNamesHandler(IDuplicateTypeNamesHandler):
    def OnDuplicateTypeNamesFound(self, args):
        return DuplicateTypeAction.UseDestinationTypes


doc = DocumentManager.Instance.CurrentDBDocument
uiapp = DocumentManager.Instance.CurrentUIApplication
app = uiapp.Application

# Paths
template = "C:\\ProgramData\\Autodesk\\RVT 2024\\Templates\\Default_M_ENU.rte"
out_path = "C:\\temp\\"

# Defaults
sao = SaveAsOptions()
sao.OverwriteExistingFile = True

copypasteoptions = CopyPasteOptions()
copypasteoptions.SetDuplicateTypeNamesHandler(HideAndAcceptDuplicateTypeNamesHandler())

# Drafting Views in current document
views = FilteredElementCollector(doc).OfClass(ViewDrafting).ToElements()

output = []

for view in views:
    # Get and filter elements
    collector = FilteredElementCollector(view.Document, view.Id)
    collector.WherePasses(ElementCategoryFilter(ElementId.InvalidElementId, True))

    elems = collector.ToElementIds()

    # Create doc
    new_doc = app.NewProjectDocument(template)
    with Transaction(new_doc, "Transfer Drafting View") as t:
        t.Start()

        viewfamilytype = next(
            vft
            for vft in FilteredElementCollector(new_doc).OfClass(ViewFamilyType)
            if vft.ViewFamily == ViewFamily.Drafting
        )

        try:
            new_view = ViewDrafting.Create(new_doc, viewfamilytype.Id)
            new_view.Name = view.Name
            ElementTransformUtils.CopyElements(
                view, elems, new_view, Transform.Identity, copypasteoptions
            )

        except Exception:
            output.append(traceback.format_exc())

        t.Commit()

        filepath = out_path + new_view.Name + ".rvt"

        new_doc.SaveAs(filepath, sao)
        new_doc.Close(False)

        output.append(filepath)

OUT = output

Just a thought. Why not have the views loaded in a project template file that everyone uses when starting a new project? Even 400+ drafting views, shouldn’t impact the file size that much. It would be a one time upgrade of all of the views when they start the project using the template file and then when the project is done, purge out any unused views.

EDIT: Or to elaborate on @bvs1982 suggestion. If they are permanent details, then export all out to separate dwg’s. Then you could set up a dynamo script similar to mimic a detail library and import the dwg back into a drafting/legend view by user selection.

the save as by right click on drafting view in proj browser command is implemented internally in the ui layer

it doesn’t have a public viewsavetonewfile or equivalent in the api. sucks bc im trying to batch out a bunch of drafting views into separate files (without tons of py to purge copy elements temp files etc) and index as an xlsx with clickable links to open each standalone drafting view.

i did manage to get it working. here is the script.py extension which exports open drafting views as standalone revit files which are linked into a clickable excel index that you can update (by running the script for additional drafting views) complete with smart timestamps. just open the desired drafting views and click the draftingexport tab in the ribbon. itll prompt for the destination folder, click ok for each view it asks to run. the excel will then open when it’s finished

-- coding: utf-8 --

from Autodesk.Revit.DB import *
from pyrevit import forms, revit
import os, datetime

Excel COM

import clr
clr.AddReference(“Microsoft.Office.Interop.Excel”)
import Microsoft.Office.Interop.Excel as Excel

.NET list for forcing correct overload

from System.Collections.Generic import List

doc = revit.doc
uidoc = revit.uidoc
app = doc.Application

Ask user for folder

save_folder = forms.pick_folder(“Select folder to save drafting views as RVTs”)

if save_folder:

Collect only currently open views

open_views = [doc.GetElement(v.ViewId) for v in uidoc.GetOpenUIViews()]
drafting_views = [v for v in open_views if isinstance(v, ViewDrafting) and not v.IsTemplate]

if not drafting_views:
    forms.alert("No open drafting views found. Please open drafting views in Revit first.", exitscript=True)

# Prepare existing timestamp map if index already exists
excel_filename = os.path.join(save_folder, "DetailIndex.xlsx")
old_timestamps = {}

if os.path.exists(excel_filename):
    try:
        old_excel = Excel.ApplicationClass()
        old_excel.Visible = False
        wb_old = old_excel.Workbooks.Open(excel_filename)
        ws_old = wb_old.Sheets[1]
        row = 2
        while ws_old.Cells(row,1).Value2:
            detail_name = str(ws_old.Cells(row,1).Value2)
            timestamp = str(ws_old.Cells(row,4).Value2)
            old_timestamps[detail_name] = timestamp
            row += 1
        wb_old.Close(False)
        old_excel.Quit()
    except:
        pass

# Create new Excel workbook
excel = Excel.ApplicationClass()
excel.Visible = False
wb = excel.Workbooks.Add()
ws = wb.Sheets[1]

# Headers
ws.Cells(1,1).Value2 = "Detail Name"
ws.Cells(1,2).Value2 = "Hyperlink"
ws.Cells(1,3).Value2 = "Folder"
ws.Cells(1,4).Value2 = "Exported On"

row = 2
now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")

# Progress bar
with forms.ProgressBar(title="Exporting Drafting Views ({value} of {max_value})",
                       cancellable=True, step=1) as pb:

    for i, v in enumerate(drafting_views):
        pb.update_progress(i+1, len(drafting_views))
        if pb.cancelled:
            break

        try:
            safe_name = "".join([c if c.isalnum() else "_" for c in v.Name])
            filename = os.path.join(save_folder, safe_name + ".rvt")

            timestamp = old_timestamps.get(safe_name, now)

            if not os.path.exists(filename):
                # --- STEP 1: Create a fresh new RVT ---
                newdoc = app.NewProjectDocument(UnitSystem.Imperial)  # or .Metric if needed

                try:
                    # --- STEP 2: Create a Drafting View ---
                    view_family_types = FilteredElementCollector(newdoc).OfClass(ViewFamilyType).ToElements()
                    drafting_vft = [vft for vft in view_family_types if vft.ViewFamily == ViewFamily.Drafting][0]

                    t = Transaction(newdoc, "Create Drafting View")
                    t.Start()
                    new_view = ViewDrafting.Create(newdoc, drafting_vft.Id)
                    new_view.Name = v.Name
                    t.Commit()

                    # --- STEP 3: Copy elements from source view ---
                    ids = FilteredElementCollector(doc, v.Id).ToElementIds()
                    if ids:
                        id_list = List[ElementId](ids)  # force correct overload
                        t2 = Transaction(newdoc, "Copy Drafting Elements")
                        try:
                            t2.Start()
                            ElementTransformUtils.CopyElements(v, id_list, new_view, Transform.Identity, None)
                            t2.Commit()
                        except:
                            if t2.HasStarted():
                                t2.RollBack()
                            raise

                    # --- STEP 4: Save the new RVT ---
                    save_opts = SaveAsOptions()
                    save_opts.OverwriteExistingFile = True
                    newdoc.SaveAs(filename, save_opts)

                finally:
                    # --- STEP 5: Ensure clean close ---
                    try:
                        newdoc.Close(False)
                    except:
                        pass

                timestamp = now

            # --- STEP 6: Update Excel row ---
            ws.Cells(row,1).Value2 = safe_name
            ws.Hyperlinks.Add(ws.Cells(row,2), filename, "", "", safe_name)
            ws.Cells(row,3).Value2 = save_folder
            ws.Cells(row,4).Value2 = timestamp
            row += 1

        except Exception as e:
            forms.alert("Failed on view {}: {}".format(v.Name, str(e)))

# Save Excel index
wb.SaveAs(excel_filename, FileFormat=51)
wb.Close(True)

# Auto-open Excel
excel.Visible = True
excel.Workbooks.Open(excel_filename)

forms.alert("Processed {} open drafting views.\nExcel index updated:\n{}".format(len(drafting_views), excel_filename),
            exitscript=True)

Hi Johannes, welcome :wave:
Please take the time to review How to get help on the Dynamo forums

Your code is in part unformatted, requires pyrevit which may not necessarily be available to Dynamo and the Excel interop which does not operate with current .NET frameworks

My code responded and reasonably solved the original post, it would be trivial to use OOTB nodes to save the list of filenames to an Excel file

This post is also a year old, so before responding, please ask if you are actually contributing to the topic’s conversation