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
I have 4 models from 4 different tables :
class Profile(models.Model):
player_name = models.CharField(max_length=150)
player_surname=models.CharField(max_length=200)
sport_type=models.CharField(max_length=200)
class Results_2019(models.Model):
player_name = models.CharField(max_length=150)
first_score=models.DecimalField(decimal_places=2)
second_score=models.DecimalField(decimal_places=2)
average_score=models.DecimalField(decimal_places=2)
class Results_2018(models.Model):
player_name = models.CharField(max_length=150)
first_score=models.DecimalField(decimal_places=2)
second_score=models.DecimalField(decimal_places=2)
average_score=models.DecimalField(decimal_places=2)
class Weight(models.Model):
player_name = models.CharField(max_length=150)
year2019=models.DecimalField(decimal_places=2)
year2018=models.DecimalField(decimal_places=2)
I use these models to filter based on meeting certain condition. Foreign key does not work for me ( i tried i do not what is wrong).
ABC = []
for MyResults in [Results_2019, Results_2018 ]:
results_list = MyResults.objects.annotate(increase=F('second_score') /
F('first_score'),total=F('second_score') +
F('first_score',).filter(increase__gt=0.2,total__gt=average_score,)
ABC.extend(results_list.values_list('player_name', flat=True))
DoubleSNames = list(set([x for x in ABC if ABC.count(x) == 2]))
finallist=list(Profile.objects.filter(player_name__in=DoubleSNames).
values_list('player_name', 'player_surname'))
This code returns list of players and their surname who meet the criteria.
However i can't embed Weight class in list and filter based on
score_weight=first_score/Weight.year19
and then filter if score_weight > 30
I tried to embed
weight_list=[Weight.year19,Weight.year18]
How can i use weight_list with MyResults to calculate score_weight=first_score/Weight.year19
How to to do it?
Is that possible at all to do that ?
Additional:
When i asked you this question i minimised formula i put in filter so after i understand code answered i learn and i can solve independently. Which i did the majority, however i get lost as i haven't done that before but want to learn.
However there are 2 formula I can't insert in the code and make it work. I am keep learning and some are confusing.
Questions:
So the code answered to the question in annotate:
total=F('second_score') + F('first_score')
This is from the code.
Formula I want to embed and filter is:
total_growth=total2019/total2018
So total of 2019 divided by total of 2018). In Python there is the list I tried to apply like:
total_growth=list(map(lambda i,w: (i/w) if w else 0, total[0],total[1]))
And check on condition whether total_growth > 0.05
However it does not work and i do not exactly where to put it in the code to make it work?
How to filter by sport_type (class Profile) so sport_type is not in football.
Would appreciate help to my additional queries to close finally my concern over this question.
I wrote my own code, you are right the result is always empty because of this conditions:
total=second+first
score_weight=total/weight19
if increase > 0.2 and total > average and average > 50 and total > 70 and
score_weight > 30 : ABC.append(result.player_name)
score_weight will never be > 30
you can find below my code, when I put score_weight > 1 I can get results:
model.py:
class Profile(models.Model):
player_name = models.CharField(max_length=150)
player_surname = models.CharField(max_length=200)
sport_type = models.CharField(max_length=200)
class Results2019(models.Model):
player_name = models.CharField(max_length=150)
first_score = models.DecimalField(decimal_places=2, max_digits=5, null=True, blank=True,)
second_score = models.DecimalField(decimal_places=2, max_digits=5, null=True, blank=True,)
average_score = models.DecimalField(decimal_places=2, max_digits=5, null=True, blank=True,)
class Results2018(models.Model):
player_name = models.CharField(max_length=150)
first_score = models.DecimalField(decimal_places=2, max_digits=5, null=True, blank=True,)
second_score = models.DecimalField(decimal_places=2, max_digits=5, null=True, blank=True,)
average_score = models.DecimalField(decimal_places=2, max_digits=5, null=True, blank=True,)
class Weight(models.Model):
player_name = models.CharField(max_length=150)
year19 = models.DecimalField(decimal_places=2, max_digits=5, null=True, blank=True,)
year18 = models.DecimalField(decimal_places=2, max_digits=5, null=True, blank=True,)
views.py
def myPageView():
ABC = {}
players = Profile.objects.all().values()
for result in players:
for data in [[Results2019, 'year19'], [Results2018, 'year18']]:
Results = data[0].objects.get(player_name__exact=result['player_name'])
if Results:
wgt = Weight.objects.filter(player_name__exact=result['player_name']).values(data[1]).last()
if wgt:
if float(Results.first_score) > 0.0:
increase19 = float(Results.second_score) / float(Results.first_score)
else:
increase19 = 0
total = float(Results.second_score) + float(Results.first_score)
score_weight = total / float(wgt[data[1]])
if (increase19 > 0.2) and (total > float(Results.average_score)) and \
(float(Results.average_score) > 50) and (total > 70) and (score_weight > 1):
ABC[result['player_name']] = result['player_surname']
else:
pass
else:
pass
else:
pass
print('*************ABC***************', ABC)
finallist = []
for name in ABC.keys():
finallist.append([name, ABC[name]])
print('*************finallist***************', finallist)
A) Possible bugs:
Maybe you forgot to initialize some variables in the loop for Weight. (your intention was not clear to me)
Other possible problem could be combined tabs and spaces. The code is incorrectly indented after you have pasted it to Stackoverflow. Maybe your editor has a different tab size, maybe Python2 interpreted it as valid, but not how you see it in the editor. Try to run python with -t option, to see warnings if the interpreted logic depends on the tab size. The recommended code style for Python is to not use TABs and to fix all indents to multiples of 4 spaces. The best editor setting for Python is to automatically expand all tabs to spaces.
B) optimizations:
very important
finallist simplified from many database requests to one request:
finallist = list(
Profile.objects.filter(player_name__in=DoubleSNames)
.values_list('player_name', 'player_surname')
)
less important optimization
simplify MyResults.objects.all() to a request with less data rows
results_list = MyResults.objects.filter(
averrage__gt=50,
second_score__gt=70 - F(first_score),
average__lt=F(first_score) + F(second_score),
first_score__gt=0,
second_score__gt=0.2 * F(first_score),
)
ABC.extend(results_list.values_list('player_name', flat=True))
It shouldn't be done before the view will be slow, because readability counts and maybe this will be not the bottle neck.
Disadvantages:
The expression for increase with Case() When() functions would be bad readable. Everything is reformulated, but it is still less readable than a filter on plain Python list.
EDIT:
I accept that you forgot to set the primary key and foreign keys that suggested #Houda, how is normal in Django and that it can be too late to allow Django to add indexes to these tables.
If all data from Profile and Weight can fit in the memory then you can easily map it by a dictionary, otherwise you can filter it by individual names as you did originally or to load them to the memory by a subset of players.
from collections import Counter
profile_map = {x.player_name: x for x in Player.objects.all()}
weight_map = {x.player_name: x for x in Weight.objects.all()}
totals_map = {} # like rows: player, columns: year
ABC = []
for MyResults in [[Results_2019, Results_2018 ]:
results_list = (
MyResults.objects
.annotate(
increase=F('second_score') / F('first_score'),
total=F('second_score') + F('first_score')
)
.filter(
increase__gt=0.2,
total__gt=average_score,
# ... possible more filters
)
)
year_str = MyResults._meta.model_name[-4:]
for result in results_list:
player_name = result.player_name
player = profile_map[player_name]
weight = weight_map[player_name]
weight_year = vars(weight)['year' + year_str[-2:]]
score_weight = result.first_score / weight_year
totals_map.setdefault(player_name, {})[year_str] = result.total
if score_weight > 30 and player.sport_type not in ['football']:
ABC.append(player_name)
counter = Counter(ABC)
DoubleSNames = {name for name, count in counter.items() if count == 2}
finallist = []
for player_name in DoubleSNames:
totals = totals_map['player_name']
total2018 = totals.get('2018', 0)
total2019 = totals.get('2019', 0)
if totals2018 > 0 and total2019 / total2018 > 0.05:
player = player_map[player_name]
finallist.append([player.player_name, player.player_surname])
(It is not an advanced question about django-queryset now, but how to simulate a database relation by Python.)
model.py
from django.db import models
class Profile(models.Model):
player_name = models.CharField(max_length=150)
player_surname = models.CharField(max_length=200)
sport_type = models.CharField(max_length=200)
class Results2019(models.Model):
player_name = models.CharField(max_length=150)
first_score = models.DecimalField(decimal_places=2, max_digits=5, null=True, blank=True,)
second_score = models.DecimalField(decimal_places=2, max_digits=5, null=True, blank=True,)
average_score = models.DecimalField(decimal_places=2, max_digits=5, null=True, blank=True,)
increase = models.BooleanField(null=False, blank=False, default=False, editable=False)
total = models.BooleanField(null=False, blank=False, default=False, editable=False)
def save(self, *args, **kwargs):
if self.second_score / self.first_score > 0.2:
self.increase = 1
else:
self.increase = 0
if self.second_score + self.first_score > self.average_score:
self.total = 1
else:
self.total = 0
super().save(*args, **kwargs)
class Results2018(models.Model):
player_name = models.CharField(max_length=150)
first_score = models.DecimalField(decimal_places=2, max_digits=5, null=True, blank=True,)
second_score = models.DecimalField(decimal_places=2, max_digits=5, null=True, blank=True,)
average_score = models.DecimalField(decimal_places=2, max_digits=5, null=True, blank=True,)
increase = models.BooleanField(null=False, blank=False, default=False, editable=False)
total = models.BooleanField(null=False, blank=False, default=False, editable=False)
def save(self, *args, **kwargs):
if self.second_score / self.first_score > 0.2:
self.increase = 1
else:
self.increase = 0
if self.second_score + self.first_score > self.average_score:
self.total = 1
else:
self.total = 0
super().save(*args, **kwargs)
class Weight(models.Model):
player_name = models.CharField(max_length=150)
year19 = models.DecimalField(decimal_places=2, max_digits=5, null=True, blank=True,)
year18 = models.DecimalField(decimal_places=2, max_digits=5, null=True, blank=True,)
views.py
ABC = {}
weight_dict = defaultdict(dict)
player_dict = {}
for player in Profile.objects.values('player_name', 'player_surname'):
player_dict[player['player_name']] = player['player_surname']
for wt in Weight.objects.values():
weight_dict[wt['player_name']] = {'year19': wt['year19'], 'year18': wt['year18']}
for MyResults in [[Results2019, 'year19'], [Results2018, 'year18']]:
results_list = MyResults[0].objects.\
filter(increase__exact=True, total__exact=True).values('player_name', 'first_score')
for t in results_list:
if t['player_name'] in ABC.keys():
pass
elif float(t['first_score']) / float(weight_dict[t['player_name']][MyResults[1]]) > 30:
ABC[t['player_name']] = player_dict[t['player_name']]
finallist = ABC.items()
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
I have this model:
class Sesion(models.Model):
maq = models.CharField(max_length=25)
ini_sesion = models.DateTimeField(auto_now_add=True)
fin_sesion = models.DateTimeField(null=True, blank=True)
cont_ini_a = models.IntegerField(null=True, blank=True)
con_ini_b = models.IntegerField(null=True, blank=True)
con_fin_a = models.IntegerField(null=True, blank=True)
con_fin_b = models.IntegerField(null=True, blank=True)
#staticmethod
def cierre():
instance = Sesion.objects.filter(fin_sesion__isnull=True).latest('ini_sesion')
sesion_abierta = None
try:
sesion_abierta = Sesion.objects.filter(maq=instance.maq).filter(fin_sesion__isnull=True) \
.filter(ini_sesion__lt=instance.ini_sesion).latest('ini_sesion')
except Exception:
print('Ha ocurrido una excepcion!')
if sesion_abierta:
sesion_abierta.con_fin_a = instance.con_fin_a
sesion_abierta.con_fin_b = instance.con_fin_b
sesion_abierta.fin_sesion = instance.ini_sesion
return sesion_abierta.save()
Now the thing is i can't make it work every time a model instance is saved. I works when it is called from python/django shell
>>> Sesion.cierre()
but not when a model instance is saved and it doesn't work on save() override or signals either. Thx in advance.
Well I will answer the question. Here is what worked:
#receiver(post_save, sender=Sesion)
def cierre(*args, **kwargs):
instance = Sesion.objects.filter(fin_sesion__isnull=True).latest('ini_sesion')
sesion_abierta = None
try:
sesion_abierta = Sesion.objects.filter(maq=instance.maq).filter(fin_sesion__isnull=True) \
.filter(ini_sesion__lt=instance.ini_sesion).latest('ini_sesion')
except Exception:
print('Ha ocurrido una excepcion!')
if sesion_abierta:
sesion_abierta.con_fin_a = instance.con_fin_a
sesion_abierta.con_fin_b = instance.con_fin_b
sesion_abierta.fin_sesion = instance.ini_sesion
sesión_abierta.save()
Edit: Note that the "signals" code goes on the same line of indentation as
class Sesion(models.Model):
I have this error, could you help me? You need to subtract the "quantity" value from the "Pedido" - "stock" model of the "Articulo" model, then save the stock result.
in line: articulo.stock -= pedido.cantidad
def Update_stock(request, id_pedido, cod_experto):
if request.method == 'GET':
pedido = Pedido.objects.get(id=id_pedido)
articulo = Articulo.objects.get(pk=cod_experto)
articulo.stock -= pedido.cantidad
articulo.save()
return render(request, 'admindata.html', {'pedido':pedido, 'articulo':articulo})
models.py:
class Pedido(models.Model):
articulo = models.ForeignKey('Articulo')
fecha_pedido = models.DateTimeField(auto_now_add=True,null=True, blank=True)
cantidad = models.IntegerField(blank=True)
def __str__(self):
return '{}'.format(self.especialidad, self.articulo, self.cantidad, self.estado)
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.CharField(max_length=999, blank=True)
The error message means that articulo.stock is inadvertently assigned a str instead of a number.
In the model, stock is defined as a CharField. Probably, it should be some numeric type such as IntegerField().