views:

56

answers:

4

Hi folks,

I'm finding this a bit tricky! Maybe someone can help me on this one

I have the following model:

class Unicorn(models.Model):

  horn_length = models.IntegerField()
  skin_color = models.CharField()
  average_speed = models.IntegerField()
  magical = models.BooleanField()
  affinity = models.CharField()

I would like to search for all similar unicorns having at least 3 fields in common.


Is it too tricky? Or is it doable?

+2  A: 

It has to be done in the HAVING clause:

SELECT ... HAVING (IF(a.horn_length=b.horn_length, 1, 0) + ...) >= 3

There's no way to express HAVING in the Django ORM so you'll need to drop to raw SQL in order to perform it.

Ignacio Vazquez-Abrams
Thanks for that! I'm having a small problem though, because I'm being asked to use a database software quite often. I'm trying to find a way to abstract it using Django's ORM. Great reply though thanks!
RadiantHex
`HAVING` is portable between databases. It is Django's ORM that doesn't support it.
Ignacio Vazquez-Abrams
+1  A: 

This should cover your question, if I understood it right:

from django.db import models

Unicorn.objects.filter(models.Q(skin_color = 'white') | models.Q(magical = True))

This would filter all unicorns that have skin color white or have some magical stuff in common. More about the Q objects here http://docs.djangoproject.com/en/dev/topics/db/queries/#complex-lookups-with-q-objects

realshadow
This is answered two questions in one! Thanks! =D
RadiantHex
+1  A: 

You should use Q objects. The rough example is:

from django.db.models import Q
from itertools import combinations
# this -- the unicorn to be matched with
attr = ['horn_length', 'skin_color', 'average_speed', 'magical', 'affinity']
q = None
for c in combinations(attrs, 3):
    q_ = Q(**{c[0]: getattr(this, c[0])}) & Q(**{c[1]: getattr(this, c[1])}) & Q(**{c[2]: getattr(this, c[2])})
    if q is None:
        q = q_
    else:
        q = q | q_
Unicorn.objects.get(q)           

not tested, though

Guard
`itertools.combinations()`
Ignacio Vazquez-Abrams
My database just got erased! Joking, tested it! Works great thanks for that!
RadiantHex
thanks. was lazy to look for it :)
Guard
Great to hear it
Guard
@Ignacio could you show an example using itertools? :)
RadiantHex
@Ignacio ok I think I understand how to do it! Thanks!
RadiantHex
I updated my example
Guard
@RadiantHex if this answer is OK for you, please choose it
Guard
+1  A: 

I have never used Django and i'm rather novice in Python but perhaps you can do something like this:

make a method that compares two instances of the class Unicorn.

def similarity(self, another)
    sim = 0
    if (self.horn_length==another.horn_length):
        sim+=1
    if (self.skin_color==another.skin_color):
        sim+=1
    if (self.average_speed==another.average_speed):
        sim+=1
    if (self.magical==another.magical):
        sim+=1
    if (self.affinity==another.affinity):
        sim+=1
    return sim

Then you can test with something like:

myUnicorn
for x in unicornsList:
    if myUnicorn.similarity(x) >=3:
        ...
ypercube