'django model' object is not subscriptable - python

I get this error when I try to do a query set on the Django model
'AppUser' object is not subscriptable
despite it is working normally in a print statement but the error only appears when I put it in an IF statement
here is my code :
def to_representation(self, instance):
data = super().to_representation(instance)
print("reached here") #print normaly
print(AppUser.objects.filter(mobile=instance['mobile']).exists()) #print normally (False)
if AppUser.objects.filter(mobile=instance['mobile']).exists(): # Raises an Exception
if instance.playerprofile_set.all().count() > 0:
player_profile = instance.playerprofile_set.all()[0]
data['player_profile'] = PlayerProfileSerializer(
player_profile).data
for item in Team.objects.all():
if player_profile in item.players.all():
data['team'] = TeamSerializer(item).data
if item.cap.id == player_profile.id:
data['team'] = TeamSerializer(item).data
# data["team"] = instance.
return data
UPDATE
And here is my AppUser class:
class AppUser(models.Model):
first_name = models.CharField(max_length=33)
last_name = models.CharField(max_length=33)
mobile = models.CharField(max_length=33)
email = models.EmailField(null=True, blank=True, max_length=33)
birthdate = models.DateField(null=True, blank=True)
password = models.CharField(max_length=33)
confirm_password = models.CharField(max_length=33)
image = models.FileField(upload_to="uploads", null=True, blank=True)
main_user = models.ForeignKey(User, on_delete=models.CASCADE, null=True)
generated_code = models.PositiveIntegerField(null=True, blank=True)
user_langauge = models.CharField(max_length=33, default="en")
dark_mode = models.BooleanField(default=False)
def __str__(self):
return str(self.mobile) + " " + str(self.first_name) + " " + str(self.last_name)
so calling AppUser.objects.filter() should return a queryset or empty query set, and when adding exists() should return a True or

Instead of count, use exists():
if AppUser.objects.filter(mobile=instance['mobile']).exists():
if instance.playerprofile_set.exists():
player_profile = instance.playerprofile_set.first()
Because it is very efficient in contrast to count() and runs a very small query.
To your original problem, it is not possible to guess what is wrong from the sample code, specially when print works, if not.
Update
I think the error should be with this code:
instance['mobile']
Here instance should be an object, so instance.mobile or data['mobile'] should work.

try this:
def to_representation(self, instance):
data = super().to_representation(instance)
print("reached here") #print normaly
print(AppUser.objects.filter(mobile=instance['mobile']).count() > 0) #print normally (False)
if AppUser:
AppUser.objects.filter(mobile=instance['mobile']).count() > 0
if instance.playerprofile_set.all().count() > 0:
player_profile = instance.playerprofile_set.all()[0]
data['player_profile'] = PlayerProfileSerializer(
player_profile).data
for item in Team.objects.all():
if player_profile in item.players.all():
data['team'] = TeamSerializer(item).data
if item.cap.id == player_profile.id:
data['team'] = TeamSerializer(item).data
# data["team"] = instance.
return data

Related

How to compare two serializer field and show whichever is higher in django rest

I have product serializer which return category_offer_price & product_offer_price,
before getting this response I want to compare both price and only return whichever is highest price.
#Serilaizer.py
class ProductSerializer(ModelSerializer):
category = CategorySerializer()
product_offer_price = SerializerMethodField()
category_offer_price = SerializerMethodField()
class Meta:
model = Products
fields = [
"id",
"product_name",
"slug",
"category",
"description",
"category_offer_price",
"product_offer_price",
"base_price",
"stock",
"is_available",
"created_date",
"images",
"images_two",
"images_three",
]
def get_product_offer_price(self, obj):
try:
product_offer = ProductOffer.objects.get(product=obj)
if product_offer.is_active:
offer_price = product_offer.product_offer_price()
return offer_price
except Exception:
pass
return None
def get_category_offer_price(self, obj):
try:
category_offer = CategoryOffer.objects.get(category=obj.category)
if category_offer.is_active:
offer_price = category_offer.category_offer_price(obj)
return offer_price
except Exception:
pass
return None
#Models.py
class Products(models.Model):
category = models.ForeignKey(Category, on_delete=models.CASCADE)
product_name = models.CharField(max_length=50, unique=True)
slug = models.SlugField(max_length=100, unique=True)
description = models.TextField(max_length=500)
base_price = models.IntegerField()
images = models.ImageField(upload_to="photos/products")
images_two = models.ImageField(upload_to="photos/products")
images_three = models.ImageField(upload_to="photos/products")
stock = models.IntegerField()
is_available = models.BooleanField(default=True)
created_date = models.DateTimeField(auto_now_add=True)
modified_date = models.DateTimeField(auto_now=True)
class Meta:
verbose_name_plural = "Products"
def __str__(self):
return self.product_name
I'd like to know is it possible to compare serializer fields in a serializer class?
You can move into one method, to validate your field. Also, substitute your try:except with get-object-or-404 method and your serializer fields with all value since you are using everything, to have a much cleaner code.
from django.shortcuts import get_object_or_404
class ProductSerializer(ModelSerializer):
category = CategorySerializer()
price = SerializerMethodField()
class Meta:
model = Products
fields = '__all__'
def get_price(self, obj):
product_offer = get_object_or_404(ProductOffer, product=obj)
category_offer = get_object_or_404(CategoryOffer, category=obj.category)
if product_offer.is_active and category_offer.is_active:
if product_offer.product_offer_price() > category_offer.category_offer_price(obj):
return product_offer.product_offer_price()
else:
return category_offer.category_offer_price(obj)
elif product_offer.is_active and not category_offer.is_active:
return product_offer.product_offer_price()
elif category_offer.is_active and not product_offer.is_active:
return category_offer.category_offer_price(obj)
EDIT: As you can see I used the classic if/else in this solution, although since Python 3.10 you can use the Match case statement to substitute these conditions chain.
In case of objects do not exist:
class ProductSerializer(ModelSerializer):
category = CategorySerializer()
price = SerializerMethodField()
class Meta:
model = Products
fields = '__all__'
def get_price(self, obj):
try:
product_offer = ProductOffer.objects.filter(product=obj).first()
category_offer = CategoryOffer.objects.filter(category=obj.category).first()
if not product_offer and not category_offer:
return obj.base_price
elif not category_offer:
return product_offer.product_offer_price()
elif not product_offer:
return category_offer.category_offer_price(obj)
elif category_offer and product_offer:
if category_offer.is_active and not product_offer.is_active:
return category_offer.category_offer_price(obj)
elif product_offer.is_active and not category_offer.is_active:
return product_offer.product_offer_price()
elif category_offer.is_active and product_offer.is_active:
if category_offer.category_offer_price(obj) > product_offer.product_offer_price():
return category_offer.category_offer_price(obj)
else:
return product_offer.product_offer_price()
except:
return obj.base_price
Although, to be honest, if there could be no objects then the is_active field is redundant.
You can override to_representation()
Example:
class ProductSerializer(ModelSerializer):
category = CategorySerializer()
product_offer_price = SerializerMethodField()
category_offer_price = SerializerMethodField()
...
...
def to_representation(self, instance):
data = super().to_representation(instance)
# access required fields like this
product_offer_price = data['product_offer_price']
category_offer_price = data['category_offer_price']
# do calculations here and returning the desired field as `calculated_price`
if category_offer_price > product_offer_price:
data['calculated_price'] = category_offer_price
else:
data['calculated_price'] = product_offer_price
return data
Not sure it s what you want but you could use a field of type SerializerMethodField which allow you to add a computed field that you could call category_offer_higher_price. Its value is computed by a function that return the highest one. See following link : https://www.django-rest-framework.org/api-guide/fields/#serializermethodfield

Django form initial pass a list to one attribute

I met an issue when I want to pass a list of value to one attribute during initial the form.
The whole process of what I am doing is:
1. User defines a number N.
2. I display N text field.
3. User fills in data and I store in the database.
4. User wants to modify the data -> which is the issue I have when. I want to initial the form with current data.
Here is my model.py
class PageComponent(models.Model):
componentName=models.CharField(max_length=50,null=True, verbose_name="Name")
type = models.ForeignKey(Type, on_delete=models.CASCADE)
user = models.ForeignKey(AS_User, on_delete=models.CASCADE, editable=False)
page = models.ForeignKey(CommunityPage, on_delete=models.CASCADE, editable=False)
STATUS = (
('a', 'Activated'),
('d', 'Deactivated'),
)
componentStatus=models.CharField(
max_length=1,
choices=STATUS,
blank=False,
default='d',
help_text='the current status of the page component', editable=False
)
textContent=models.TextField(max_length=10000, help_text="Enter a description for your component", null=True, blank=True)
photoContent=models.ImageField(upload_to=component_directory_path, null=True, blank=True, verbose_name="Photo")
videoContent=models.FileField(upload_to=component_directory_path, null=True, blank=True, verbose_name="Video")
def __str__(self):
return self.componentName
class PageComponent_SeasonalText(models.Model):
pageStextComponent = models.ForeignKey(PageComponent, on_delete=models.CASCADE)
seasonalText = models.CharField(max_length=10001)
Here is my form.py
class SeasonalTextForm(forms.Form):
componentName = forms.CharField(label=_('Enter title'),max_length=40)
def __init__(self, *args, **kwargs):
seasonTexts = kwargs.pop('extra')
super(SeasonalTextForm, self).__init__(*args, **kwargs)
# self.cleaned_data = {}
for i in range(0, seasonTexts):
field_name = 'seasonText_%s' % (i,)
self.fields[field_name] = forms.CharField(widget=forms.Textarea(attrs={'rows':10, 'cols':51}))
#set field label as placeholder for every field
for field in self.fields.values():
field.widget.attrs["placeholder"] = field.label
def clean(self):
seasonTexts = set()
i = 0
field_name = 'seasonText_%s' % (i,)
while self.cleaned_data.get(field_name):
seasonText = self.cleaned_data[field_name]
if seasonText in seasonTexts:
self.add_error(field_name, 'Duplicate')
else:
seasonTexts.add(seasonText)
i += 1
field_name='seasonText_%s' % (i,)
self.cleaned_data["seasonTexts"] = seasonTexts
def save(self):
for seasonalText in self.cleaned_data["seasonTexts"]:
PageComponent_SeasonalText.objects.create(pageStextComponent = PageComponent.pageStextComponent,seasonalText = seasonalText,)
Here is my view.py
def edit_stext(request, page_id, id):
page = get_object_or_404(CommunityPage, pk=page_id)
component = PageComponent.objects.get(id=id)
stext = PageComponent_SeasonalText.objects.filter(pageStextComponent=component)
numOfSeasons = page.numSeasons
if request.method == "POST":
stextEditor = SeasonalTextForm(request.POST, instance=stext, extra=numOfSeasons)
if stextEditor.is_valid():
stextEditor.save()
return HttpResponseRedirect(reverse('page', kwargs={'page_id' : page_id}))
else:
# stext1 = PageComponent_SeasonalText.objects.filter(pageStextComponent=component)
initial = {}
initial['componentName'] = component.componentName
for i in range(0,numOfSeasons):
st = stext[i].seasonalText
print(st)
initial['seasonalText_{}'.format(i)] = st
stextEditor = SeasonalTextForm(initial=initial, extra=numOfSeasons)
return render(request, 'editComponent_stext.html', {'stextEditor': stextEditor})
NB:
at the view.py, I have a print function to print the actual value of the attribute "seasonalText" and it is success. But it seems cannot be passed to the initial when I want to initial the form.
Thanks for all spending time to help me with this issue. Many thanks.
Screenshot for understanding:
print function gets the correct value
initialed form doesn't get the seasonalText value

'QuerySet' object has no attribute ''cantidad_update"

how are you? I have this error when trying to subtract the values ​​in an IF where it is subtracted if the quantity_update is greater than 0. and if it does not subtract only the quantity.
models.py:
class Pedido(models.Model):
especialidad = models.ForeignKey('Especialidad')
articulo = models.ForeignKey('Articulo')
fecha_entrega = models.DateTimeField(auto_now_add=False, null=True, blank=True)
fecha_pedido = models.DateTimeField(auto_now_add=False,null=True, blank=True)
cantidad = models.IntegerField(blank=True, default=0)
estado = models.CharField(max_length=20, blank=True)
cantidad_update = models.IntegerField(blank=True, default=0)
estado_update = models.CharField(max_length=20, blank=True)
class Articulo(models.Model):
cod_experto = models.CharField(max_length=999, primary_key=True, blank=True)
nombre = models.CharField(max_length=999, blank=True)
on_delete=models.CASCADE)
stock = models.IntegerField(blank=True, default=0)
Views.py Query:
def Entregar(request, id_especialidad):
if request.method == 'GET':
especialidad = Especialidad.objects.get(id=id_especialidad)
pedido = Pedido.object.filter(especialidad=especialidad).filter(estado='pendiente')
if pedido.cantidad_update > 0: #Here is the error!
pedido.articulo.stock -= pedido.cantidad_update
else:
pedido.articulo.stock -= pedido.cantidad
pedido.save()
pedido2 = Pedido.objects.filter(especialidad=especialidad).filter(estado='pendiente').update(estado='entregado').update(fecha_entrega=datetime.date.today())
return HttpResponseRedirect('/solicitar/lista_super/%s/' % id_especialidad)
This would be relevant and I do not know that I'm missing, some help please!
Change
pedido = Pedido.object.filter(especialidad=especialidad).filter(estado='pendiente')
` to
pedido = Pedido.object.filter(especialidad=especialidad).filter(estado='pendiente')[0]
# or use for x in y to iterate each item`,
Your error occurs because filter() returns Queryset, not Pedido Object!
But in your case why are you using filter instead of get!
Using pedido = Pedido.object.filter(especialidad=especialidad).filter(estado='pendiente')[0] as long as there is data to retrieve. But when there is no data ? the query fails and the page returns 500 error. Because None queryset will not have 0th element.
Consider using get_object_or_404 since you want to get single object. Use something like which will be fail
def Entregar(request, id_especialidad):
if request.method == 'GET':
especialidad = get_object_or_404(Especialidad, id=id_especialidad)
pedido = get_object_or_404(Pedido, especialidad=especialidad, estado='pendiente')
if pedido.cantidad_update > 0: # Here is the error!
pedido.articulo.stock -= pedido.cantidad_update
else:
pedido.articulo.stock -= pedido.cantidad
pedido.save()
pedido2 = get_object_or_404(Pedido, especialidad=especialidad, estado='pendiente')
pedido2.update(estado='entregado').update(fecha_entrega=datetime.date.today())
return HttpResponseRedirect('/solicitar/lista_super/%s/' % id_especialidad)

Getting TypeError when attempting to migrate database in Django

I'm currently trying to automatically generate an id number and store it as a default value in the database:
class EmployeeProfile(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
def generate_id(self):
first_initial = self.first_name[0].upper()
second_initial = self.last_name[0].upper()
id_number = first_initial + second_initial + str(random.randint(1000000, 9999999))
if not EmployeeProfile.objects.filter(employee_id=id_number).exists():
return id_number
employee_id = models.CharField(unique=True, max_length=11, default=generate_id)
What I'm getting is a "TypeError: generate_id() missing 1 required positional argument: 'self'". I've looked through the Django documentation https://docs.djangoproject.com/en/1.9/ref/models/fields/#default and it says I can use a callable for the default value in the model, which is what I did but I'm getting this type error when I attempt to migrate the database. Any ideas what I'm doing wrong?
I tried some stuff and this seems to migrate well:
class EmployeeProfile(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
def generate_id():
first_initial = 'a'
second_initial = 'b'
id_number = 2
return id_number
employee_id = models.CharField(unique=True, max_length=11, default=generate_id)
So it seems you cannot pass "self" to generate_id().
Can't you add the employee_id later in the view? Thats the way i'd do it. If you do it like this you can edit the values before saving:
if form.is_valid():
instance = form.save(commit=False)
instance.employee_id = <STUFF>
instance.save()
messages.success(request, "Stamp changes saved.")
return HttpResponseRedirect(instance.get_absolute_url())
EDIT: I tried some more stuff and you can try to remove self from generate_id(), then migrate, then add it back in. It seems to work. Even modifying the model afterwards and migrating again was no problem.
Thanks to user thebjorn, I merely had to override the save method instead of trying to call the method.
def save(self):
first_initial = self.first_name[0].upper()
second_initial = self.last_name[0].upper()
id_number = first_initial + second_initial + str(random.randint(1000000, 9999999))
if not EmployeeProfile.objects.filter(employee_id=id_number).exists():
self.employee_id = id_number
super(EmployeeProfile, self).save()

Django Filter with AND

Am having a django query to filter trough a model and print out the condition that meets the search.
Here is the views
if user_search != '' and (start_date != '' and end_date != ''):
items = Order.objects.filter(
Q(client__email__iexact=user_search) , Q(created_on__range=(start_date, end_date))
)
print "items ", items
The django filter is to print email address the user searched for, that falls within the date range.
But the code am having also prints email that wasn't searched for but falls within the date range
Here is the model
class Order(models.Model):
client = models.ForeignKey(User, related_name = "order_user")
order_number = models.CharField(max_length = 12)null=True)
terms_and_conditions = models.BooleanField(default=False)
order_status = models.CharField(max_length = 20, choices = ORDER_STATUS, default = "new")
created_on = models.DateTimeField(auto_now_add = True)
edited_on = models.DateTimeField(auto_now_add = False)
def __unicode__(self):
return self.order_number
Use & for doing AND operations on Q objects.
if user_search != '' and (start_date != '' and end_date != ''):
items = Order.objects.filter(
Q(client__email__iexact=user_search) & Q(created_on__range=(start_date, end_date))
)
print "items ", items

Categories