Reverse Relationship in django 'QuerySet' object has no attribute 'name' - python

I have two models called car and producer. The two models have many to one relation between them.
class Producer(models.Model):
name = models.CharField(max_length=30)
def __str__(self):
return self.name
class Car(models.Model):
name = models.CharField(max_length=20)
producer = models.ForeignKey(Producer, on_delete=models.CASCADE)
def __str__(self):
return self.name here
When i try to query the reverse relationship.
Producer.objects.filter(car__name='Mini')
then it return a queryset object
<QuerySet [<Producer: BMW>]>
when i try to assign the queryset object to a variable and fetch the name field result then it gives error.
obj1 = Producer.objects.filter(car__name='Mini')
In [6]: obj1.name
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-6-5155cb2773b4> in <module>
----> 1 obj1.name
AttributeError: 'QuerySet' object has no attribute 'name'
what could be the reason for this error

When do you use get() Django return an object and you can get the variables of that object, for example obj1.name, but when you use filter, Django return a Queryset, you have to iterate the queryset with a for:
mini_producers = Producer.objects.filter(car__name='Mini')
for producer in mini_producers:
print(producer.name)

Queryset is a list of objects, not a single object.
So you can do:
obj1 = Producer.objects.filter(car__name='Mini').first(). # <- get first
In [6]: obj1.name
or in case you have to handle multiple.
for obj in obj1:
print(obj.name)
# do your logic

Related

Code to display Django (Reverse) related table throws error

I'm quite new to Django and practicing Models section of Django by following its official tutorial. I also created a project of my own and try to apply similar concepts.
This is my models.py;
from django.db import models
class Experience(models. Model):
o01_position = models.CharField(max_length=50)
o02_year_in = models.DateField(null=True)
o03_year_out = models.DateField(null=True)
o04_project = models.CharField(max_length=100)
o05_company = models.CharField(max_length=50)
o06_location = models.CharField(max_length=50)
def __str__(self):
return self.o01_position}
class Prjdesc(models.Model):
o00_key = models.ForeignKey(
Experience, on_delete=models.CASCADE)
o07_p_desc = models.CharField(max_length=250)
def __str__(self):
return self.o07_p_desc
class Jobdesc(models.Model):
o00_key = models.ForeignKey(Experience, on_delete=models.CASCADE)
o08_job_desc = models.CharField(max_length=250)
def __str__(self):
return self.o08_job_desc
Now when I run below command in Python/Django shell it runs as expected with the related data.
>>> x = Experience.objects.get( pk = 2 )
>>> x
<Experience: Head Office Technical Office Manager>
Below two also work as expected:
>>> y = Prjdesc.objects.get( pk = 11 )
>>> y
<Prjdesc: Description 1>
>>> x.prjdesc_set.all()
<QuerySet [<Prjdesc: Description 1>, <Prjdesc: Description 2>]>
However this expression does not return anything although it should return its related record in Experience Class.
>>> y.experience
Traceback (most recent call last):
File "<console>", line 1, in <module>
AttributeError: 'Prjdesc' object has no attribute 'experience'
Could you tell me what I am missing here?
As you mentioned in one of the comments above:
Strangely it returns this; Traceback (most recent call last): File "", line 1, in AttributeError: 'Prjdesc' object has no attribute 'experience'.
You simply need to write c.o00_key not c.experience, you confused with official docs, they give their field name also as experince.
Generally, ForeignKey is created using model name in smallcase while defining field, and the related_name sets to model name as prefix and _set as suffix by default, so it will be prjdesc_set in your case or you can override it by using ForeignKey.related_name in the field.
With your current models use this:
>>> x = Experience.objects.get(pk=2)
>>> x
<Experience: Head Office Technical Office Manager>
>>> c = x.prjdesc_set.create(o07_p_desc='Description 5')
>>> c
<Prjdesc: Description 5>
>>> c.o00_key
>>> c
<Experience: Head Office Technical Office manager>
Note: Also it's better to use f stings in the __str__() method, so in your models.py:
class Experience(models.Model):
...
...
def __str__(self):
return f"{self.o01_position}"
class Prjdesc(models.Model):
...
...
def __str__(self):
return f"{self.o07_p_desc}"
class Jobdesc(models.Model):
...
...
def __str__(self):
return f"{self.o08_job_desc}"
If you pay attention:
c = q.choice_set.create(choice_text='Just hacking again', votes=0)
there is a call through _set. But not at all:
q = Question.objects.get(pk=1)
followed by:
q.choice# which will throw the same error
By using the primary model, you can get the data associated with it from the secondary model. To do this, a special property (object) with the name secondary model_set is created in the primary model by default. In your case, for example:
x = Experience.objects.get(pk=1)
x.prjdesc_set.all()
That is, we get all the values of the secondary model with pk=1 of the primary one (one-to-many access).
If you need to get the value from the primary model from the secondary model, then as already mentioned:
Prjdesc.objects.get(id=1).o00_key.o01_position
In this case, get is used, that is, the value should be one, if more is expected, then filter should be applied.

Django Rest Framework serializing queryset fetchedn with value_list

I'm trying to query a specific column from my table. I've tried doing it with this
team_lenDeserialized = RolesInTeam.objects.values_list('user_id', flat=True).filter(academic_year_id=9).filter(deleted=0)
team_lenDict = RolesInTeamSerializer(team_lenDeserialized, many=True)
team_len = orderedDictToJSON(team_lenDict.data)
After that I run it through a function that converts it to JSON
def orderedDictToJSON(orderedDict):
return json.loads(json.dumps(orderedDict))
then I go and manipulate it further. However if I try to serialize and convert the team_lenDeserialized I get an error that states
AttributeError: Got AttributeError when attempting to get a value for field `user_id` on
serializer RolesInTeamSerializer`.
The serializer field might be named incorrectly and not match any
attribute or key on the `int` instance.
Original exception text was: 'int' object has no attribute 'user_id'.
This is my model for that table
class RolesInTeam(models.Model):
user_id = models.IntegerField()
team_id = models.IntegerField()
role_id = models.IntegerField()
deleted = models.IntegerField()
academic_year_id = models.IntegerField()
class Meta:
managed = False
db_table = 'roles_in_team'
and my serializer
class RolesInTeamSerializer(serializers.ModelSerializer):
class Meta:
model = RolesInTeam
fields = ['id', 'user_id', 'team_id', 'role_id', 'deleted', 'academic_year_id']
I have no clue what's happening or why it's not working.
You can only serialize models instances with a ModelSerializer, and values_list() returns a queryset of tuples, so when you try to use the serializer over the queryset, you get the error.
If you make a regular query (team_lenDeserialized = RolesInTeam.objects.filter(academic_year_id=9).filter(deleted=0)), you would be able to serialize team_lenDeserialized.

'tuple' object has no attribute - Django

I'm trying to save some data to my database, but I keep getting the error: 'tuple' object has no attribute 'view_id I think that somehow I'm getting the object wrongly from my db.
Models.py
class GoogleProperty(models.Model): # Settings for each single site, a user can have many!
user = models.CharField(max_length=200) # Owner of site
google_email = models.EmailField(max_length=200)
profile_id = models.CharField(max_length=200) # Needed to delete users, but should be removed!
property_name = models.CharField(max_length=200, blank=True, null=True)
property_id = models.CharField(max_length=200, blank=True, null=True)
property_url = models.CharField(max_length=200, blank=True, null=True)
view_id = models.CharField(max_length=200)
def __str__(self):
return str(self.property_url)
Views.py
def some_function(requests):
if len(list_of_views)==1: # Save to DB and call it a day
view_name = list_of_views[0]['name']
view_id = list_of_views[0]['id']
print(view_id) # 123823290
dic_views[view_name]=view_id
# Save View to DB
'''
obj, created = GoogleProperty.objects.get_or_create(google_email=current_user, defaults={'view_id': view_id})
if not created:
obj.view_id = view_id
obj.save()
'''
objx = GoogleProperty.objects.get_or_create(google_email=current_user)
print(objx) # (<GoogleProperty: None>, False)
objx.view_id = view_id
objx.save
return HttpResponse(request, '/ga_app/report.html', {'view_id':view_id})
else: # Many Views, ask which one they want to track
Do something
edit added traceback:
File "/my-path/views.py", line 212, in select_view
objx.view_id = view_id
AttributeError: 'tuple' object has no attribute 'view_id'
I've put as side note the results of the print() function.
Also, in some parts of my code I add the defaults={'view_id': view_id} is that really needed? If so why?
P.s. I tried both codes that commented out and the one not commented out.
You had the correct approach commented out, why?
https://docs.djangoproject.com/en/1.11/ref/models/querysets/#get-or-create get_or_create returns a tuple of the form (object, created [boolean]).
What you'd want to do is split out the result of that command:
objx, created = GoogleProperty.objects.get_or_create(google_email=current_user)
Then you can do:
if not created:
objx.view_id = view_id
objx.save()
You seem to have syntax errors. objx is a tuple, tuples are indexed by integers, and also tuples are immutable in python, so this should work.
objx[0].view_id = view_id
objx[0].save()
and defaults are provided to set default attributes incase of object creation. So basically you are setting a default view_id, if the object is created.
Provide the stack trace for the commented out part also.
#Costantin : You are calling to a property of tuple object that no exist so that is why you have getting error ex:
>>> t = ('23','e')
>>> t[1]
'e'
>>> t.r
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'tuple' object has no attribute 'r'

How to print the query of .get queryset in django

How can I know the query when doing a .get queryset in django
I have this model:
class Artist(EsIndexable, models.Model):
name = models.CharField(max_length=50)
birth_date = models.DateField()
And I did this in the shell:
x = Artist.objects.get(name="Eminem")
print x.query
Then I got the error:
AttributeError: 'Artist' object has no attribute 'query'
.get returns an instance, not a queryset.
To see the query that is done, do the same thing but with .filter, which does return a queryset:
queryset = Artist.objects.filter(name="Eminem")
print queryset.query
x = queryset.get()
from django.db import connection
x = Artist.objects.get(name="Eminem")
print connection.queries[-1]

Subclassing django model doesn't carry the Manager

If I have a Django model:
class Person(models.Model):
name = models.CharField(max_length=45)
surname = models.CharField(max_length=45)
objects = PersonManager()
and its manager:
class PersonManager(models.Manager):
def create_person(self, fullname):
name, surname = fullname.split(" ", 1)
return self.create(name=name, surname=surname)
Extending that class:
class Actor(Person):
pass
doesn't have the same manager object, but the default one.
In [5]: Person.objects.create_person
Out[5]: <bound method PersonManager.create_person of <xxx.PersonManager object at 0x10297d190>>
In [6]: Actor.objects.create_person
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-6-468f84e48664> in <module>()
----> 1 Actor.objects.create_person
AttributeError: 'Manager' object has no attribute 'create_person'
Why is that and how can I propagate the manager to all subclasses?
You can read more about this here: https://docs.djangoproject.com/en/dev/topics/db/managers/#custom-managers-and-model-inheritance
Basically managers are not inherited (from ordinary models). To get around this you can manually declare the manager in each model that should use the PersonManager. Or you can make Person an abstract model, that way all subclasses will inherit the PersonManager. Considering that you might want to add Directors, Producers or Technicians this might be the way to go. To do that you add the abstract attribute to Persons metaclass.
class Person(models.Model):
name = models.CharField(max_length=45)
surname = models.CharField(max_length=45)
objects = PersonManager()
class Meta:
abstract = True

Categories