Django 1.7 migration cannot serialize a class method - python

I have a very basic class that looks something like the following:
class Car(Model):
name = CharField(max_length=255, unique=True)
#classmethod
def create_simple_examples(cls):
for c in ['Sedan', 'Coupe', 'Van', 'SUV']:
cls.objects.get_or_create(name=c)
#classmethod
def get_default(cls):
c, _ = cls.objects.get_or_create(name='Sedan')
return c
def __unicode__(self):
return self.name
I am trying to add it to a django app. I have the two class methods to 1. a function to populate the table quickly, and 2. to grab a default one which will be used often.
When I run
python manage.py makemigrations myapp
I get the following error
ValueError: Cannot serialize: <bound method ModelBase.get_default of <class 'crunch.django.myapp.models.Car'>>
I am not quite sure why it's trying to serialize my get_default function as that's not really part of the migration of the table itself. Any help would be greatly appreciated
UPDATE I think I may have found the source of the problem (still not sure how to fix it though...)
I have other classes that are FKing to my new class, and the default uses my default above...something like this
class OtherClass(Model):
car = ForeignKey(Car, default=Car.get_default)
It looks like the migration is trying to serialize the function because of this. Any tips on how to get around this?

Add the #deconstructible decorator to the classes which have a classmethod
from django.utils.deconstruct import deconstructible
#deconstructible
class Car(Model):
...
More documentation on deconstructible can be found here

As explained in Django's migrations docs, Django can serialize function and method references, (in Python 3) unbound methods used from within the class body, and a bunch of other stuff, but it can't serialize everything.
In this case, because you've made get_default a #classmethod, Car.get_default is a bound method (i.e., it takes an implicit reference to Car as its first parameter), rather than a plain function or method reference, and Django doesn't know what to do with that.
Try making get_default a #staticmethod instead, or make a free function (top-level function) that calls Car.get_default.

Related

return a string from a function in a class in python

Cannot return a string from a python class to another python class.
Created two classes and need to get a string from one to the other. I keep getting the message -
'app.classes.xxx' has no attribute 'returnDBString'
Class1.py
from app.classes import DBManager
def CustomerSetup(self, user_id):
db = DBManager.returnDBString()
cnxn = pdc.connect(db)
DBManager.py
class DBManager():
def returnDBString():
return 'Database string and connection info'
def returnConnection():
return pdc.connect(returnDBString())
I was expecting to get back the actual string in the class, but I keep getting the error
app.classes.DBManager' has no attribute 'returnDBString
This has nothing to do with returning strings.
For some reason you have put your function inside a class, which just happens to have the same name as the module it is in. But Python is not Java; functions don't need to be in classes, and if you do define a class then you need to import it specifically, not just the module (or, at least, refer to it via the module).
In any case, you should remove the class declaration and just put your two functions directly at module level.
Decorate the method with #classmethod if it makes sense to have this method under DBManager
This is an issue of usability of module with classes.
There are 2 solution to your problem:
1) If you create class with member function in DBManager.py and want to use it some different file.Then, first thing which should come into you mind that a class is nothing without an class object. You need to create an object of your class and call into returnDBString() with that object. keep in mind you need to create constructor init() as well of you class, its incomplete in your code.
def CustomerSetup(self, user_id):
DBObject = DBManager()
db = DBObject.returnDBString()
2) Don't have class in DBManager.py, delete class and have same function without class. In this case your current code Class1.py would work.
You need to instantiate the class in Class1.py, and make pdc available to it:
db = DBManager.DBManager(pdc).returnDBString()
Note the parens, DBManager().
You'll also need to write your DBManager class like so:
class DBManager():
def __init__(self, pdx):
self.pdx = pdx
def returnDBString(self):
return 'Database string and connection info'
def returnConnection(self):
return self.pdc.connect(self.returnDBString())

Can python class variable be used as both class and instance variable? [duplicate]

I'm simultaneously learning Python while picking up Django. I'm familiar with many other languages.
In the following code snippet, x is a class variable of class Foo.
class Foo(object):
x = 9000
Given the previous declaration, the following works fine.
print Foo.x
The Django framework lets you create your model by defining Python classes. It makes fields out of the different class variables in your Python classes.
class Question(models.Model):
question_text = models.CharField(max_length=200)
Why does the following code snippet:
#!/usr/bin/env
import os, django
os.environ['DJANGO_SETTINGS_MODULE'] = 'mysite.settings'
django.setup()
from polls.models import Question, Choice
print Question.question_text
throw the following error:
AttributeError: type object 'Question' has no attribute 'question_text'
As far as I'm understanding everything my Question class has a single static member defined: Question.question_text.
Django models use a metaclass to alter what is normal class behaviour.
Use dir(Question) and you'll see there are different attributes on that class now. This is custom behaviour just for Django models however.
If you are curious you can study the metaclass __new__ method, but it does a lot of work specific to Object Relational Mapping tasks.
Magic.
No, really.
Python classes aren't set-in-stone structure, like they are in C++. They are, themselves, just objects — instances of another type:
class Foo(object):
pass
print(type(Foo)) # <class 'type'>
You can even make a class like you'd make any other object, by calling type. This:
class Bar(object):
a = 1
b = 2
Is really (more or less) syntactic sugar for this:
Bar = type('Bar', (object,), {'a': 1, 'b': 2})
type takes the name of your new class, a list of its superclasses, and a dict of all the attributes of the class, and spits out a new class.
But, because type is just a class like any other, it's possible to subclass it and give it different behavior. And this is what Django has done: it's created a subclass of type that does something different with the dict of attributes you pass to it.
You don't see this happening directly in your own code, but if you check type(models.Model), you'll find out its type is not type, but something specific to Django. It probably has "meta" in the name, because it's called a metaclass: the class of a class.
This is a fairly common pattern for making "declarative" libraries in Python, where the attributes of a class actually define some kind of structure. You can see the same thing in form validation (wtforms), schema validation (colander), other ORMs (sqlalchemy), and even the stdlib enum module.
Question is an object of type type. You want an instance of Question:
>>> q= Question(text = "Does a dog have the buddha nature?")
Then you should get
q.text
"Does a dog have the buddha nature?"
Note that this object will not persist unless you save() it:
>>> q.save()

Django, Python, and Class Variables

I'm simultaneously learning Python while picking up Django. I'm familiar with many other languages.
In the following code snippet, x is a class variable of class Foo.
class Foo(object):
x = 9000
Given the previous declaration, the following works fine.
print Foo.x
The Django framework lets you create your model by defining Python classes. It makes fields out of the different class variables in your Python classes.
class Question(models.Model):
question_text = models.CharField(max_length=200)
Why does the following code snippet:
#!/usr/bin/env
import os, django
os.environ['DJANGO_SETTINGS_MODULE'] = 'mysite.settings'
django.setup()
from polls.models import Question, Choice
print Question.question_text
throw the following error:
AttributeError: type object 'Question' has no attribute 'question_text'
As far as I'm understanding everything my Question class has a single static member defined: Question.question_text.
Django models use a metaclass to alter what is normal class behaviour.
Use dir(Question) and you'll see there are different attributes on that class now. This is custom behaviour just for Django models however.
If you are curious you can study the metaclass __new__ method, but it does a lot of work specific to Object Relational Mapping tasks.
Magic.
No, really.
Python classes aren't set-in-stone structure, like they are in C++. They are, themselves, just objects — instances of another type:
class Foo(object):
pass
print(type(Foo)) # <class 'type'>
You can even make a class like you'd make any other object, by calling type. This:
class Bar(object):
a = 1
b = 2
Is really (more or less) syntactic sugar for this:
Bar = type('Bar', (object,), {'a': 1, 'b': 2})
type takes the name of your new class, a list of its superclasses, and a dict of all the attributes of the class, and spits out a new class.
But, because type is just a class like any other, it's possible to subclass it and give it different behavior. And this is what Django has done: it's created a subclass of type that does something different with the dict of attributes you pass to it.
You don't see this happening directly in your own code, but if you check type(models.Model), you'll find out its type is not type, but something specific to Django. It probably has "meta" in the name, because it's called a metaclass: the class of a class.
This is a fairly common pattern for making "declarative" libraries in Python, where the attributes of a class actually define some kind of structure. You can see the same thing in form validation (wtforms), schema validation (colander), other ORMs (sqlalchemy), and even the stdlib enum module.
Question is an object of type type. You want an instance of Question:
>>> q= Question(text = "Does a dog have the buddha nature?")
Then you should get
q.text
"Does a dog have the buddha nature?"
Note that this object will not persist unless you save() it:
>>> q.save()

How do you have an attribute called "property" and use the #property decorator?

I have a bit of a problem, and I've tried googling, but it doesn't turn up anything helpful.
I'm designing a django application and I want/need to have a field called "property". The reason for this is that is the technical title of the thing I'm trying to manage, and where possible I'd like to keep the business terminology.
Now this hasn't been a problem... up until now.
I now need to have a method, that I'd like to be able to use as a property, but there is a bit of a clash around the use of the token property.
class DataElementConcept(trebleObject):
template = "polls/dataElementConcept.html"
objectClass = models.ForeignKey(ObjectClass,blank=True,null=True)
property = models.ForeignKey(Property,blank=True,null=True)
#property
def registryCascadeItems(self):
return [self.objectClass,self.property]
I understandably get this error.
File "/home/theodore/Github/possum-mdr/polls/models.py", line 381, in DataElementConcept
#property
TypeError: 'ForeignKey' object is not callable
Is there a way around this that lets me treat this method as a property, and keep the property attribute?
Maybe this helps:
# On the module-level, do a workaround reference
# as property() is just a normal built-in function
_property = property
class Foobar:
property = ....
#_property
def registryCascadeItems(self):
....
Use the "fully-qualified" name of the builtin property:
import __builtin__
#__builtin__.property
def registryCascadeItems(self): ...
Of course, I used quotations around the term "fully-qualified" because this is not a pythonic term. There are no name-qualifications in python. What this really is, is just another place where the original property is defined and can be accessed.
IMHO, this also makes your code more readable. There is no doubt what kind of property is involved -- you explicitly refer to the builtin one.

Python grab class in class definition

I don't even know how to explain this, so here is the code I'm trying.
from couchdb.schema import Document, TextField
class Base(Document):
type = TextField(default=self.__name__)
#self doesn't work, how do I get a reference to Base?
class User(Base):
pass
#User.type be defined as TextField(default="Test2")
The reason I'm even trying this is I'm working on creating a base class for an orm I'm using. I want to avoid defining the table name for every model I have. Also knowing what the limits of python is will help me avoid wasting time trying impossible things.
The class object does not (yet) exist while the class body is executing, so there is no way for code in the class body to get a reference to it (just as, more generally, there is no way for any code to get a reference to any object that does not exist). Test2.__name__, however, already does what you're specifically looking for, so I don't think you need any workaround (such as metaclasses or class decorators) for your specific use case.
Edit: for the edited question, where you don't just need the name as a string, a class decorator is the simplest way to work around the problem (in Python 2.6 or later):
def maketype(cls):
cls.type = TextField(default=cls.__name__)
return cls
and put #maketype in front of each class you want to decorate that way. In Python 2.5 or earlier, you need instead to say maketype(Base) after each relevant class statement.
If you want this functionality to get inherited, then you have to define a custom metaclass that performs the same functionality in its __init__ or __new__ methods. Personally, I would recommend against defining custom metaclasses unless they're really indispensable -- instead, I'd stick with the simpler decorator approach.
You may want to check out the other question python super class relection
In your case, Test2.__base__ will return the base class Test. If it doesn't work, you may use the new style: class Test(object)

Categories