1

I am just learning Python and Django and trying to understand how objects are initialized. Suppose I have a Django model called Alpha, with three attributes: x, y and z. x and y are integers, and z is a boolean. When I create an Alpha object, I want to initialize x and y (similar to a constructor in C++). Then, I want to automatically set z to True if x is equal to y, and False otherwise. I have been recommended to edit the __init__ function, and I have tried the following:

from django.db import models

class Alpha:
    x = models.IntegerField(default = 0)
    y = models.IntegerField(default = 0)
    z = models.BooleanField(default = 'false')

However, this does not work as I would expect. In the Django shell, I have the following:

>>> from test.models import Alpha
>>> a = Alpha(3, 3)
>>> a.x
3
>>> a.y
0
>>> a.z
u'false'

I am trying to set x=3 and y=3, therefore z='True', but this is obviously not what is happening. y is not set to anything, and I suspect this is because the first argument is actually set to self, rather than x. I don't think I quite understand the role of the self argument, which may be the problem...

Any advice on how I should be doing this properly?

2
  • 2
    You've been told correctly: where's your __init__ code? Btw: it should be False (a boolean) not 'false' (a string). Commented Feb 12, 2014 at 20:49
  • You also might want to make Alpha inherit from models. You can do that by having the class signature be Alpha(models). Commented Feb 12, 2014 at 20:52

3 Answers 3

2

You've been told correctly: overriding __init__ is one possibility:

from django.db import models

class Alpha(models.Model):  # <-- missing inheritance?
    x = models.IntegerField(default = 0)
    y = models.IntegerField(default = 0)
    z = models.BooleanField(default = False)  # <-- False, not 'false'

    def __init__(self, *args, **kwargs):
        super(Alpha, self).__init__(*args, **kwargs)
        self.z = (self.x == self.y)
Sign up to request clarification or add additional context in comments.

Comments

1

I prefer to use signals rather than overriding the native methods. Try using post_init or pre_save signals to set the value for you. The post_init will only execute when initializing the object and will not execute on subsequent model edits. The pre_save will execute when the object is saved.

https://docs.djangoproject.com/en/dev/ref/signals/#post-init

from django.db.models.signals import post_init
from django.dispatch import receiver
from myapp.models import Alpha

@receiver(post_init, sender=Alpha)
def my_handler(sender, instance):
    instance.z = (instance.x == instance.y):

https://docs.djangoproject.com/en/dev/ref/signals/#pre-save

from django.db.models.signals import pre_save
from django.dispatch import receiver
from myapp.models import Alpha

@receiver(pre_save, sender=Alpha)
def my_handler(sender, instance, raw, using, update_fields):
    instance.z = (instance.x == instance.y)

EDIT: Used freakish one line boolean assignment

Comments

0

If you are creating instance of django model class with positional arguments, first argument is used for id and should be None in case if you dont want to set it manually:

>>> a = Alpha(None, 3, 3)
>>> a
<Alpha: Alpha object>
>>> a.x
3
>>> a.y
3
>>> a.z
u'false'

Simplest way to set z=True if x==z is just pass this comparison as third (no count None) argument in class __init__:

>>> x = y = 3
>>> a = Alpha(None, x, y, x==y)

And of course if you can override __init__ method (check @freakish answer).

4 Comments

-1: Actually he is not: I don't see Alpha inherting from models.Model. But what is more important: that's a detail which does not answer the question at all.
@freakish check question, OP talks about django. And why you place models.Model as base class of Alpha?
What I've meant is that you are talking about positions of args while OP's code is missing the most important inheritance (the code would not work in the first place). So it is safe to assume that he's initialization was a typo as well. I'm glad you've edited the answer. However the first part is unrelated to the question and the second part is just a copy thus still -1.
I've removed -1 from your post. Although I don't like your behaviour (copying other people answers) it does answer the question now. I won't argue anymore.

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.