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'
Related
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.
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
I have a method of creating clien. one of the body fields of my method is client_users which is not in my client model. He has a foreign key for clients. I overwrite the create method and it is ok. But when I return the method I have this error:
AttributeError: Got AttributeError when attempting to get a value for field `clientes_usuarios` on serializer `ClienteCreateSerializer`.
The serializer field might be named incorrectly and not match any attribute or key on the `Cliente` instance.
Original exception text was: 'Cliente' object has no attribute 'clientes_usuarios'.
My field in my serializer:
class ClienteCreateSerializer(serializers.ModelSerializer):
endereco_residencial = EnderecoSerializer(read_only=False)
endereco_cobranca = EnderecoSerializer(read_only=False,required=False)
contatos = ContatoClienteSerializer(many=True, read_only=False, required=False)
certificados = CertificadoSerializer(many=True, read_only=False, required=False)
email = serializers.EmailField(source='usuario.email')
cnpj = serializers.CharField(max_length=14, min_length=14, source='usuario.cpf_cnpj')
foto = serializers.CharField(required=False)
data_abertura = serializers.DateField(input_formats=settings.DATE_INPUT_FORMATS, required=False, allow_null=True)
clientes_usuarios = UsuarioClienteCreateSerializer(many=True,read_only=False)
I have outher methods like this and they works fine
I have the following two model class in django.
class Rule(models.Model):
name = models.CharField(max_length=50)
user = models.ForeignKey(User, related_name='rules', null=True, blank=True)
threshold = models.CharField(max_length=50, null=True, blank=True)
alert_value = models.CharField(max_length=50, null=True, blank=True)
is_internal = models.BooleanField(default=False)
def __unicode__(self):
return self.name
def to_json(self):
return {
'name': self.name,
'threshold': self.threshold,
'alert_value': self.alert_value
}
class Module(models.Model):
name = models.CharField(max_length=50)
description = models.TextField(null=True, blank=True)
is_internal = models.BooleanField(default=False)
rules = models.ManyToManyField(Rule)
def to_json(self):
return {
'name': self.name,
'description': self.description,
'rules': [r.to_json() for r in self.rules.all()]
}
def __unicode__(self):
return self.name
Now I have the following code to save a Module object which implicitly contains a rules object in my view.py
def create_module(request):
if request.method == 'POST':
module_name = request.POST.get('name')
module_description = request.POST.get('description')
rule_ids = request.POST.getlist('rule_id')
rules = None
for rule_id in rule_ids:
try:
rules = models.Rule.objects.filter(pk__in=rule_id)
except models.Rule.DoesNotExist:
pass
module = models.Module(name=module_name,
description=module_description,
rules=rules)
module.save()
I get the rules correctly here but when save gets called I get an error
Exception Type: TypeError at /modules/create/
Exception Value: 'rules' is an invalid keyword argument for this function
How to overcome this when I want to save an object graph.
rules is not really a field on the model, it's an entry in a linking table - so it can't be saved until the Module entry exists. Also note that your loop is such that it will never consist of more than one Rules object, because you overwrite the rules variable each time. Instead you should simply get all the Rules and add them in one go.
module = models.Module(name=module_name,
description=module_description)
module.save()
rules = models.Rule.objects.filter(pk__in=rule_ids)
module.rules = rules
There's no need to save again after that: assigning to a related queryset does the database operation automatically. Also note that filter will not raise a DoesNotExist exception: if there is no matching rule, then there simply won't be an element in the resulting queryset.
you are overriding the rules queryset inside try and filter() doesnot raise DoesNotExist exception btw..
try this:
module = models.Module(name=module_name,description=module_description)
module.save()
#first save 'module' and add 'rules' from filter()-result
rules = models.Rule.objects.filter(pk__in=rule_ids)
module.rules = rules
module.save()
more about how to save m2m in django
I used below code to import csv file to django model containing manytomanyfield Release.metamodules
>>> from app.models import Metamodule,Release
>>> reldata = csv.reader(open('/root/Django-1.6.5/django/bin/dashboard/release.csv'),delimiter=',')
for row in reldata:
q = Release(number = row[0],
notes= row[1],
changes = row[2],
metamodules = Metamodule.objects.filter(name = row[3]))
try:
q.save()
except:
# if the're a problem anywhere, you wanna know about it
print "there was a problem with line"
Error:
Traceback (most recent call last):
File "<console>", line 5, in <module>
File "/usr/local/lib/python2.7/site-packages/django/db/models/base.py", line 416, in __init__
raise TypeError("'%s' is an invalid keyword argument for this function" % list(kwargs)[0])
TypeError: 'metamodules' is an invalid keyword argument for this function
As the field is ManyToManyField i used objects.fileter to get multiple records. But it is returning error.Please help me to fix this issue
models.py:
class Metamodule(models.Model):
name = models.CharField(max_length=50)
version = models.IntegerField(default=0)
modulename = models.ForeignKey(Module)
createdate = models.DateField(auto_now=True, null=True)
createdby = models.CharField(max_length=50)
def __unicode__(self):
return unicode(self.name)
class Release(models.Model):
number = models.IntegerField(default=0)
notes = models.CharField(max_length=50)
changes = models.CharField(max_length=50)
metamodules = models.ManyToManyField(Metamodule)
def __unicode__(self):
return unicode(self.number)
You can't create your Release object like that. You cannot create m2m relations from unsaved objects. See here
Try something like this :
for row in reldata:
q = Release(number=row[0], notes=row[1], changes=row[2])
# You have to save the object before adding the m2m relations
q.save()
metamodules = Metamodule.objects.filter(name=row[3])
for metamodule in metamodules:
q.metamodules.add(metamodule)
There is probably a better way to do the for loop but this is what you want to achieve.