Count the number of rows in a Django database : AttributeError - django

I have database created by Django model, where idRecruteur is the fields of the table Offre.
I need to count the number of rows where idRecruteur = 1.
This is my "Offre" table code:
#python_2_unicode_compatible
class Offre(models.Model):
titre = models.CharField(max_length=100)
dateAjout = models.DateField(auto_now=False, auto_now_add=False)
nature = models.CharField(max_length=50)
duree = models.CharField(max_length=50)
niveau = models.CharField(max_length=50)
description = models.CharField(max_length=50)
salaire = models.FloatField(null=True, blank=True)
idRecruteur = models.ForeignKey(Recruteur, related_name="Offre", on_delete=models.CASCADE)
def __str__(self):
return "Offre: {}".format(self.title)
and this is my queryset:
class OffresparEntrepriseViewSet(ModelViewSet):
queryset = Offre.objects.filter(idRecruteur=1).count()
serializer_class = OffreSerializer
I get the error " AttributeError: 'int' object has no attribute 'model' "
Any ideas what I am doing wrong?

ViewSet's queryset attribute should be QuerySet object, but count() returns integer. You need to use queryset = Offre.objects.filter(idRecruteur=1) as viewset queryset, and move counting functionality to another level. For example using list_route:
class OffresparEntrepriseViewSet(ModelViewSet):
queryset = Offre.objects.filter(idRecruteur=1)
serializer_class = OffreSerializer
#list_route()
def count(self, request):
count = self.queryset.count()
return Response({'count': count})
Now you can get count by accesing viewset_url/count url.

Related

django serializer field not recognizing attribute clearly defined

when i try to run a view I get this error:
AttributeError: Got AttributeError when attempting to get a value for field `inreplytouser` on serializer `ContentFeedPostCommentSerializer`.
The serializer field might be named incorrectly and not match any attribute or key on the `QuerySet` instance.
Original exception text was: 'QuerySet' object has no attribute 'inreplytouser'.
Here is my model:
class ContentFeedPostComments(models.Model):
inreplytouser = models.ForeignKey(SiteUsers, null=True, related_name='replytouser', blank=True, on_delete=models.CASCADE)
inreplytotopcomment = models.BigIntegerField(null=True, blank=True)
timecommented = models.DateTimeField(auto_now_add=True)
user = models.ForeignKey(SiteUsers, on_delete=models.CASCADE)
contentcreator = models.ForeignKey(ContentCreatorUsers, on_delete=models.CASCADE)
contentfeedpost = models.ForeignKey(ContentFeedPost, on_delete=models.CASCADE)
text = models.CharField(max_length=1000)
here is the serializer:
class ContentFeedPostCommentSerializer(ModelSerializer):
id = IntegerField()
inreplytouser = SiteusersSerializer()
user = SiteusersSerializer()
contentcreator = ContentCreatorSerializer()
class Meta:
model = ContentFeedPostComments
fields = ('id','inreplytouser', 'inreplytotopcomment', 'timecommented',
'user', 'contentcreator', 'contentfeedpost', 'text')
here is the view:
class ContentFeedPostsComments(APIView):
def get(self, request, *args, **kwargs):
postid = kwargs.get('postid')
contentfeedpost = get_object_or_404(ContentFeedPost, id=postid)
topcomments = ContentFeedPostComments.objects.filter(contentfeedpost= contentfeedpost, inreplytotopcomment= None).order_by('timecommented')
replycomments = ContentFeedPostComments.objects.filter( contentfeedpost = contentfeedpost, inreplytotopcomment__isnull = False).order_by('timecommented')
serializedtopcomments = ContentFeedPostCommentSerializer(topcomments)
serializedreplycomments = ContentFeedPostCommentSerializer(replycomments)
payload = {
'topcomments': serializedtopcomments.data,
'replycomments': serializedreplycomments.data
}
return Response(payload)
I was reading something about source being passsed into the inreplytouser field of the serializer field but that makes no sense. Your wisdom and knowledge on this situation is greatly appreciated.
Since querysets are a collection of objects, many=True..[DRF-doc] needs to be set in the serializer:
serializedtopcomments = ContentFeedPostCommentSerializer(topcomments, many=True)
serializedreplycomments = ContentFeedPostCommentSerializer(replycomments, many=True)

Filter by fields from foreignKey relationships

I got a bunch of models and some of them are connected (by foreign-key relationships) and I wrote a serializer which allows me to print out all of the connected fields that I want, and leave out what I do not want to see. Great. Now I also have a basic filter, which uses the model (PmP) which contains all the foreignkeys, but now I want to add another filter for a field (field name e from PmPr Model) from a different Model, one that is read in via foreignkey connection (li in Model PmP connects to model PmL containing field pro which connects to model PmPr where the field e is). But I dont know how to do that and as far as I can see, I cant set two filter_classes inside my view (PmPLListView)?! And I dont know how to access the field via the foreignkey relation. So how do I go about this? If I can access the e field from PmPr Model via my existing filter - than that is also fine with me, I dont necessary want two filter classes (if even possible). It was just me first thought. (btw. sorry about the strange names, but unfortunately I'm not allowed to write the real names)
these are my models (at least the relevant ones):
class PmP(models.Model):
created_at = models.DateTimeField()
pr = models.DecimalField(max_digits=6, decimal_places=2)
li = models.ForeignKey(PmL, models.DO_NOTHING)
se = models.ForeignKey('PmSe', models.DO_NOTHING)
class Meta:
managed = False
db_table = 'pm_p'
class PmL(models.Model):
u = models.TextField()
pro = models.ForeignKey('PmPr', models.DO_NOTHING)
sh = models.ForeignKey('PmS', models.DO_NOTHING)
active = models.IntegerField()
class Meta:
managed = False
db_table = 'pm_l'
class PmSe(models.Model):
name = models.TextField()
s_i_id = models.TextField(blank=True, null=True)
sh = models.ForeignKey('PmS',
models.DO_NOTHING,
blank=True,
null=True)
class Meta:
managed = False
db_table = 'pm_se'
class PmPr(models.Model):
name = models.TextField()
e = models.CharField(max_length=13)
created_at = models.DateTimeField()
cus = models.ForeignKey(PmC, models.DO_NOTHING)
u_v_p = models.DecimalField(max_digits=10,
decimal_places=2,
blank=True,
null=True)
cf = models.IntegerField(blank=True, null=True)
s_k_u = models.IntegerField(blank=True, null=True)
class Meta:
managed = False
db_table = 'pm_pr'
this is what my serializer looks like:
class PmPLSerializer(serializers.ModelSerializer):
# id = serializers.SerializerMethodField('get_l_id')
u = serializers.SerializerMethodField('get_l_u')
sh = serializers.SerializerMethodField('get_sh_name')
name = serializers.SerializerMethodField('get_pro_name')
e = serializers.SerializerMethodField('get_pro_e')
u_v_p = serializers.SerializerMethodField('get_pro_u_v_p')
s_k_u = serializers.SerializerMethodField('get_pro_s_k_u')
se = serializers.SerializerMethodField('get_se_name')
pr = serializers.SerializerMethodField('get_pr')
created_at = serializers.SerializerMethodField('get_created_at')
class Meta:
model = PmP
# fields = '__all__'
fields = ('u', 'sh', 'name', 'e', 's_k_u', 'u_v_p', 'pr',
'created_at', 'se')
depth = 2
def get_l_id(self, obj):
return obj.li.id
def get_l_u(self, obj):
return obj.li.u
def get_sh_name(self, obj):
return obj.li.sh.name
def get_pro_name(self, obj):
return obj.li.pro.name
def get_pro_e(self, obj):
return obj.li.pro.e
def get_pro_u_v_p(self, obj):
return obj.li.pro.u_v_p
def get_pro_s_k_u(self, obj):
return obj.li.pro.s_k_u
def get_se_name(self, obj):
return obj.se.name
def get_pr(self, obj):
return obj.pr
def get_created_at(self, obj):
return obj.created_at
this is my filter class:
class PmPFilter(rfilters.FilterSet):
class Meta:
model = PmP
fields = [
"created_at",
"pr",
]
for field in ["pr"]:
exec(f'min_{field} = rfilters.NumberFilter(field, lookup_expr="gte")')
exec(f'max_{field} = rfilters.NumberFilter(field, lookup_expr="lte")')
# filter by date as "is_less_than_or_equal_to"
written_to = rfilters.CharFilter(method="created_at_to", label="created_at to")
# filter by date as "is_greater_than_or_equal_to"
written_from = rfilters.CharFilter(method="created_at_from", label="created_at from")
# filter by exact date
written = rfilters.CharFilter(method="created_at_exact", label="created_at exact")
def created_at_exact(self, queryset, name, value):
year, month, day, hour, minute, second = self.parse_date(value)
cdate = datetime(year, month, day, hour, minute, second)
return queryset.filter(created_at=cdate)
def created_at_to(self, queryset, name, value):
year, month, day, hour, minute, second = self.parse_date(value)
cdate = datetime(year, month, day, hour, minute, second)
return queryset.filter(created_at__lte=cdate)
def created_at_from(self, queryset, name, value):
year, month, day, hour, minute, second = self.parse_date(value)
cdate = datetime(year, month, day, hour, minute, second)
return queryset.filter(created_at__gte=cdate)
def parse_date(self, value):
return (
parser.parse(value).year,
parser.parse(value).month,
parser.parse(value).day,
parser.parse(value).hour,
parser.parse(value).minute,
parser.parse(value).second,
)
and finally, this is my view:
class PmPLListView(generics.ListAPIView):
queryset = PmP.objects.all()
serializer_class = PmPLSerializer
filter_backends = (DjangoFilterBackend, SearchFilter, OrderingFilter)
ordering_fields = ["created_at", "pr"]
filter_class = PmPFilter
fields = ("created_at", "pr")
filter_fields = fields
search_fields = fields
def get_queryset(self):
"""
This view should return a list of all data
"""
return PmP.objects.filter()
oh I got it! I can access the foreign relationship with two underscores. So I modified my Filter class to this:
class PmPFilter(rfilters.FilterSet):
class Meta:
model = PmPrice
fields = [
"created_at",
"pr",
"li__pro__e",
]
...
and inside my PmPLListView view I also added the double underscores to access the field:
class PmPLListView(generics.ListAPIView):
queryset = PmP.objects.all()
serializer_class = PmPLSerializer
filter_backends = (DjangoFilterBackend, SearchFilter, OrderingFilter)
ordering_fields = ["created_at", "pr"]
filter_class = PmPFilter
fields = ("created_at", "pr", "li__pro__e")
filter_fields = fields
search_fields = fields
now I can filter by field e

KeyError: 'id' in django rest framework when trying to use update_or_create() method

I am trying to update the OrderItem model using update_or_create() method. OrderItem model is related to the Order model with many to one relationship ie with a Foreignkey.
I am trying to query the orderitem object using id and update the related fields using default as you can see, but got this error.
My models:
class Order(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, blank=True)
ordered_date = models.DateTimeField(auto_now_add=True)
ordered = models.BooleanField(default=False)
total_price = models.CharField(max_length=50,blank=True,null=True)
#billing_details = models.OneToOneField('BillingDetails',on_delete=models.CASCADE,null=True,blank=True,related_name="order")
def __str__(self):
return self.user.email
class Meta:
verbose_name_plural = "Orders"
ordering = ('-id',)
class OrderItem(models.Model):
#user = models.ForeignKey(User,on_delete=models.CASCADE, blank=True)
order = models.ForeignKey(Order,on_delete=models.CASCADE, blank=True,null=True,related_name='order_items')
item = models.ForeignKey(Product, on_delete=models.CASCADE,blank=True, null=True)
order_variants = models.ForeignKey(Variants,on_delete=models.CASCADE,blank=True,null=True)
quantity = models.IntegerField(default=1)
ORDER_STATUS = (
('To_Ship', 'To Ship',),
('Shipped', 'Shipped',),
('Delivered', 'Delivered',),
('Cancelled', 'Cancelled',),
)
order_item_status = models.CharField(max_length=50,choices=ORDER_STATUS,default='To_Ship')
My view:
class UpdateOrderView(UpdateAPIView):
permission_classes = [AllowAny]
queryset = Order.objects.all()
serializer_class = OrderUpdateSerializer
My serializers:
class OrderUpdateSerializer(serializers.ModelSerializer):
order_items = OrderItemUpdateSerializer(many=True)
billing_details = BillingDetailsSerializer()
class Meta:
model = Order
fields = ['id','ordered','order_status','order_items','billing_details']
def update(self, instance, validated_data):
instance.order_status = validated_data.get('order_status')
instance.ordered = validated_data.get('ordered')
#billing_details_logic
billing_details_data = validated_data.pop('billing_details',None)
if billing_details_data is not None:
instance.billing_details.address = billing_details_data['address']
instance.billing_details.save()
#order_items_logic
instance.save()
order_items_data = validated_data.pop('order_items')
# print(order_items_data)
#instance.order_items.clear()
for order_items_data in order_items_data:
oi, created = OrderItem.objects.update_or_create(
id= order_items_data['id'],
defaults={
'quantity' : order_items_data['quantity'],
'order_item_status': order_items_data['order_item_status']
}
)
super().update(instance,validated_data)
return oi
Updated serializer:
for order_item_data in order_items_data:
oi, created = instance.order_items.update_or_create(
id= order_item_data['id'],
defaults={
'quantity' : order_item_data['quantity'],
'order_item_status': order_item_data['order_item_status']
}
)
The order_items data are sent like this.
order_items_data is a list.
Then you iterate over it with the same variable name.
for order_items_data in order_items_data:
Just rename it to something like
for order_data in order_items_data:
and there will be an id in your order_data.
I wasn't getting the id on the OrderedDict also, so I've added a id = serializers.IntegerField(required=False) on the serializer and put that id into the update_or_create method:
for obj in data:
Model.objects.update_or_create(
pk=obj.get('id', None), ...
)

Django Queryset with custom property

django==3.0.5 django-filter==2.3.0 djongo==1.3.3 my database is mongodb
I have a simple model like below
class Parishioner(models.Model):
def _age(self):
return date.today().year - self.dob.year
"""Parishioner model"""
first_name = models.CharField(max_length=255)
last_name = models.CharField(max_length=255)
dob = models.DateField()
age = property(_age)
GENDER_CHOICES = [("Male", "Male"), ("Female", "Female"), ("Other", "Other")]
gender = models.CharField(max_length=10, choices=GENDER_CHOICES)
address = models.CharField(max_length=1000)
fathers_name = models.CharField(max_length=500)
mothers_name = models.CharField(max_length=500)
baptism_certificate = models.ImageField(null=True, upload_to=baptism_certificates_image_file_path)
marriage_certificate = models.ImageField(null=True, upload_to=marriage_certificates_image_file_path)
As you can see age is a calculated property.
I have my viewset like below
class ParishionerViewSet(viewsets.ModelViewSet):
queryset = Parishioner.objects.all()
serializer_class = serializers.ParishionerSerializer
authentication_classes = (TokenAuthentication,)
permission_classes = (IsAuthenticated,)
def get_queryset(self):
first_name = self.request.query_params.get('first_name')
last_name = self.request.query_params.get('last_name')
gender = self.request.query_params.get('gender')
address = self.request.query_params.get('address')
fathers_name = self.request.query_params.get('fathers_name')
mothers_name = self.request.query_params.get('mothers_name')
age = int(self.request.query_params.get('age'))
queryset = self.queryset
if first_name:
queryset = queryset.filter(first_name__contains=first_name)
if last_name:
queryset = queryset.filter(last_name__contains=last_name)
if gender:
queryset = queryset.filter(gender__contains=gender)
if address:
queryset = queryset.filter(address__contains=address)
if fathers_name:
queryset = queryset.filter(fathers_name__contains=fathers_name)
if mothers_name:
queryset = queryset.filter(mothers_name__contains=mothers_name)
if age:
queryset = queryset.filter(age__gte=age)
return queryset.filter()
All I want is to return obects who has age >= provides value.
So if I send a request to this url http://localhost:8000/api/parishioners/?age=32
I'm getting this error --> Cannot resolve keyword 'age' into field
So how can I use this url http://localhost:8000/api/parishioners/?age=32
and get objects who has age greater than or equal to 32 ?
You cannot use a function / property of the model in a query. You need to bring the logic of the function into the query instead.
from django.db.models.functions import ExtractYear, Now
queryset = queryset.annotate(age=ExtractYear(Now()) - ExtractYear('dob')).filter(age__gte=age)

Django Rest Framework serilize relations

How to serialize a fields in related models.
I got a models:
class Order(models.Model):
order_id = models.BigIntegerField(verbose_name='Order ID', unique=True)
order_name = models.CharField(verbose_name='Order name', max_length=255)
order_type = models.IntegerField(verbose_name='Campaign type')
class Types(models.Model):
delimiter = models.CharField(verbose_name='Delimiter', max_length=255)
status = models.BooleanField(verbose_name='Status', default=True)
title = models.CharField(verbose_name='Title', max_length=255)
class User(models.Model):
name = models.CharField(verbose_name='User name', max_length=200, unique=True)
class Report(models.Model):
order = models.ForeignKey(Order, to_field='order_id', verbose_name='Order ID')
user = models.ForeignKey(User, verbose_name='User ID')
ad_type = models.ForeignKey(Types, verbose_name='Type')
imp = models.IntegerField(verbose_name='Total imp')
month = models.DateField(verbose_name='Month', default=datetime.datetime.today)
View:
class ReportLisAPIView(ListAPIView):
serializer_class = ReportSerializer
def get_queryset(self):
month = parse_date(self.kwargs['month']) - relativedelta(day=1)
queryset = (
Report.objects.filter(month=month)
.values_list(
'user', 'user__name', 'order__order_id',
'order__order_name', 'order__order_type'
).all().annotate(Sum('imp'))
)
return queryset
Serializer:
class ReportSerializer(ModelSerializer):
class Meta:
model = Report
depth = 1
I need to get all field like in 'queryset' in get_queryset()
but I got an error:
Got AttributeError when attempting to get a value for field imp on
serializer ReportSerializer. The serializer field might be named
incorrectly and not match any attribute or key on the tuple
instance. Original exception text was: 'tuple' object has no attribute
'imp'.
But if I return in get_queryset() just Report.objects.filter(month=month).all() I'll get all objects and related object with all field, without aggregate of imp and not grouping.
So the question is how to make serializer return structure that set in queryset?
The get_queryset method requires to return a queryset but you are returning a tuple beacause of values_list. Either drop it to return a queryset or go with a more generic view like APIView.
I found a way how to do it.
As I use .values_list() it return list object instead of queryset object. So for serializer do understand what is inside the list I defined all fields in serializer. And in to_representation() I return dictionary like it should be.
Serializer:
class ReportSerializer(serializers.ModelSerializer):
user = serializers.IntegerField()
user_name = serializers.CharField()
order_id = serializers.IntegerField()
order_name = serializers.CharField()
order_type = serializers.IntegerField()
imp = serializers.IntegerField()
class Meta:
model = Report
fields = [
'user', 'user_name', 'order_id', 'order_name',
'order_type', 'imp'
]
depth = 1
def to_representation(self, instance):
Reports = namedtuple('Reports', [
'user',
'user_name',
'order_id',
'order_name',
'order_type',
'imp',
])
return super(ReportSerializer, self).to_representation(
Reports(*instance)._asdict()
)
View:
class ReportLisAPIView(ListAPIView):
serializer_class = ReportSerializer
def get_queryset(self):
month = parse_date(self.kwargs['month']) - relativedelta(day=1)
queryset = (
Report.objects.filter(month=month)
.values_list(
'user', 'user__name', 'order__order_id',
'order__order_name', 'order__order_type'
).all().annotate(Sum('imp'))
)
return queryset
def list(self, *args, **kwargs):
queryset = self.get_queryset()
serializer = self.serializer_class(queryset, many=True)
# actualy that's it! part of which is below can be pass and just
# return Response(serializer.data)
result = {
'month': parse_date(self.kwargs['month']).strftime('%Y-%m'),
'reports': []
}
inflcr = {}
for item in serializer.data:
inflcr.setdefault(item['user'], {
'id': item['user'],
'name': item['user_name'],
'campaigns': []
})
orders = {
'id': item['order_id'],
'name': item['order_name'],
'type': item['order_type'],
'impressions': item['imp'],
}
inflcr[item['user']]['campaigns'].append(orders)
result['reports'] = inflcr.values()
return Response(result)