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 ![]()
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 ![]()
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