2

I have a Link and a Bookmark model like this:

class Link(models.Model):
    url = models.URLField(unique=True)        
    def __unicode__(self):
        return self.url

class Bookmark(models.Model):
    title=models.CharField(max_length=200)
    user=models.ForeignKey(User)
    link=models.ForeignKey(Link)        
    def __unicode__(self):
        return u'%s, %s' % (self.user.username, self.link.url)

Now within a view I see if a Link with a given url already exists. This object is then passed next with the username to Bookmarks collection to see if a bookmark already exists with this username and Link instance already exists.

def bookmark_save_page(request):
    if request.method == 'POST':
        form = BookmarkSaveForm(request.POST)
        if form.is_valid():
            # Create or get Link
            link, dummy = Link.objects.get_or_create(url=form.cleaned_data['url'])
            # Create or get bookmark
            bookmark, created = Bookmark.objects.get_or_create(user=request.user, link=link)

            # Save bookmark to database
            bookmark.save()
            return HttpResponseRedirect('/user/%s/' % request.user.username)

This is the bit I don't understand. How does it know how to take the url field inside Link model as a way of comparison? Is it because I had defined it in the Link model like this?

def __unicode__(self):
        return self.url

I am coming from .NET and there you have to define the GetHash() for the class as a way to specify how the instances should be compared against each other.

How does Python know this? Thanks

Alasdair
  • 298,606
  • 55
  • 578
  • 516
Houman
  • 64,245
  • 87
  • 278
  • 460
  • Where are you even making a comparison between objects? The only comparison operator you have is in `request.method == 'POST'`, which is comparing 2 strings. – Wooble May 22 '12 at 12:16
  • Which line is comparing objects? – bcoughlan May 22 '12 at 12:16
  • 3
    [`__cmp__()`](http://docs.python.org/reference/datamodel.html#object.__cmp__), [`__eq__()`](http://docs.python.org/reference/datamodel.html#object.__eq__), [`__gt__()`](http://docs.python.org/reference/datamodel.html#object.__gt__), [`__lt__()`](http://docs.python.org/reference/datamodel.html#object.__lt__), etc... – Mike Pennington May 22 '12 at 12:17
  • 1
    http://stackoverflow.com/questions/1227121/compare-object-instances-for-equality-by-their-attributes-in-python – bcoughlan May 22 '12 at 12:18
  • @MikePennington `__cmp__` hasn't been recommended for a long while (and no longer works if you happen to be using Py3) - it is better to implement the various rich comparison operators (`__eq__`, `__ne__`, `__gt__`, `__lt__`, `__ge__` and `__le__`), possibly with help from `functools.total_ordering`. – lvc May 22 '12 at 12:23

1 Answers1

5

I think you are asking "how does Django compare instances when filtering", rather than "how does python compare objects".

With the following line of code,

bookmark, created = Bookmark.objects.get_or_create(user=request.user, link=link)

Django is filtering on link object's primary key. The __unicode__ method does not matter.

See the Django docs for comparing objects and queries over related objects for more info.

Alasdair
  • 298,606
  • 55
  • 578
  • 516
  • That is it. Thank you. In Link class the url is the primary key because its unique correct? How about the bookmark class? title is not unique and the other two are foreign keys anyway. How does one know which field is the primary key? – Houman May 22 '12 at 12:32
  • 2
    Unless you manually specify the primary key, (which you haven't done here) Django generates one automatically. See the docs for [automatic primary key fields](https://docs.djangoproject.com/en/dev/topics/db/models/#automatic-primary-key-fields) for more info. – Alasdair May 22 '12 at 12:35
  • 1
    In other words, none of these fields are the primary key - the automatic `id` field is. – Daniel Roseman May 22 '12 at 12:46