Django: merging objects

django combine query sets different models
django union two querysets
django join multiple tables
django left join
inner join in django
django right join
django combining queries
cannot combine a unique query with a non-unique query.

I have such model:

class Place(models.Model):
    name = models.CharField(max_length=80, db_index=True)
    city = models.ForeignKey(City)
    address = models.CharField(max_length=255, db_index=True)
    # and so on

Since I'm importing them from many sources, and users of my website are able to add new Places, I need a way to merge them from an admin interface. Problem is, name is not very reliable since they can be spelled in many different ways, etc I'm used to use something like this:

class Place(models.Model):
    name = models.CharField(max_length=80, db_index=True) # canonical
    city = models.ForeignKey(City)
    address = models.CharField(max_length=255, db_index=True)
    # and so on

class PlaceName(models.Model):
    name = models.CharField(max_length=80, db_index=True)
    place = models.ForeignKey(Place)

query like this

Place.objects.get(placename__name='St Paul\'s Cathedral', city=london)

and merge like this

class PlaceAdmin(admin.ModelAdmin):
    actions = ('merge', )

    def merge(self, request, queryset):
        main = queryset[0]
        tail = queryset[1:]

        PlaceName.objects.filter(place__in=tail).update(place=main)
        SomeModel1.objects.filter(place__in=tail).update(place=main)
        SomeModel2.objects.filter(place__in=tail).update(place=main)
        # ... etc ...

        for t in tail:
            t.delete()

        self.message_user(request, "%s is merged with other places, now you can give it a canonical name." % main)
    merge.short_description = "Merge places"

as you can see, I have to update all other models with FK to Place with new values. But it's not very good solution since I have to add every new model to this list.

How do I "cascade update" all foreign keys to some objects prior to deleting them?

Or maybe there are other solutions to do/avoid merging


If anyone intersted, here is really generic code for this:

def merge(self, request, queryset):
    main = queryset[0]
    tail = queryset[1:]

    related = main._meta.get_all_related_objects()

    valnames = dict()
    for r in related:
        valnames.setdefault(r.model, []).append(r.field.name)

    for place in tail:
        for model, field_names in valnames.iteritems():
            for field_name in field_names:
                model.objects.filter(**{field_name: place}).update(**{field_name: main})

        place.delete()

    self.message_user(request, "%s is merged with other places, now you can give it a canonical name." % main)

Django Tips #5 How to Merge QuerySets, This tip is particularly useful when you want to merge two or more querysets into a medium = Medium.objects.get(name='Django Blog') user  medium = Medium. objects. get (name = 'Django Blog') user = User. objects. get (username = 'vitor') django_stories = medium. stories. all vitor_stories = user. stories. filter (category__name = 'django') At this point we have two different querysets, one containing all the stories from a medium and other containing all the stories from a user using the django category.


Based on the snippet provided in the comments in the accepted answer, I was able to develop the following. This code does not handle GenericForeignKeys. I don't ascribe to their use as I believe it indicates a problem with the model you are using.

I used list a lot of code to do this in this answer, but I have updated my code to use django-super-deduper mentioned here. At the time, django-super-deduper did not handle unmanaged models in a good way. I submitted an issue, and it looks like it will be corrected soon. I also use django-audit-log, and I don't want to merge those records. I kept the signature and the @transaction.atomic() decorator. This is helpful in the event of a problem.

from django.db import transaction
from django.db.models import Model, Field
from django_super_deduper.merge import MergedModelInstance


class MyMergedModelInstance(MergedModelInstance):
    """
        Custom way to handle Issue #11: Ignore models with managed = False
        Also, ignore auditlog models.
    """
    def _handle_o2m_related_field(self, related_field: Field, alias_object: Model):
        if not alias_object._meta.managed and "auditlog" not in alias_object._meta.model_name:
            return super()._handle_o2m_related_field(related_field, alias_object)

    def _handle_m2m_related_field(self, related_field: Field, alias_object: Model):
        if not alias_object._meta.managed and "auditlog" not in alias_object._meta.model_name:
            return super()._handle_m2m_related_field(related_field, alias_object)

    def _handle_o2o_related_field(self, related_field: Field, alias_object: Model):
        if not alias_object._meta.managed and "auditlog" not in alias_object._meta.model_name:
            return super()._handle_o2o_related_field(related_field, alias_object)


@transaction.atomic()
def merge(primary_object, alias_objects):
    if not isinstance(alias_objects, list):
        alias_objects = [alias_objects]
    MyMergedModelInstance.create(primary_object, alias_objects)
    return primary_object

Merging model instances in Django 1.9 · GitHub, Use this function to merge model objects and migrate all of the related. fields from the alias objects the primary object. Usage: from django.contrib.auth.models  Merging 3 or more media objects can throw unnecessary MediaOrderConflictWarnings Django should be able to resolve the JS files for the final form into the order


Two libraries now exist with up-to-date model merging functions that incorporate related models:

Django Extensions' merge_model_instances management command.

Django Super Deduper

5. How to do union of two querysets from same or different models , The UNION operator is used to combine the result-set of two or more querysets. q1 = User.objects.filter(id__gte=5) >>> q1 <QuerySet [<User: Ritesh>, <User:  >>> q3 = EventVillain. objects. all >>> q3 <QuerySet [<EventVillain: EventVillain object (1)>]> >>> q1. union (q3) django.db.utils.OperationalError: SELECTs to the left and right of UNION do not have the same number of result columns


Tested on Django 1.10. Hope it can serve.

def merge(primary_object, alias_objects, model):
"""Merge 2 or more objects from the same django model
The alias objects will be deleted and all the references 
towards them will be replaced by references toward the 
primary object
"""
if not isinstance(alias_objects, list):
    alias_objects = [alias_objects]

if not isinstance(primary_object, model):
    raise TypeError('Only %s instances can be merged' % model)

for alias_object in alias_objects:
    if not isinstance(alias_object, model):
        raise TypeError('Only %s instances can be merged' % model)

for alias_object in alias_objects:
    # Get all the related Models and the corresponding field_name
    related_models = [(o.related_model, o.field.name) for o in alias_object._meta.related_objects]
    for (related_model, field_name) in related_models:
        relType = related_model._meta.get_field(field_name).get_internal_type()
        if relType == "ForeignKey":
            qs = related_model.objects.filter(**{ field_name: alias_object })
            for obj in qs:
                setattr(obj, field_name, primary_object)
                obj.save()
        elif relType == "ManyToManyField":
            qs = related_model.objects.filter(**{ field_name: alias_object })
            for obj in qs:
                mtmRel = getattr(obj, field_name)
                mtmRel.remove(alias_object)
                mtmRel.add(primary_object)
    alias_object.delete()
return True

Model merging function, Based on http://djangosnippets.org/snippets/382/, with several Use this function to merge model objects (i.e. Users, Organizations, Polls, etc.)  What Django looks for when it loads a migration file (as a Python module) is a subclass of django.db.migrations.Migration called Migration. It then inspects this object for four attributes, only two of which are used most of the time: dependencies, a list of migrations this one depends on.


I was looking for a solution to merge records in Django Admin, and found a package that is doing it (https://github.com/saxix/django-adminactions).

How to use:

Install package: pip install django-adminactions

Add adminactions to your INSTALLED_APPS:

INSTALLED_APPS = (
    'adminactions',
    'django.contrib.admin',
    'django.contrib.messages',
)

Add actions to admin.py:

from django.contrib.admin import site
import adminactions.actions as actions

actions.add_to_site(site)

Add service url to your urls.py: url(r'^adminactions/', include('adminactions.urls')),

Tried it just now, it works for me.

Combine Two Querysets in Django (with different models), Today, I stumbled upon a use case where I needed to have a querysets that had objects from different models. Django has a neat "contenttypes  from django.db import transaction from django.db.models import Model, Field from django_super_deduper.merge import MergedModelInstance class MyMergedModelInstance(MergedModelInstance): """ Custom way to handle Issue #11: Ignore models with managed = False Also, ignore auditlog models.


Making queries | Django documentation, You can compose statements of arbitrary complexity by combining Q objects with the & and | operators and use  To save you time, Django automatically derives the name of the database table from the name of your model class and the app that contains it. A model’s database table name is constructed by joining the model’s “app label” – the name you used in manage.py startapp – to the model’s class name, with an underscore between them.


Related objects reference | Django documentation, Related objects reference¶. class RelatedManager ¶. A “related manager” is a manager used in a one-to-many or many-to-many related context. This happens​  1. How to create multiple objects in one shot? 2. How to copy or clone an existing model object? 3. How to ensure that only one object can be created? 4. How to update denormalized fields in other models on save? 5. How to perform truncate like operation using Django ORM? 6. What signals are raised by Django during object creation or update? 7.


Multiple databases | Django documentation, The default routing scheme ensures that objects remain 'sticky' to their original database (i.e., an object retrieved from the foo database will be saved on the  ¶. In previous chapters we used Q objects for OR and AND and NOT operations. Q objects provides you complete control over the where clause of the query. If you want to OR your conditions. >>> from django.db.models import Q >>> queryset = User.objects.filter( Q(first_name__startswith='R')