Grab the domain's values when exporting attachments

467
4
Jump to solution
02-11-2022 11:28 AM
AlfredBaldenweck
MVP Regular Contributor

Hey all,

I'm using field values as input for naming exported attachments, and I'm running into an issue with domains.

Namely, if the field uses a coded value domain, it will grab the code and not the value. 

How can I grab the value?

I found this post here but I'm not sure how to put it together; I was able to create the initial dictionary of codes and values, but I'm not sure how to connect that to my fields afterwards.

The code runs as :

  1. Look up the RELKEY from the Attachment Table in the Feature Class
  2. Grab the Name from the Feature Class (End here if no domain or if the domain is a range.)
  3. Use the Name from the Feature Class to Lookup the Coded value in the Domain Table
  4. Grab the Value for the Code from the Domain Table AlfredBaldenweck_0-1644606698839.png

I have steps 1,2, and 4, but I can't figure out how to make step 3 work.

Code sample

 

 

'''Rough order of how I think it should go? 
Step 1 is definitely supposed to be at the bottom'''

'''Step 4''' # Mostly lifted directly from that example I link
testDom = arcpy.ListFields(inFC)
for field in testDom:
    if field.domain != "": #I only care about domains if there is one. Also need to specify that it's a coded value domain somehow.
        cvdTable = arcpy.DomainToTable_management(myGDB, field.domain, 'in_memory/cvdTable', 'codeField', 'descriptionField')
        d = {}  #Create an empty dictionary.
        rows = arcpy.SearchCursor(cvdTable)  #Create a cursor to loop through the table holding the domain and code info 
        for row in rows:   # Loop through each row in the table. 
            d[row.codeField] = row.descriptionField # For each row in the table populate the key with the code field and the value from the description field   

'''Step 2'''
primeNames = dict()
with arcpy.da.SearchCursor(FeatureClass, [relPairO, nameField1]) as cursor:
    for row in cursor:
        primeNames[row[0]] = row[1] #Every time you check this dictionary for the relation key, it will direct you to the right entry in the primary naming field.



'''Step 1'''
with arcpy.da.SearchCursor(inTable,['DATA', 'ATT_NAME', 'ATTACHMENTID', relPairA]) as cursor:
    for row in cursor:
        relPairKey = row[3] 
        fieldValue = primeNames[relPairKey] # Value of specified field in feature class

 

 

 

Also, this is a total beginner question, but in the example that I linked, what happens to that domain table? Is it automatically deleted?

 

Thanks!

0 Kudos
1 Solution

Accepted Solutions
AlfredBaldenweck
MVP Regular Contributor

I ended up making a table from the domain, then joining to the original FC.

Below is my code sample, with the addition of lines #6-13, which validate that the domain is a Code Value Domain (checked in line #16).

This validation is necessary; if you use a Range domain with this workflow otherwise, it will return "Min Value", "Max Value", or nothing.

I have a little more stuff to do on this project, but the end is very near.

 

Thanks everyone!

def grabDomain (workspace, inFC, namefield, relPairO): 
    '''Grabs the Coded Value of a coded Value Domain'''
    ''' Otherwise just grabs the field's value'''

    names = dict()
    
    rawDomain = arcpy.da.ListDomains(workspace) #list of all domains in the GDB
    valDomain = [] #list of valid domains
    for dom in rawDomain:
        if dom.domainType != "Range": #add Coded Value Domains to the valid list
            valDomain.append(dom.name)
            
    listFlds = arcpy.ListFields(inFC, namefield)
    for field in listFlds:
        if (field.domain != "") and (field.domain in valDomain): #For retreiving Coded values
            #Create an in-memory table representing the domain.
            codeTable = arcpy.DomainToTable_management(workspace, field.domain, 'in_memory/codeTable', "codeField", "descriptionField")
            inFC2 = arcpy.management.AddJoin(inFC, namefield, codeTable, "codeField") # Join said table to your Feature Class.
            
            # Okay this next part is kinda tricky
            # perform your search cursor on the joined feature class, but use the ORIGINAL FC to find the field names.
            with arcpy.da.SearchCursor(inFC2, [f"{inFC}.{relPairO}", f"{inFC}.{namefield}", f"codeTable.descriptionField"]) as cursor:
                for row in cursor:
                    names[row[0]] = row[2]
    
        else: #Otherwise just grabs the code
            with arcpy.da.SearchCursor(inFC, [relPairO, namefield]) as cursor:
                for row in cursor:
                    names[row[0]] = row[1] #Every time you check this dictionary for the relation key, it will direct you to the right entry in the primary naming field.
    return names

 

 

View solution in original post

0 Kudos
4 Replies
by Anonymous User
Not applicable

Looks like you are creating the code:value dictionary in the first cursor, but since its scope is under the for loop, it is destroyed when the loop finishes.  Move the d = {} above the for loop so it persists and can be used in other parts of your code.

To get the code value, it would be a simple g.get('code (key) here', <default value here if you want it to return a value when the code is not in the keys>)

0 Kudos
by Anonymous User
Not applicable

For your second question, since the table is created in the 'memory' workspace, it is sent to the digital abyss when there is no more reference/ need for it and garbage collector does its thing.  Or when the script ends and python releases the memory.

AlfredBaldenweck
MVP Regular Contributor

Good to know, thanks!

0 Kudos
AlfredBaldenweck
MVP Regular Contributor

I ended up making a table from the domain, then joining to the original FC.

Below is my code sample, with the addition of lines #6-13, which validate that the domain is a Code Value Domain (checked in line #16).

This validation is necessary; if you use a Range domain with this workflow otherwise, it will return "Min Value", "Max Value", or nothing.

I have a little more stuff to do on this project, but the end is very near.

 

Thanks everyone!

def grabDomain (workspace, inFC, namefield, relPairO): 
    '''Grabs the Coded Value of a coded Value Domain'''
    ''' Otherwise just grabs the field's value'''

    names = dict()
    
    rawDomain = arcpy.da.ListDomains(workspace) #list of all domains in the GDB
    valDomain = [] #list of valid domains
    for dom in rawDomain:
        if dom.domainType != "Range": #add Coded Value Domains to the valid list
            valDomain.append(dom.name)
            
    listFlds = arcpy.ListFields(inFC, namefield)
    for field in listFlds:
        if (field.domain != "") and (field.domain in valDomain): #For retreiving Coded values
            #Create an in-memory table representing the domain.
            codeTable = arcpy.DomainToTable_management(workspace, field.domain, 'in_memory/codeTable', "codeField", "descriptionField")
            inFC2 = arcpy.management.AddJoin(inFC, namefield, codeTable, "codeField") # Join said table to your Feature Class.
            
            # Okay this next part is kinda tricky
            # perform your search cursor on the joined feature class, but use the ORIGINAL FC to find the field names.
            with arcpy.da.SearchCursor(inFC2, [f"{inFC}.{relPairO}", f"{inFC}.{namefield}", f"codeTable.descriptionField"]) as cursor:
                for row in cursor:
                    names[row[0]] = row[2]
    
        else: #Otherwise just grabs the code
            with arcpy.da.SearchCursor(inFC, [relPairO, namefield]) as cursor:
                for row in cursor:
                    names[row[0]] = row[1] #Every time you check this dictionary for the relation key, it will direct you to the right entry in the primary naming field.
    return names

 

 

0 Kudos