Is it possible to use a field for the filename of an attachment export?

1047
10
Jump to solution
06-14-2018 01:46 PM
CraigSchellenbach1
New Contributor III

Hello,

I am able to export photo attachments with the generic script but I would like to name them based on a field on the record they are attached to. The field I would like to use is 'FID' and it's unique to each row in the table. The current code I use is. 

import arcpy
from arcpy import da
import os

inTable = arcpy.GetParameterAsText(0)
fileLocation = arcpy.GetParameterAsText(1)

with da.SearchCursor(inTable, ['DATA', 'ATT_NAME', 'Access Point FQN_ID']) as cursor:
for item in cursor:
attachment = item[0]
filenum = "ATT" + str(item[2]) + "_"
filename = filenum + str(item[1])
open(fileLocation + os.sep + filename, 'wb').write(attachment.tobytes())
del item
del filenum
del filename
del attachment

0 Kudos
1 Solution

Accepted Solutions
RandyBurton
MVP Regular Contributor

This will get filename information from the master feature class and save an attachment in a related table.

import arcpy

masterFC = r"C:\Path\to\file.gdb\masterFC"
masterFlds = ['GlobalID', 'Name']
# Use list comprehension to build a dictionary from a da SearchCursor  
masterDict = {r[0]:(r[1:]) for r in arcpy.da.SearchCursor(masterFC, masterFlds)}

print masterDict

relatedTbl = r'C:\Path\to\file.gdb\related_ATTACH'
relatedFlds = ['REL_GLOBALID', 'ATT_NAME', 'DATA']

fileLocation = r'C:\Path\to\attachments'

with arcpy.da.SearchCursor(relatedTbl, relatedFlds) as cursor:
    for item in cursor:

        # item[0] is related GlobalID; take first item in masterDict tuple with that key
        f1 = masterDict[item[0]][0].replace(" ","_") # replacing spaces
        # assuming attachment name starts with "attachment", remove that part and keep rest
        f2 = item[1][10:] # can use .split('.')[1:] or similar to get just extension
        # make new filename 
        filename = "ATT_{}_{}".format(f1, f2)
        print filename
        
        open(fileLocation + os.sep + filename, 'wb').write(item[2].tobytes())

del cursor‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

This assumes that the master feature class contains some attributes like:

Master Feature Class

And the related attachments table is something like:

Attachment Table

The dictionary and filenames created are:

# print masterDict

{u'{B0174984-E7EB-47EA-A49A-9D535CFD6125}': (u'State Office Building',), u'{43902175-71ED-47DB-BCC8-6C805D930D23}': (u'State Capitol',)}

# print filename

ATT_State_Capitol_1.jpg
ATT_State_Capitol_2.jpg
ATT_State_Office_Building_1.jpg‍‍‍‍‍‍‍

Hope this helps.

View solution in original post

10 Replies
DanPatterson_Retired
MVP Esteemed Contributor

/blogs/dan_patterson/2016/08/14/script-formatting would help make sure there aren't any formatting errors Craig.

Also, I don't see where you added the FID field into the searchcursor.  You will need that for your id numbers.

I presume that you haven't tested this yet?

0 Kudos
CraigSchellenbach1
New Contributor III

import arcpy
from arcpy import da
import os

inTable = arcpy.GetParameterAsText(0)
fileLocation = arcpy.GetParameterAsText(1)

with da.SearchCursor(inTable, ['DATA', 'ATT_NAME', 'ATTACHMENTID']) as cursor:
for item in cursor:
attachment = item[0]
filenum = "ATT" + str(item[2]) + "_"
filename = filenum + str(item[1])
open(fileLocation + os.sep + filename, 'wb').write(attachment.tobytes())
del item
del filenum
del filename
del attachment

The code is what I used. I posted the wrong code earlier.

0 Kudos
CraigSchellenbach1
New Contributor III

I don't know if I explained what I was trying to say earlier. I need a way to save the images and have the filename be the ID of the record they are attached to or have the filename include a field from the record they are attached too. I will give an example.

Record in table is {D40A7E01-4D12-453C-A69E-BEB4E59D9A2C}. The ID in the attachment table is df6ea7eb9fb3464f9313cae304c2b27d. 

Is this possible to do this or export the relationship table?

0 Kudos
RandyBurton
MVP Regular Contributor

The record for the attachment should contain the global ID of the linked/master record in one of the fields.  As shown my example code, you can work it into the file name.  If the master record can have multiple attachments, you will need to use some sort of count, perhaps the attachment ID, to make a unique filename.  You will want to append a file extension which could be obtained from splitting the filename at the dot in your code or by using the data in the content type field to create an extension.

If you want to create a filename using data from the master record other than the global/linking ID field, you should be able to do that by using some sort of join with the master table or creating a dictionary of the master record feature/table.

I will work on a code sample later today or this weekend that illustrates this.

0 Kudos
RandyBurton
MVP Regular Contributor

I really didn't find any major problems with your script.  For testing, my script was similar:

import arcpy, os

inTable = r'C:\Path\to\file.gdb\feature__ATTACH'
fileLocation = r'C:\Path\to\attachments'

with arcpy.da.SearchCursor(inTable, ['DATA', 'ATT_NAME', 'ATTACHMENTID']) as cursor:
    for item in cursor:
        print "ATT_NAME: {}  - ATTACHMENTID: {}".format(item[1], item[2])
        filename = "ATT_{}_{}".format(item[2], item[1])
        print filename
        open(fileLocation + os.sep + filename, 'wb').write(item[0].tobytes())

del cursor‍‍‍‍‍‍‍‍‍‍‍‍‍

I would suggest testing with some print statements (or AddMessage), to see that  your input table and file location strings are being interpreted correctly.  For the filename, you might want to start with the attachment ID as the ATT_NAME field may include a file extension.  If it does not contain an extension, you may need to look at the CONTENT_TYPE field so your code can append one if necessary.

RandyBurton
MVP Regular Contributor

This will get filename information from the master feature class and save an attachment in a related table.

import arcpy

masterFC = r"C:\Path\to\file.gdb\masterFC"
masterFlds = ['GlobalID', 'Name']
# Use list comprehension to build a dictionary from a da SearchCursor  
masterDict = {r[0]:(r[1:]) for r in arcpy.da.SearchCursor(masterFC, masterFlds)}

print masterDict

relatedTbl = r'C:\Path\to\file.gdb\related_ATTACH'
relatedFlds = ['REL_GLOBALID', 'ATT_NAME', 'DATA']

fileLocation = r'C:\Path\to\attachments'

with arcpy.da.SearchCursor(relatedTbl, relatedFlds) as cursor:
    for item in cursor:

        # item[0] is related GlobalID; take first item in masterDict tuple with that key
        f1 = masterDict[item[0]][0].replace(" ","_") # replacing spaces
        # assuming attachment name starts with "attachment", remove that part and keep rest
        f2 = item[1][10:] # can use .split('.')[1:] or similar to get just extension
        # make new filename 
        filename = "ATT_{}_{}".format(f1, f2)
        print filename
        
        open(fileLocation + os.sep + filename, 'wb').write(item[2].tobytes())

del cursor‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

This assumes that the master feature class contains some attributes like:

Master Feature Class

And the related attachments table is something like:

Attachment Table

The dictionary and filenames created are:

# print masterDict

{u'{B0174984-E7EB-47EA-A49A-9D535CFD6125}': (u'State Office Building',), u'{43902175-71ED-47DB-BCC8-6C805D930D23}': (u'State Capitol',)}

# print filename

ATT_State_Capitol_1.jpg
ATT_State_Capitol_2.jpg
ATT_State_Office_Building_1.jpg‍‍‍‍‍‍‍

Hope this helps.

CraigSchellenbach1
New Contributor III

Thanks Randy! That is exactly what I needed!

0 Kudos
by Anonymous User
Not applicable

So I've been following these instructions. This is my code:

----------------------------------------------------------------------------------------------------------

import arcpy

masterFC = r"C:\Users\kameehan\OneDrive - Westwood Active Directory\Documents\Project_Documents\UI_Railroad\Shapefiles\Observations_FGDB\UI_Walkdown_Observations.gdb\Observations"
masterFlds = ['GlobalID', 'NAME']
# Use list comprehension to build a dictionary from a da SearchCursor
masterDict = {r[0]:(r[1:]) for r in arcpy.da.SearchCursor(masterFC, masterFlds)}

print(masterDict)

relatedTbl = r'C:\Users\kameehan\OneDrive - Westwood Active Directory\Documents\Project_Documents\UI_Railroad\Shapefiles\Observations_FGDB\UI_Walkdown_Observations.gdb\Observations_ATTACH'
relatedFlds = ['REL_GLOBALID', 'ATT_NAME', 'DATA']

fileLocation = r'C:\Users\kameehan\OneDrive - Westwood Active Directory\Documents\Project_Documents\UI_Railroad\Shapefiles\Observations_FGDB\UI_Walkdown_Observations.gdb\Observations_ATTACH'


with arcpy.da.SearchCursor(relatedTbl, relatedFlds) as cursor:
for item in cursor:

# item[0] is related GlobalID; take first item in masterDict tuple with that key
f1 = masterDict[item[0]][0].replace(" ","_") # replacing spaces
# assuming attachment name starts with "attachment", remove that part and keep rest
f2 = item[1][10:] # can use .split('.')[1:] or similar to get just extension
# make new filename
filename = "ATT_{}_{}".format(f1, f2)
print (filename)

open(fileLocation + os.sep + filename, 'wb').write(item[2].tobytes())

del cursor

---------------------------------------------------------------------------------------------------------------------------

and I keep getting this error:

Traceback (most recent call last):   File "C:\Users\kameehan\OneDrive - Westwood Active Directory\Documents\ExportAttachments2.py", line 16, in <module>     with arcpy.da.SearchCursor(relatedTbl, relatedFlds) as cursor: RuntimeError: cannot open 'C:\Users\kameehan\OneDrive - Westwood Active Directory\Documents\Project_Documents\UI_Railroad\Shapefiles\Observations_FGDB\UI_Walkdown_Observations.gdb\Observations_ATTACH'
Failed to execute (ExportAttachments2).

And I'm not sure how to fix it or what is wrong. As in why won't it open that file path?
0 Kudos
by Anonymous User
Not applicable

rvburton Please let me know if you have any clue, or might need more information to potentially help, if you could!

0 Kudos