On Sat, 2009-02-28 at 15:38 -0500, Vitaly Babiy wrote:
> I have a model that I have created a custom consturctor now when I use
> it in a test or in loaddata, I get this error:

Your model constructor must still allow the normal way of calling model
constructors. That is, you can only extend the allowed parameters, not
replace them.

Django calls Model.__init__ in two different ways. One is by passing in
field values as a list of positional parameters. This is generally only
used internally, because it's *very* hard to get things in the right
order (you have to allow for hidden fields and related fields, etc), but
it's also fast to do, so serializers and the ORM layer use it. Thus, you
have to allow *args in your constructor. The other way __init__ is
called is with a bunch of key=value pairs, corresponding to initialising
the model fields by name. So you also have to allow for **kwargs.

Thus, there are two practical ways to create a new constructor in your
subclasses.

The first approach is to keep the same signature for __init__ and pop
any of your extra keyword arguments from the list before calling
super().__init__. Thus, if you were wanting to pass in a "foo"
parameter, you would do something like this:

        class MyModel(models.Model):
           def __init__(self, *args, **kwargs):
              if "foo" in kwargs:
                 self.foo = kwargs.pop("foo")
              super(MyModel, self).__init__(*args, **kwargs)
        
It's not really practical to add extra positional arguments, since
there's no way to tell if there arguments intended for the Model's
__init__ method or your own.

The second approach is to call your particular constructor by an
entirely different name. Constructors are (more or less) just class
methods that return an instance of the class. So you could write:

        class MyModel(models.Model):
          @classmethod
          def my_constructor(cls, foo):
             obj = cls(....)
             obj.foo = foo
             return foo
        
The general rule here, which is always applicable when subclassing
anything in Python, is that you should try to obey what's called The
Liskov Substitution Principle: the subclass should be able to be used
wherever the base class is used. Which means the __init__ method in the
subclass has to be able to be called using exactly the same (and only
the) parameters used to construct the base class, otherwise it's not
substitutable.

Regards,
Malcolm



--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To post to this group, send email to django-users@googlegroups.com
To unsubscribe from this group, send email to 
django-users+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/django-users?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to