you need to get the filter using the get_related_filter class method
views
modelPath = 'Money.models'
app_model = importlib.import_module(modelPath)
cls = getattr(app_model, 'Money')
related_result = cls().get_related_filter(search_query='search_query')
models.py
class Money(models.Model):
money = models.DecimalField(max_digits=19, blank=True, default=0, decimal_places=2)
def get_related_filter(self, **kwargs):
results = super(Money, self).objects.filter(Q(money__icontains=kwargs['search_query']))
return results
def __str__(self):
return self.money
why gives 'super' object has no attribute 'objects' Python Django, and does not return filter
It makes no sense to work with super(Money, self) for two reasons:
this proxy object will resolve to Model, but Model nor it parents have an objects attribute; and
even if that was the case, you can only access .objects on a model class, not the instance.
You thus can filter with:
class Money(models.Model):
money = models.DecimalField(max_digits=19, blank=True, default=0, decimal_places=2)
def get_related_filter(self, search_query, **kwargs):
return Money.objects.filter(money__icontains=search_query)
def __str__(self):
return str(self.money)
The __str__ is also supposed to return a string, not a decimal, so you should return str(self.money), not self.money.
Related
I am trying to insert some data into MySQL database (model LogsSeparate) through Django and Django Rest Framework but I keep getting an error which I bet is very easy to solve yet I couldn't figure it out myself:
Error:
if obj.pk is None:
AttributeError: 'LogObjTest' object has no attribute 'pk'
Code:
class LogObjTest():
def __init__(self):
self._id = None
self.bits = None
class getLogs(viewsets.ModelViewSet):
arrayTest=[]
for x in Logs.objects.all():
serializer_class = LogsSeparateSerializer
test = Fields.objects.filter(pac_id=x.message_id_decimal)
binaryTest=x.data_binary
for i in test:
obj=LogObjTest()
obj._id=x.message_id_decimal
obj.bits=binaryTest[i.fld_offset:i.fld_offset+i.fld_len]
arrayTest.append(obj)
queryset = arrayTest
LogsSeparate.objects.bulk_create(arrayTest)
print("arrayTest",arrayTest)
models.py
class LogsSeparate(models.Model):
_id = models.CharField(max_length=255, primary_key=True, null=False, db_column='_id')
bits = models.CharField(max_length=500, db_column='bits')
def __str__(self):
return self.bits```
Don't use LogObjTest. Import LogsSeparate that you created in the model.py file then use it to create a new object.
class getLogs(viewsets.ModelViewSet):
arrayTest=[]
for x in Logs.objects.all():
serializer_class = LogsSeparateSerializer
test = Fields.objects.filter(pac_id=x.message_id_decimal)
binaryTest=x.data_binary
for i in test:
obj=LogsSeparate(_id=x.message_id_decimal, bits=binaryTest[i.fld_offset:i.fld_offset+i.fld_len])
arrayTest.append(obj)
queryset = arrayTest
LogsSeparate.objects.bulk_create(arrayTest)
print("arrayTest",arrayTest)
I am running a django app and have a setup like this:
ModelSuper(models.Model):
class Meta:
abstract = False
ModelSub1(ModelA):
name = models.CharField(...)
def __str__:
return self.name
ModelSub2(ModelA)
name = models.CharField(...)
def __str__:
return self.name
ModelForeign(models.Model):
element = models.ForeignKey(ModelA)
def __str__:
return self.name
So ModelForeign has a FK to ModelSuper. What happens now is that when I create an instance of ModelForeign I can choose if it belongs either to ModelSub1 or to ModelSub2. But the string representation is ModelSuper Onject (3) where (3) is the id.
Normally I can change this representation by overwriting the __str__ method on the model, but since I do not have any fields on the Supermodel I can't return anything.
What I tried:
I have already implemented the __str__ method in the Submodels but that does not help.
I wanted to make the Super model abstract. But this does not let me point FKs to the Supermodel, so I can't do this. My setup requires this FK
I used a generic FK with django's ContentType framework. This is also not an option because it messes completely with my app and is also not recommended from an SQL perspective.
Also when I do API-calls I get ModelSuper Onject (3) back instead of a human-readable name.
Is there a way to do what I intend to do? Thanks in advance for help and hints. Very much appreciated!
EDIT1: What I tried thanks to Abdul's help:
class ModelA(models.Model):
class Meta:
abstract = False
TYPE_CHOICES = [('sub1', 'sub1'), ('sub2', 'sub2')]
type_model = models.CharField(max_length=50, choices=TYPE_CHOICES, null=True, blank=True)
def __str__(self):
if self.type_model == "sub1":
return "sub1"
elif self.type_model == "sub2":
return "sub2"
else:
return "unkown"
I am not understanding how your foreign key works as model inheritance means the tables are separate. How about trying something like this:-
ModelA(models.Model):
TYPE_CHOICES = [('Sub1', 'ModelSub1'), ('Sub2', 'ModelSub2')]
model_type = models.CharField(max_length=4, choices=TYPE_CHOICES)
def __str__:
# Return string representation using if-else
class Meta:
abstract = False
ModelSub1(ModelA):
name = models.CharField(...)
model_a = models.ForeignKey(ModelA, on_delete=models.CASCADE)
def __str__:
return self.name
ModelSub2(ModelA)
name = models.CharField(...)
model_a = models.ForeignKey(ModelA, on_delete=models.CASCADE)
def __str__:
return self.name
ModelForeign(models.Model):
element = models.ForeignKey(ModelA)
def __str__:
return self.name
I got following models:
class OrderItem(models.Model):
ordered_amount = models.IntegerField(validators=[MinValueValidator(0)])
amount = models.IntegerField(default=0)
order = models.ForeignKey(
Order, on_delete=models.CASCADE, related_name="order_items"
)
class Order(models.Model):
reference = models.CharField(max_length=50)
purchase_order = models.CharField(max_length=15, blank=True, null=True)
I'm now writing a serializer for listing orders. In this OrderSerializer I need to access amount and ordered_amount in the OrderItem class. How do I do this?
This is What I have now:
class AdminOrderListSerializer(serializers.ModelSerializer):
amount = serializers.IntegerField()
ordered_amount = serializers.IntegerField()
class Meta:
model = Order
fields = [
"purchase_order",
"reference",
"amount",
"ordered_amount",
]
# noinspection PyMethodMayBeStatic
def validate_amount(self, order):
if order.order_items.amount:
return order.order_items.amount
return
# noinspection PyMethodMayBeStatic
def validate_ordered_amount(self, order):
if order.order_items.ordered_amount:
return order.order_items.ordered_amount
return
This gives me following error:
AttributeError: Got AttributeError when attempting to get a value for field amount on serializer AdminOrderItemListSerializer.
The serializer field might be named incorrectly and not match any attribute or key on the Order instance.
Original exception text was: 'Order' object has no attribute 'amount'.
There are many ways to that, one of them is SerializerMethodField:
from django.db.models import Sum
class AdminOrderListSerializer(serializers.ModelSerializer):
amount = serializers.SerializerMethodField()
ordered_amount = serializers.SerializerMethodField()
def get_amount(self,obj):
return obj.order_items.aggregate(sum=Sum('amount'))['sum']
def get_ordered_amount(self,obj):
return obj.order_items.aggregate(sum=Sum('order_amount'))['sum']
Optimized solution
Another way of achieving this is to annotate the data to queryset, and access them in serializer. For that, you need to change in view:
class SomeView(ListAPIView):
queryset = Order.objects.annotate(amount=Sum('order_items__amount'),order_amount=Sum('order_items__order_amount'))
This is a optimized solution because it reduces database hits(it only hits once).
I have these models:
class BlogCategory(models.Model):
name = models.CharField(max_length=20)
def __str__(self):
return self.name
def get_number_of_categorys_items(self):
return self.post_set.count()
class Post(models.Model):
title = models.CharField(max_length=130)
content = models.TextField()
category = models.ForeignKey(BlogCategory, related_name='blog_category')
def __str__(self):
return self.title
And when I try to call method get_number_of_categorys_items it cause error:
AttributeError: 'BlogCategory' object has no attribute 'post_set'
This method should return number of posts with this category.
What can I do?
Since you've specified the related_name, Django would not automatically create the related name as post_set for you. Either use:
def get_number_of_categorys_items(self):
return self.blog_category.count()
Or, don't specify the related_name:
category = models.ForeignKey(BlogCategory)
I am trying to set a default value for attribute threshold in this code, the threshold should be the current level*50 and this is the model
class Level (models.Model):
name = models.CharField(max_length=20,null=True, blank=True)
description = models.CharField(max_length=20, null=True, blank=True)
number = models.IntegerField(null=True, blank=True)
threshold = models.IntegerField(null=True, blank=True,default=50*number,editable=False)
i get an error unsupported operand types for * : 'int' and 'IntegerField'
You best best is to do such calculation while saving the object. So override Model.save
or a better generic way would be to write a custom field and override pre_save
class DependentIntegerField(models.IntegerField):
def pre_save(self, model_instance, add):
if not add: # set the default only while adding model
return super(self, DependentIntegerField).pre_save(model_instance, add)
return model_instance.number*50
You can further enhance it and make DependentIntegerField generic so that you can pass callable to it and do any calculation, and you can do further enhancements like checking if user has set the value or not before using default value, and to make it more generic so that you can make any Field as dependent field by passing the field class to a factory function. e.g.
from django.db import models
class_map = {}
def depends_field_pre_save(self, model_instance, add):
"""
if default is not callable or it is not a model add, lets skip our hook
"""
if not add or not callable(self.default):
super(self.__class__, self).__init__(self,*args, **kwargs)
value = self.default(model_instance)
setattr(model_instance, self.attname, value)
return value
def FieldDepends(field_class):
"""
return a dervied class from field_class which supports dependent default
"""
if field_class in class_map:
# we already created this class so return that
return class_map[field_class]
new_class = type('Depends'+field_class.__name__, (field_class,), {'pre_save':depends_field_pre_save })
class_map[field_class] = new_class
return new_class
and use it like this
class DependentModel(models.Model):
def threshold_default(model_instance=None):
if model_instance is None:
return 10
return model_instance.number*10
number = models.IntegerField(null=True, blank=True, default=10)
threshold = FieldDepends(models.IntegerField)(null=True, blank=True, default=threshold_default,editable=False)
I have created a small django project djangodepends on bitbucket with test cases
You can override save method to calculation.
https://docs.djangoproject.com/en/dev/topics/db/models/#overriding-predefined-model-methods
class Level (models.Model):
name = models.CharField(max_length=20,null=True, blank=True)
description = models.CharField(max_length=20, null=True, blank=True)
number = models.IntegerField(null=True, blank=True)
threshold = models.IntegerField(null=True, blank=True ,editable=False)
def save(self, *args, **kwargs):
try:
self.threshold = self.number * 50
except TypeError:
pass
super(Level, self).save(*args, **kwargs) # Call the "real" save() method.