2

I looked at similar question on SO but none of them answer my problem. For Ex. How do you cast an instance to a derived class? . But the answer doesn't seem to be what I want.

Here is my situation. I have a class structure like in Django

class Base:
     ...some stuff...

class Derived(Base):
     ...some more stuff...

Now when I make some queries in Django, I always get objects of Base class.

 baseobj = get_object_or_404(Base, id = sid)

At runtime I can also encounter "Derived" objects which have some extra properties. I'm able to figure out if an object is Base or derived(there is sufficient info in Base class object). But how should I access those extra fields which are present only in Derived class. I'm not able to downcast "Base" -> "Derived". How should I handle it?

EDIT:

I figured out the problem. Django stores "additional properties" of Derived class in a separate table. Hence problem arose due to this line of code.

baseobj = get_object_or_404(Base, id = sid)

baseobj will always be of Base class and will not have any properties of Derived class. I have to make an additional query to get the Derived class object.

baseobj = get_object_or_404(Base, id = sid)
if baseobj.isDerivedType:
      derivedobj = get_object_or_404(Derived, id = sid)
7
  • 1
    Is there a reason you can't just get_object_or_404(Derived, id = sid)? Commented Feb 5, 2011 at 2:38
  • 3
    There is no need to "cast" in Python. Objects in Python are duck typed. Commented Feb 5, 2011 at 2:42
  • No I can't. I cannot know which 'sid' belongs to either Base or Derived. Commented Feb 5, 2011 at 2:43
  • @santa - I get an error if I try to access some derived properties. "'Base' object has no attribute 'DerivedProperty' Commented Feb 5, 2011 at 2:45
  • 2
    @Neo: I get the feeling that you are trying to implement a multi-table inheritance in Django's ORM, correct? Have you read the documentation on it? Commented Feb 5, 2011 at 2:52

4 Answers 4

9

This sort of inheritance in Django-land smells like multi-table inheritance to me. According to the doc, assuming everything is wired properly, you should be able to do:

baseobj.derived    # note: small 'd'
Sign up to request clarification or add additional context in comments.

2 Comments

Your welcome. That will do the trick, but be aware that your solution will also incur an additional database access cost that might not be necessary.
This solution don't hit the database?
2

Normally, I would say that it's typical to use a try-except clause in a situation like this.

class thing1(object):
    def __init__(self):
        self.a = 5

class thing2(thing1):
    def __init__(self):
        super(thing2, self).__init__()
        self.b = 6

t = thing1()
try: 
    print(t.b)
except AttributeError: 
    print("handling the exception")

EDIT: But am I understanding your question correctly? Answer: No. Oops!

EDIT2: Nonetheless, it seems that some variation on the above try-except block would be better than accessing the database twice, as your edited question suggests.

10 Comments

Shouldn't that be try: t.b = 6? As written, the exception doesn't occur. Your code would be a little easier to read if try/except were each on their own line, as well.
@Velociraptors, yes I realized that and fixed it but I guess not before you did! Also, put try/except blocks on their own lines. Thanks!
I would try a similar approach of wrapping get_object_or_404(Derived, id = sid) within try-catch. First try to retrieve it as a Derived and if that fails then load it as a Base. Although, it's probably better to design your application so objects of different types use separate primary key spaces.
@senderle - Distinguishing between 'thing1' and 'thing2' is not the problem. I can determine which object is which class, there is enough information in 'thing1' object itself. But how do I access the properties of 'thing2', once I'm sure that t is thing2 type.
If you know t is thing2, why can't you just access them? Also, the point of the above code is that you don't have to know whether you're dealing with thing1 or thing2 in advance.
|
1

I have never had to do this in python. It seems like a code smell that you have an instance of a type, and need to know the most derived type of the object. You should already know what the type is based on the function that you're using. Perhaps if you showed us the actual code that you are using, we'd be able to help you with a better solution.

The problem with checking if your object isDerivedType is that when you add another derived class, you will have to modify your base to do checks for the new derived type. This breaks the model of object oriented programming. If someone else is using your code and they decide to derive from your class, they can't effectively do it.

Try to work with the derived types as much as possible. The point of inheritance in Django is to allow code re-use and the sharing of data between classes - not information hiding.

Comments

0

Use the "lowercase" version of Derived class:

class Base:
     base_attribute

class Derived(Base):
     derived_attribute

baseobj = get_object_or_404(Base, id = sid)
if baseobj.isDerivedType:
     print baseobj.derived.derived_attribute

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.