Opened 8 years ago

Closed 7 years ago

#4157 closed (wontfix)

Add is_equal method to models for other kinds of equality checking.

Reported by: Michael Axiak <axiak@…> Owned by: nobody
Component: Database layer (models, ORM) Version: master
Severity: Keywords: equality, models
Cc: Michael, Axiak, <axiak@…>, ferringb@… Triage Stage: Design decision needed
Has patch: yes Needs documentation: yes
Needs tests: yes Patch needs improvement: no
Easy pickings: UI/UX:

Description

There are many cases where one might want to check to see if two models are equal (and not just the same database row). If you take the OO analogy, you might want to see if two Articles are equivalent articles even if they are not the 'same' object.
This patch will allow one to do that. You can specify which fields you want to exclude by specifying attnames in the exclude parameter. If it's left unspecified, it will automatically exclude the primary key field(s). To disable excluding the primary key, just set excludes to [].
Examples:

class Article(models.Model):
    subject = models.CharField(maxlength=512)
    submitted = models.DateTimeField()
    author  = models.ForeignKey(User)

# suppose a and b only differ on when they were submitted

a = Article.objects.get(id = 5)
b = Article.objects.get(id = 6)

a.is_equal(b)
False

a.is_equal(a)
True

a.is_equal(b, ['id','submitted'])
True

a.is_equal(b, [])
False

a.is_equal(a, [])
True

Attachments (3)

5079-add_is_equal_to_model.diff (2.0 KB) - added by Michael Axiak <axiak@…> 8 years ago.
The code to make it work.
5079-better_patch_for_is_equal_check.diff (2.0 KB) - added by Michael Axiak <axiak@…> 8 years ago.
Cleaner Patch, now uses new Meta equality_exclude parameter
5079-better_patch_for_is_equal_check_2.diff (1.9 KB) - added by Michael Axiak <axiak@…> 8 years ago.
This works a little better.

Download all attachments as: .zip

Change History (8)

Changed 8 years ago by Michael Axiak <axiak@…>

The code to make it work.

comment:1 Changed 8 years ago by Michael Axiak <axiak@…>

  • Needs documentation set
  • Needs tests set
  • Patch needs improvement unset
  • Triage Stage changed from Unreviewed to Design decision needed

Patch might need improvement, depends on what people think.

comment:2 Changed 8 years ago by ubernostrum

Any chance of implementing this as the more Pythonic __eq__ or __cmp__?

Changed 8 years ago by Michael Axiak <axiak@…>

Cleaner Patch, now uses new Meta equality_exclude parameter

comment:3 follow-up: Changed 8 years ago by Michael Axiak <axiak@…>

I submitted a new patch...no docs or tests yet (waiting on thumbs up from developers actually).
This new patch will allow one to specify the excluded fields in Meta, like so:

class Article(models.Model):
    subject = models.CharField(maxlength=512)
    submitted = models.DateTimeField()
    author  = models.ForeignKey(User)

    class Meta:
        equality_exclude = ('submitted','id')

# suppose a and b only differ on when they were submitted

a = Article.objects.get(id = 5)
b = Article.objects.get(id = 6)

a.is_equal(b)
True

a.is_equal(b, [])
False

a.is_equal(b, ['submitted'])
False # ids differ

As a response to ubernostrum, eq currently uses the pk field to determine which if they are equal. Now that it uses a Meta field, we could have it override eq and have the default Meta make it just compare pk.

I'm not sure either way, and there seemed to be strong opinions in either direction. What's *YOUR* take?

Changed 8 years ago by Michael Axiak <axiak@…>

This works a little better.

comment:4 in reply to: ↑ 3 Changed 8 years ago by (removed)

  • Cc Michael Axiak <axiak@…> ferringb@… added; Michael Axiak <axiak@…> removed

comment:5 Changed 7 years ago by lukeplant

  • Resolution set to wontfix
  • Status changed from new to closed

Some points:

  • The current implementation of is_equal() is not very flexible -- for instance, a 'fuzzy' match on certain attributes (e.g. case insensitive equality) might be useful.
  • Why not just override __eq__ ?


  • With ether is_equal or __eq__, this could be easily implemented as a mixin:
class IsEqualMixin(object):
    def is_equal(self, other):
        # whatever you want here

    def __eq__(self, other):
        # whatever

class YourModel(IsEqualMixin, models.Model):
    # whatever

For these reasons, closing as WONTFIX.

Note: See TracTickets for help on using tickets.
Back to Top