Login

Save a model using an arbitrary db connection

Author:
weswinham
Posted:
August 31, 2009
Language:
Python
Version:
1.1
Score:
2 (after 2 ratings)

This function lets you save an instance of a model to another database based on a connection argument. Useful when doing data migrations across databases. Connection is anything that would work as a django.db.connection

I'm not sure if this handles proxy models or model inheritance properly, though.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
def save_using_connection(instance, connection, force_insert=False, force_update=False, raw=False):
    model = instance.__class__

    cls = instance.__class__
    meta = cls._meta
    origin = cls

    if not meta.proxy:
        non_pks = [f for f in meta.local_fields if not f.primary_key]

        # First, try an UPDATE. If that doesn't update anything, do an INSERT.
        pk_val = instance._get_pk_val(meta)
        pk_set = pk_val is not None
        record_exists = True
        manager = cls._base_manager
        if pk_set:
            # Determine whether a record with the primary key already exists.
            if (force_update or (not force_insert and
                    manager.filter(pk=pk_val).extra(select={'a': 1}).values('a').order_by())):
                # It does already exist, so do an UPDATE.
                if force_update or non_pks:
                    values = [(f, None, (raw and getattr(instance, f.attname) or f.pre_save(instance, False))) for f in non_pks]
                    q = manager.filter(pk=pk_val)
                    q.query.connection = connection
                    rows = q._update(values)
                    if force_update and not rows:
                        raise DatabaseError("Forced update did not affect any rows.")
            else:
                record_exists = False
        if not pk_set or not record_exists:
            if not pk_set:
                if force_update:
                    raise ValueError("Cannot force an update in save() with no primary key.")
                values = [(f, f.get_db_prep_save(raw and getattr(instance, f.attname) or f.pre_save(instance, True))) for f in meta.local_fields if not isinstance(f, AutoField)]
            else:
                values = [(f, f.get_db_prep_save(raw and getattr(instance, f.attname) or f.pre_save(instance, True))) for f in meta.local_fields]

            if meta.order_with_respect_to:
                field = meta.order_with_respect_to
                values.append((meta.get_field_by_name('_order')[0], manager.filter(**{field.name: getattr(instance, field.attname)}).count()))
            record_exists = False

            update_pk = bool(meta.has_auto_field and not pk_set)
            if values:
                # Create a new record.
                result = _insert(model, connection, values, return_id=update_pk)
            else:
                # Create a new record with defaults for everything.
                result = _insert(model, connection, [(meta.pk, connection.ops.pk_default_value())], return_id=update_pk, raw_values=True)

            if update_pk:
                setattr(instance, meta.pk.attname, result)

More like this

  1. Template tag - list punctuation for a list of items by shapiromatron 10 months, 2 weeks ago
  2. JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 10 months, 3 weeks ago
  3. Serializer factory with Django Rest Framework by julio 1 year, 5 months ago
  4. Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 6 months ago
  5. Help text hyperlinks by sa2812 1 year, 7 months ago

Comments

Please login first before commenting.