Replacing a model instance's __dict__

170 views
Skip to first unread message

Tom Evans

unread,
Feb 8, 2013, 12:50:22 PM2/8/13
to django...@googlegroups.com
Hi all

I have a curious problem with a complex data replication issue.

Basically, we use SalesForce as a CRM system. We also have a bunch of
users who aren't allowed a SF license due to cost reasons, and they
interact with SF via our own Django website that communicates to SF
via an API.

With this API, we can CRUD all salesforce objects. We can also fetch
all changes since (specific time), so we maintain a local copy of all
our SF data in django models, synchronizing changes every 10 minutes
throughout the day. This actually works quite well!

The problem comes with using django idioms like get_or_create(), when
an object is created directly on SF in the period since the last
synchronization. In this example, we want to get_or_create a Contact
with a specific email address. There is no Contact locally with the
specified email address, so get_or_create tries to create a new one.

Using the API, this issues the appropriate query to SF, but since the
Contact already exists on SF, an exception is raised.

get_or_create(), create() all work via save(), so my idea is to catch
this specific error in save, re-synchronise the database against the
remote end, pull the freshly synced record out of the database, and
replace self.__dict__ with new_item.__dict__, looking something like
this:

def save(self, *args, **kwargs):
try:
super(Contact, self).save(*args, **kwargs)
except ValueError, e:
if 'Contact already exists' in unicode(e):
# Synchronize Contact objects with SF
run_log = SyncRunLog(start_time=datetime.now())
run_log.save()
Contact.update(run_log)
# The contact should now be available locally
try:
synched_contact = Contact.objects.get(email=self.email)
self.__dict__ = synched_contact.__dict__
except Contact.DoesNotExist:
# Still not there, raise a new ValueError
raise ValueError(
'Failed to find contact %s after resyncing '
'Contact following this error: %s'
% (self.email, unicode(e)))
else:
raise e

Is there an obvious issue with doing this? Can I simply replace
self.__dict__ like that without bad consequences?

Cheers

Tom

Daniel Roseman

unread,
Feb 8, 2013, 1:31:39 PM2/8/13
to django...@googlegroups.com, teva...@googlemail.com
The only thing I can think of is that by using simple assignment you're creating a linkage between the two entities' dicts, which might cause problems down the line. Rather than doing that, I would probably do:

    self.__dict__.clear()
    self.__dict__.update(synched_contact.__dict__)

or maybe even

    self.__dict__ = copy.deepcopy(synched_contact.__dict__)

---
DR.

Bill Freeman

unread,
Feb 9, 2013, 6:22:40 AM2/9/13
to django...@googlegroups.com
Tom,

I suspect that there man be problematic, perhaps dependent on python version, because the __dict__ attribute itself is a slot (it couldn't, for example, be in the __dict__).  Some slots may not accept assignment after creation, and the __dict__ object may not be an ordinary dict().

Separately, if I'm understanding correctly, there is a local database with a copy of the information.  Unless you've done something special with the local model definitions, the id field will be problematic.

I think that you're stuck with  a for loop over synched_contact.items(), where you can filter keys that shouldn't be saved.  You can also then uses setattr(self, key, value) instead of accessing self.__dict__, leaving you the flexibility for some of these attributes to be properties, if that turns out to be useful.

Bill


Tom

--
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users...@googlegroups.com.
To post to this group, send email to django...@googlegroups.com.
Visit this group at http://groups.google.com/group/django-users?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.



Tom Evans

unread,
Feb 11, 2013, 4:58:57 AM2/11/13
to django...@googlegroups.com
Thanks for the advice guys, I didn't like it much either - a Friday
afternoon solution. I'll do something a little less brute force ;)

Cheers

Tom
Reply all
Reply to author
Forward
0 new messages