I'm developing Django application, and I have following error
'Sheep' object has no attribute _state
My models are constructed like this
class Animal(models.Model):
aul = models.ForeignKey(Aul)
weight = models.IntegerField()
quality = models.IntegerField()
age = models.IntegerField()
def __init__(self,aul):
self.aul=aul
self.weight=3
self.quality=10
self.age=0
def __str__(self):
return self.age
class Sheep(Animal):
wool = models.IntegerField()
def __init__(self,aul):
Animal.__init__(self,aul)
What I must do?
firstly, you must be very careful overriding __init__ to have non-optional arguments. remember it will be called every time you get an object from a queryset!
this is the correct code you want:
class Animal(models.Model):
#class Meta: #uncomment this for an abstract class
# abstract = True
aul = models.ForeignKey(Aul)
weight = models.IntegerField(default=3)
quality = models.IntegerField(default=10)
age = models.IntegerField(default=0)
def __unicode__(self):
return self.age
class Sheep(Animal):
wool = models.IntegerField()
I highly suggest setting the abstract option on Animal if you will only ever be using subclasses of this object. This ensures a table is not created for animal and only for Sheep (etc..). if abstract is not set, then an Animal table will be created and the Sheep class will be given it's own table and an automatic 'animal' field which will be a foreign key to the Animal model.
Django docs recommend against you to use __init__ method in models:
You may be tempted to customize the model by overriding the __init__ method. If you do so, however, take care not to change the calling signature as any change may prevent the model instance from being saved. Rather than overriding __init__, try using one of these approaches:
Add a classmethod on the model class
Add a method on a custom manager (usually preferred)
Related
In Django, I have an abstract class:
class AbstractResult(models.Model):
specimen = models.ForeignKey(Specimen, on_delete=models.CASCADE, related_name='%(class)s')
...
class Meta:
abstract = True
This gives me some control over the related name of this field for each concrete class, but not full control. I'd like to be able to set this name in each concrete class.
I thought maybe I could use a callable:
class AbstractResult(models.Model):
def get_related_name(self):
raise NotImplementedError("Override this method in your concrete model classes!")
specimen = models.ForeignKey(Specimen, on_delete=models.CASCADE, related_name=get_related_name)
But that didn't work, as the related_name arg doesn't take a callable.
I also thought maybe I could do:
class AbstractResult(models.Model):
related_name = 'OVERRIDE THIS ATTRIBUTE!'
specimen = models.ForeignKey(Specimen, on_delete=models.CASCADE, related_name=related_name)
and then try to use it in the concrete class:
class TestA_Result(AbstractResult):
related_name = "test_a_results"
but that didn't work either.
Why didn't that work? Is there any simple way to make it work?
Update:
It looks like the "problem" is that the related_name=related_name in my last example gets evaluated when the AbstractResult class is being constructed - not when the TestA_Result class is being constructed. This isn't a Django thing - this is just how Python works:
class AbstractClass:
field_one = 'field one set in abstract class'
field_two = field_one
class ConcreteClass(AbstractClass):
field_one = 'set in concrete class'
inst = ConcreteClass()
inst.field_one # 'set in concrete class'
inst.field_two # 'field one set in abstract class'
Is there a way around this that would allow me to set the related_name in Django's concrete class?
Having two models, parent and child, I want to set the value of one of the attributes the child inherits.
For example, in the following code the color attribute would be set when creating a RedCat object.
# Parent class
class Cat(models.Model):
name = models.CharField(max_length=10)
color = models.CharField(max_length=10)
class Meta:
abstract = True
# Child class
class RedCat(Cat):
color = 'red' # <-- Doesn't work!
I'm considering either overriding the parent attribute or having the attribute only on the children, but I wonder, is there a right/better way to set a default value in a Django model for an inherited attribute?
You can link using ForeignKey and then override the parent field value in child.
models.py
# Parent class
class Cat(models.Model):
name = models.CharField(max_length=10)
color = models.CharField(max_length=10)
# Child class
class RedCat(Cat):
color_type = models.ForeignKey(Cat, on_delete=models.CASCADE)
def save(self, *args, **kwargs):
self.color_type.color = "Red"
self.color_type.save()
super(RedCat, self).save(*args, **kwargs)
First, the description of being a child of a parent in django, I think it is not by subclassing the parent class.
Instead, Considering if RedCat is a child of Cat, you should create a new model that has a ForeignKey field that aims to the Cat module.
I think what you mean is to set default values for a field, which can be done by using the default attr on the field.
Models.py
class Cat(models.Model):
...
class RedCat(models.Model):
cat = models.ForeignKey(Cat, on_delete=models.CASCADE)
color = models.CharField(
max_length=10,
default='red',
)
When I first made the question I was confused because I couldn't see the value for the attribute being set in the subclass in the /admin interface, but the code actually works.
The parent class is an abstract class that contains the definition of the attribute.
The child class inherits this attribute correctly and sets its value.
When navigating the admin panel for this model, the value of the attribute will not show, as it is established by default and will never change, but this attribute is still correctly set and accessible from everywhere else.
See Django docs on abstract model classes
I have a parent class and a child class, like so:
class Animal(models.Model):
age = models.IntegerField()
class Bird(Animal)
wingSpan = models.DecimalField()
Here's the view to get birds:
class BirdViewSet(viewsets.ModelViewSet):
queryset = Bird.objects.all()
serializer_class = BirdSerializer
And here is the serializer:
class BirdSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Bird
fields = ['age', 'wingSpan']
In the database, jango appropriately created an animal_prt_id field in the birds table, so that this view/serializer pair knows where to find the age, which is mapped to the parent class, Animal.
How to make a view/serializer pair that does the opposite, meaning, it receives the id of an Animal and responds with the complete Bird (or with any other Animal subclass I might have)?
There is an useful package called django-model-utils that provides an InheritanceManager logic.
TLDR: After setting up the package, your code will sort of look like this
bird = Animal.objects.filter(pk=animal_id).select_subclasses("bird")
I am using Django Rest Framework, and want to allow API clients to create resources, where one attribute of the created resource is the (required) primary key of a related data structure. For example, given these models:
class Breed(models.Model):
breed_name = models.CharField(max_length=255)
class Dog(models.Model):
name = models.CharField(max_length=255)
breed = models.ForeignKey(Breed)
I want to allow the caller to create a Dog object by specifying a name and a breed_id corresponding to the primary key of an existing Breed.
I'd like to use HyperlinkedModelSerializer in general for my APIs. This complicates things slightly because it (apparently) expects related fields to be specified by URL rather than primary key.
I've come up with the following solution, using PrimaryKeyRelatedField, that behaves as I'd like:
class BreedSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Breed
class DogSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Dog
read_only_fields = ('breed', )
breed_id = serializers.PrimaryKeyRelatedField(queryset=Breed.objects.all())
def create(self, validated_data):
validated_data['breed'] = validated_data['breed_id']
del validated_data['breed_id']
return Dog.objects.create(**validated_data)
But it seems weird that I would need to do this mucking around with the overloaded create. Is there a cleaner solution to this?
Thanks to dukebody for suggesting implementing a custom related field to allow an attribute to be serialized OUT as a hyperlink, but IN as a primary key:
class HybridPrimaryKeyRelatedField(serializers.HyperlinkedRelatedField):
"""Serializes out as hyperlink, in as primary key"""
def to_internal_value(self, data):
return self.get_queryset().get(pk=data)
This lets me do away with the create override, the read_only_fields decorator, and the weirdness of swapping out the breed and breed_id:
class BreedSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Breed
class DogSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Dog
breed = HybridPrimaryKeyRelatedField(queryset=Breed.objects,
view_name='breed-detail')
I have a Base class for many Subclasses, and the only thing changing within the subclasses is a certain method (the template pattern). However I am stuck and can't get it to work.
class Base(models.Model):
_value = models.CharField(max_length=200)
_name = models.CharField(max_length=200)
user = models.ForeignKey(User, related_name="some_set")
#used as a property
def value():
def fget(self):
self.refresh()
return self._value
def refresh(self):
raise NotImplementedError("..")
class Subclass1(Base):
def refresh(self):
self._value = some_val
class Subclass2(Base):
def refresh(self):
self._value = some_other_val
I would love to be able to treat the entire related set as the same entity, and call the value property on each, with each deferring to its own implemented version of refresh, i.e.
for x in user.some_set.all():
print x.value
but at this point it doesn't seem possible, even with removing refresh in the superclass. I've also thought of using the Strategy pattern and use a ForeignKey relationship to call the method, but I would still have to have a base class in the ForeignKey that the subclasses derive from.
use Proxy Models
from the doc
Sometimes, however, you only want to change the Python behavior of a model – perhaps to change the default manager, or add a new method.
This is what proxy model inheritance is for: creating a proxy for the original model. You can create, delete and update instances of the proxy model and all the data will be saved as if you were using the original (non-proxied) model. The difference is that you can change things like the default model ordering or the default manager in the proxy, without having to alter the original.
I might be missing the point, but have you tried Django Model Utils?
https://bitbucket.org/carljm/django-model-utils/src
If you look at the inheritance manager and make the relevant changes to your model, you should then be able to query as per:
entities = Base.objects.filter(user=my_user_obj).select_subclasses()
for entity in entities:
print entity.value
I ended up using the Strategy pattern with a GenericForeignKey
class Base(models.Model):
_name = models.CharField(max_length=200)
user = models.ForeignKey(User, related_name="some_set")
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
strategy = GenericForeignKey()
#used as a property
def value():
def fget(self):
return self.strategy.value
class Strategy1(models.Model):
#some other definitions
def value():
def fget(self):
return some_var
class Strategy2(models.Model):
#some other definitions
def value():
def fget(self):
return some_other_var
Which allowed me to do for x in user.some_set.all(): print x.value