[ckan-dev] Repeatable metadata elements

Pabitra Dash pkdash_reena at hotmail.com
Wed Apr 2 21:19:09 UTC 2014


Thanks Khalegh. I will give that a try. It seems it should work for my case too.
 
Pabitra

 
From: khalegh at highwaythreesolutions.com
Date: Wed, 2 Apr 2014 11:38:24 -0700
To: ckan-dev at lists.okfn.org
Subject: Re: [ckan-dev] Repeatable metadata elements

Hello Pabitra,
I asked the same question a while ago but I didn’t get any answers. I had to add multiple values for a group of fields like contact name, contact email, etc. I checked ckan src for schema definition and came up with the following solution which I am not sure if it is the best way of doing it.
In my dataset form class I am overriding create_package_schema, update_package_schema, show_package_schema. Both  create_package_schema and update_package_schema use the same schema definition. Here is part of the schema containing the multi value fields :
       schema.update({			... ,                        'contacts' : contacts_db_schema(),                        'dates' : dates_to_db_schema(),			... ,                      })
def contacts_db_schema():    schema = {              'name' : [check_empty, convert_to_extras],              'organization' : [check_empty, convert_to_extras],              'email' : [check_empty, valid_email, convert_to_extras],              'role' : [check_empty, convert_to_extras],              'private' : [ignore_missing, convert_to_extras],              'delete' :[ignore_missing, convert_to_extras]              }    return schema
Ckan uses this schema when creating or updating  a dataset. It generates keys like  (contacts, 0, name) or (contacts, 0, email) which are used by convert_to_extras convertor function.
I tried to do the same for show_package_schema, but ckan doesn’t give me the same key for fields so that I can use them to get the corresponding values from extras. The other problem is that ckan’s default convert_to_extras function takes the last part of the key when storing the data in extras which obviously doesn’t work when having multiple values.
For show_package_schema I am simply updating the schema as follow :    def show_package_schema(self):        schema = super(DatasetFormClass, self).show_package_schema()                schema['tags']['__extras'].append(toolkit.get_converter('free_tags_only'))        schema.update({                        'contacts' : [convert_from_extras, ignore_missing],                        'dates' : [convert_from_extras, ignore_missing],                       })
Then I had to override both convert_to_extras and convert_from_extras. Be careful you cannot use the same converters for resources, you need to use ckan’s default if you have extra fields for resources.def convert_to_extras(key, data, errors, context):#    print "key :====> ", key, "data : ====>", data[key]     extras = data.get(('extras',), [])    if not extras:        data[('extras',)] = extras        keyStr = ':'.join([str(x) for x in key])    extras.append({'key': keyStr, 'value': data[key]})

def convert_from_extras(key, data, errors, context):
    print "key : <====", key, "\n"    def remove_from_extras(data, keyList):        to_remove = []        for data_key, data_value in data.iteritems():            if (data_key[0] == 'extras' and data_key[1] in keyList) :                to_remove.append(data_key)        for item in to_remove:            del data[item]                indexList = [] # A list containing the index of items in extras to be removed.    new_data = {}  #A new dictionary for data stored in extras with the given key    for data_key, data_value in data.iteritems():        if (data_key[0] == 'extras'            and data_key[-1] == 'key'):            #Extract the key components eparated by ':'            keyList = data_value.split(':')            #Check for multiple value inputs and convert the list item index to integer            if (len(keyList) > 1):                keyList[1] = int(keyList[1])            #Construct the key for the stored value(s)            newKey = tuple(keyList)            if (key[-1] == newKey[0]):                #Retrieve data from extras and add it to new_data so it can be added to the data dictionary.                 new_data[newKey] = data[('extras', data_key[1], 'value')]                #Add the data index in extras to the list of items to be removed.                 indexList.append(data_key[1])        #print new_data    #Remove all data from extras with the given index    remove_from_extras(data, indexList)
    #Remove previous data stored under the given key    del data[key]        deleteIndex = []    for data_key, data_value in new_data.iteritems():        #If this is a deleted record then add it to the deleted list to be removed from data later.          if ('delete' in data_key            and data_value == '1'):            deleteIndex.append(data_key[1])    deleted = []            for data_key, data_value in new_data.iteritems():            if (len(data_key) > 1                 and data_key[1] in deleteIndex):                deleted.append(data_key)    for item in deleted :        del new_data[item]
    #Add data extracted from extras to the data dictionary    for data_key, data_value in new_data.iteritems():        data[data_key] = data_value        I am attaching my template and javascript for contacts here as well. I hope this helps. Please let me know if you have any problem with the code.
Best,Khalegh

--Forwarded Message Attachment--

{#
  adds input fields of contact information.
  
  contacts - The contact fields to add (list of contacts).
  errors   - A dict of errors for the fields.
  
  Example:
  	{snippet 'snippets/contact_fields.html', contacts=data.contacts, errors=errors %}
  	
#}

{% import "macros/form.html" as form %}
{% set contacts = contacts or [] %}
{% set organizations_available = h.edc_orgs() %}


	
	{% for contact in contacts %}
		{% if errors.contacts %}
			{% set email_error = errors.contacts[loop.index0].email %}
			{% set name_error = errors.contacts[loop.index0].name %}
			{% set org_error = errors.contacts[loop.index0].organization %}
			{% set role_error = errors.contacts[loop.index0].role %}
			{% set contact_error = email_error or name_error or org_error or rol_error %}
		{% endif %}
		
		
			
				
					Name
					
				 	Organization
				 	
				 	Select an organization
				 	{% for organization in organizations_available %}
				 		{% set selected_org = contact.organization and organization.id == contact.organization %}
						 {{ organization.title }}		 		
				 	{% endfor %} 
				 	
				 
				 
					Email
					
				   	Role
				   	
				   	
				   	Select a contact role
				   	{% for role in h.edc_tags(_("contact_roles")) %}
				   		{% set selected_role = contact.role and contact.role == role.id %}
				   		{{ role.name }}
				   	{% endfor %}
				   	
				
 				
				
					{% set is_private = (contact.private and contact.private == _('Private')) %} 
					
					Private Contact
				 				
				 Delete  				   	
				

			
				{% if name_error and name_error is iterable %}
				   	 Name: {{ name_error|join(', ') }}
				{% endif %}				   	   		
				{% if email_error and email_error is iterable %}
				   	 Email: {{ email_error|join(', ') }}
				{% endif %}				   	   		
				{% if org_error and org_error is iterable %}
				   	 Organization: {{ org_error|join(', ') }}
				{% endif %}				   	   		
				{% if role_error and role_error is iterable %}
				   	 Role: {{ role_error|join(', ') }}
				{% endif %}				   	   		
		
	{% endfor %}
	
	{% set len = contacts|count %}
	{% if len == 0 %}
		
			
				
					Name
					
				 	Organization
				 	
				 	
				 		Select an organization 
				 		{% for organization in organizations_available %}
							 {{ organization.name }}		 		
				 		{% endfor %}
				 	
				 
				 
					Email
					
				   	Role
				   	
				   	Select a contact role
				   	{% for role in h.edc_tags(_("contact_roles")) %}
				   		{{ role.name }}
				   	{% endfor %}
				   	
				

				
					
					Private Contact
				 				
			Delete 
			
			
		 
	{% endif %}
	
	
	
	
	
		
			
			Add another contact
		
	

 
On Apr 2, 2014, at 10:47 AM, Pabitra Dash <pkdash_reena at hotmail.com> wrote:Hi All,
 
I have implemented a custom metadata schema for dataset. We have another requirement to make some of the metadata elements repeatable. For example, I have creator element and creator_email element which I want to make repeatable. So in the UI when the user selects add a creator, I should be able to store name and email for another creator. Not sure how I define a schema for these kind of repeatable elements. 
 
Would appreciate any help on this.
 
Pabitra



_______________________________________________
ckan-dev mailing list
ckan-dev at lists.okfn.org
https://lists.okfn.org/mailman/listinfo/ckan-dev
Unsubscribe: https://lists.okfn.org/mailman/options/ckan-dev

_______________________________________________
ckan-dev mailing list
ckan-dev at lists.okfn.org
https://lists.okfn.org/mailman/listinfo/ckan-dev
Unsubscribe: https://lists.okfn.org/mailman/options/ckan-dev 		 	   		  
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.okfn.org/pipermail/ckan-dev/attachments/20140402/97c894e5/attachment-0003.html>


More information about the ckan-dev mailing list