def update(self, instance, validated_data): """ Update the profile, including nested fields. Raises: errors.AccountValidationError: the update was not attempted because validation errors were found with the supplied update """ language_proficiencies = validated_data.pop("language_proficiencies", None) # Update all fields on the user profile that are writeable, # except for "language_proficiencies" and "social_links", which we'll update separately update_fields = set(self.get_writeable_fields()) - set(["language_proficiencies"]) - set(["social_links"]) for field_name in update_fields: default = getattr(instance, field_name) field_value = validated_data.get(field_name, default) setattr(instance, field_name, field_value) # Update the related language proficiency if language_proficiencies is not None: instance.language_proficiencies.all().delete() instance.language_proficiencies.bulk_create([ LanguageProficiency(user_profile=instance, code=language["code"]) for language in language_proficiencies ]) # Update the user's social links social_link_data = self._kwargs['data']['social_links'] if 'social_links' in self._kwargs['data'] else None if social_link_data and len(social_link_data) > 0: new_social_link = social_link_data[0] current_social_links = list(instance.social_links.all()) instance.social_links.all().delete() try: # Add the new social link with correct formatting validate_social_link(new_social_link['platform'], new_social_link['social_link']) formatted_link = format_social_link(new_social_link['platform'], new_social_link['social_link']) instance.social_links.bulk_create([ SocialLink(user_profile=instance, platform=new_social_link['platform'], social_link=formatted_link) ]) except ValueError as err: # If we have encountered any validation errors, return them to the user. raise errors.AccountValidationError({ 'social_links': { "developer_message": u"Error thrown from adding new social link: '{}'".format(text_type(err)), "user_message": text_type(err) } }) # Add back old links unless overridden by new link for current_social_link in current_social_links: if current_social_link.platform != new_social_link['platform']: instance.social_links.bulk_create([ SocialLink(user_profile=instance, platform=current_social_link.platform, social_link=current_social_link.social_link) ]) instance.save() return instance
def _update_social_links(self, instance, requested_social_links): """ Update the given profile instance's social links as requested. """ try: new_social_links = [] deleted_social_platforms = [] for requested_link_data in requested_social_links: requested_platform = requested_link_data['platform'] requested_link_url = requested_link_data['social_link'] validate_social_link(requested_platform, requested_link_url) formatted_link = format_social_link(requested_platform, requested_link_url) if not formatted_link: deleted_social_platforms.append(requested_platform) else: new_social_links.append( SocialLink(user_profile=instance, platform=requested_platform, social_link=formatted_link)) platforms_of_new_social_links = [ s.platform for s in new_social_links ] current_social_links = list(instance.social_links.all()) unreplaced_social_links = [ social_link for social_link in current_social_links if social_link.platform not in platforms_of_new_social_links ] pruned_unreplaced_social_links = [ social_link for social_link in unreplaced_social_links if social_link.platform not in deleted_social_platforms ] merged_social_links = new_social_links + pruned_unreplaced_social_links instance.social_links.all().delete() instance.social_links.bulk_create(merged_social_links) except ValueError as err: # If we have encountered any validation errors, return them to the user. raise errors.AccountValidationError({ 'social_links': { "developer_message": u"Error when adding new social link: '{}'".format( text_type(err)), "user_message": text_type(err) } })