'tuple' object has no attribute 'user' - python

Thank you so much for your help, i really appreciate it.
I get this error "'tuple' object has no attribute 'user'"
Anybody can tell me if my codes is right.
im trying to make artist followers system.
View.py
#api_view(['GET'])
#permission_classes([IsAuthenticated])
def artist_follow(request, pk):
artist = Artist.objects.get(pk=pk)
current_user = User.objects.get(pk=request.user.id)
# check the current user already followed the artsit, if exist remove it else add
if artist.followers().user.filter(user=current_user).exists(): # This line throw error
artist.followers().user.remove(current_user)
else:
artist.followers().user.add(current_user)
return Response(status=status.HTTP_200_OK)
Model.py
class Artist(models.Model):
name = models.CharField(unique=True, max_length=100)
.....
def __str__(self):
return self.name
def followers(self):
return ArtistFollower.objects.get_or_create(artist=self)
class ArtistFollower(models.Model):
artist = models.OneToOneField(Artist, on_delete=models.CASCADE)
user = models.ManyToManyField(User, related_name='user_artist_followed')
def __str__(self):
return self.artist.name
Traceback
Traceback (most recent call last):
File "/opt/anaconda3/envs/app-ENV/lib/python3.8/site-packages/django/core/handlers/exception.py", line 47, in inner
response = get_response(request)
File "/opt/anaconda3/envs/app-ENV/lib/python3.8/site-packages/django/core/handlers/base.py", line 181, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/opt/anaconda3/envs/app-ENV/lib/python3.8/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
return view_func(*args, **kwargs)
File "/opt/anaconda3/envs/app-ENV/lib/python3.8/site-packages/django/views/generic/base.py", line 70, in view
return self.dispatch(request, *args, **kwargs)
File "/opt/anaconda3/envs/app-ENV/lib/python3.8/site-packages/rest_framework/views.py", line 509, in dispatch
response = self.handle_exception(exc)
File "/opt/anaconda3/envs/app-ENV/lib/python3.8/site-packages/rest_framework/views.py", line 469, in handle_exception
self.raise_uncaught_exception(exc)
File "/opt/anaconda3/envs/app-ENV/lib/python3.8/site-packages/rest_framework/views.py", line 480, in raise_uncaught_exception
raise exc
File "/opt/anaconda3/envs/app-ENV/lib/python3.8/site-packages/rest_framework/views.py", line 506, in dispatch
response = handler(request, *args, **kwargs)
File "/opt/anaconda3/envs/app-ENV/lib/python3.8/site-packages/rest_framework/decorators.py", line 50, in handler
return func(*args, **kwargs)
File "/Users/username/Desktop/Clients/app/source/app/artists/web/views.py", line 44, in artist_follow
if artist.followers().user.filter(user=current_user).exists():
Exception Type: AttributeError at /api/v1/web/artists/1/follow
Exception Value: 'tuple' object has no attribute 'user'

Your .followers() method uses .get_or_create(…) [Django-doc], and thus:
Returns a tuple of (object, created), where object is the retrieved or created object and created is a boolean specifying
whether a new object was created.
You can return the item that is obtained or constructed by subscripting:
class Artist(models.Model):
# …
def followers(self):
return ArtistFollower.objects.get_or_create(artist=self)[0]
or work with a throw away variable:
class Artist(models.Model):
# …
def followers(self):
obj, __ = ArtistFollower.objects.get_or_create(artist=self)
return obj
It however does not seem to make much sense to create a ArtistFollower model. Why not create a ManyToManyField to the User class in Artist model. This will simplify the modeling, and reduce the size of the database.
Such model thus looks like:
from django.conf import settings
class Artist(models.Model):
name = models.CharField(unique=True, max_length=100)
followers = models.ManyToManyField(
settings.AUTH_USER_MODEL,
related_name='following_artists'
)
You thus can then access the followers of an artist with:
my_artist.followers.all() # queryset of User objects
or for a user the artists they are following with:
my_user.following_artists.all()
You can also edit the ManyToManyField at both directions. For more information, see te section on many-to-many relations of the documentation.
Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation.

Related

Why do I get a context must be a dict rather than type

I've been working on a project for a while, and I have a resource called Item.
The item detail view can only be viewed, if the item is from the same company as the user. If not, it should be a 404. This is the code that I have:
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
# To only show items in your company
if (context['item'].company != getCompany(self.request.user)):
return HttpResponseNotFound
return context
getCompany is a function I wrote to check the users company. The company is in a custom Profile model. This function works, I already used it multiple times for other things
Now i expected to have a 404 when going to a item from another company, but instead this error appears:
Internal Server Error: /fr/items/5/
Traceback (most recent call last):
File "/Users/username/Documents/Work/Inventory/inventory-env/lib/python3.9/site-packages/django/core/handlers/exception.py", line 55, in inner
response = get_response(request)
File "/Users/username/Documents/Work/Inventory/inventory-env/lib/python3.9/site-packages/django/core/handlers/base.py", line 220, in _get_response
response = response.render()
File "/Users/username/Documents/Work/Inventory/inventory-env/lib/python3.9/site-packages/django/template/response.py", line 114, in render
self.content = self.rendered_content
File "/Users/username/Documents/Work/Inventory/inventory-env/lib/python3.9/site-packages/django/template/response.py", line 92, in rendered_content
return template.render(context, self._request)
File "/Users/username/Documents/Work/Inventory/inventory-env/lib/python3.9/site-packages/django/template/backends/django.py", line 58, in render
context = make_context(
File "/Users/username/Documents/Work/Inventory/inventory-env/lib/python3.9/site-packages/django/template/context.py", line 278, in make_context
raise TypeError(
TypeError: context must be a dict rather than type.
Edited:
What did I miss?
The get_context_data(...) method supposed to be return a dict object. In your case, you are returning a HttpResponseNotFound which is not correct.
The easy method to raise the 404 error is to use the Http404 class to raise the exception
from django.http import Http404
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
# To only show items in your company
if (context['item'].company != getCompany(self.request.user)):
raise Http404
return context
as Django doc
def get_context_data(self, **kwargs):
is used to
Returns a dictionary representing the template context. The keyword
arguments provided will make up the returned context
and you are trying to return HttpResponseNotFound, that will not work, you should return dict type
Rather raise a PermissionDenied error, then return a Response incorrectly as the context, it gives better meaning, then Django will return the usual 403 page.
from django.core.exceptions import PermissionDenied
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
# To only show items in your company
if (context['item'].company != getCompany(self.request.user)):
raise PermissionDenied("You are not authorized to view the requested company")
return context

Models and ModelForms: needs to have a value for field "id" before this many-to-many relationship can be used

I'm using a Django Model with some many-to-many fields. I'm also using a ModelForm to generate the associated form. It is my understanding that, provided nothing else is overridden, Django should be able to handle many-to-many fields being saved in the ModelForm?
For me, attempting to do this is causing this error:
Internal Server Error: /cameramodel/create/
Traceback (most recent call last):
File "/usr/local/lib/python3.8/site-packages/django/core/handlers/exception.py", line 34, in inner
response = get_response(request)
File "/usr/local/lib/python3.8/site-packages/django/core/handlers/base.py", line 115, in _get_response
response = self.process_exception_by_middleware(e, request)
File "/usr/local/lib/python3.8/site-packages/django/core/handlers/base.py", line 113, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/usr/local/lib/python3.8/site-packages/django/views/generic/base.py", line 71, in view
return self.dispatch(request, *args, **kwargs)
File "/usr/local/lib/python3.8/site-packages/django/contrib/auth/mixins.py", line 52, in dispatch
return super().dispatch(request, *args, **kwargs)
File "/usr/local/lib/python3.8/site-packages/django/views/generic/base.py", line 97, in dispatch
return handler(request, *args, **kwargs)
File "/usr/local/lib/python3.8/site-packages/django/views/generic/edit.py", line 172, in post
return super().post(request, *args, **kwargs)
File "/usr/local/lib/python3.8/site-packages/django/views/generic/edit.py", line 141, in post
if form.is_valid():
File "/usr/local/lib/python3.8/site-packages/django/forms/forms.py", line 185, in is_valid
return self.is_bound and not self.errors
File "/usr/local/lib/python3.8/site-packages/django/forms/forms.py", line 180, in errors
self.full_clean()
File "/usr/local/lib/python3.8/site-packages/django/forms/forms.py", line 383, in full_clean
self._post_clean()
File "/usr/local/lib/python3.8/site-packages/django/forms/models.py", line 403, in _post_clean
self.instance.full_clean(exclude=exclude, validate_unique=False)
File "/usr/local/lib/python3.8/site-packages/django/db/models/base.py", line 1188, in full_clean
self.clean()
File "./schema/models.py", line 1439, in clean
if self.metering_modes is True:
File "/usr/local/lib/python3.8/site-packages/django/db/models/fields/related_descriptors.py", line 527, in __get__
return self.related_manager_cls(instance)
File "/usr/local/lib/python3.8/site-packages/django/db/models/fields/related_descriptors.py", line 838, in __init__
raise ValueError('"%r" needs to have a value for field "%s" before '
ValueError: "<CameraModel: Canon Canonflex R2000>" needs to have a value for field "id" before this many-to-many relationship can be used.
So I checked out the docs and it seems like I need to override the save method in the ModelForm. So I did this:
class CameraModelForm(ModelForm):
class Meta:
model = CameraModel
fields = '__all__'
def save(self, commit=True):
form = super(CameraModelForm, self).save(commit=False)
if commit:
form.save(commit=False)
form.save_m2m()
return form
and instead I'm getting a different error:
TypeError at /cameramodel/create/
save() got an unexpected keyword argument 'commit'
Request Method: POST
Request URL: http://localhost:8000/cameramodel/create/
Django Version: 2.2.12
Exception Type: TypeError
Exception Value:
save() got an unexpected keyword argument 'commit'
Exception Location: /home/jonathan/git/camerahub/schema/models.py in save, line 1397
and models.py:1397 is actually an overridden Model save to add a slug field:
class CameraModel(models.Model):
# other stuff here
def save(self, *args, **kwargs):
if not self.slug:
custom_slugify_unique = UniqueSlugify(
unique_check=cameramodel_check, to_lower=True)
self.slug = custom_slugify_unique("{} {} {}".format(
self.manufacturer.name, self.model, str(self.disambiguation or '')))
super().save(*args, **kwargs)
For what it's worth, I am using many-to-many fields in some other models and I'm not seeing a problem with them. I'm a Python/Django beginner though and I'm pretty stuck on this one because simply following the advice on a million other posts like this one hasn't helped me. Grateful for any advice or code snippets anyone can offer.
If anyone needs more context, the whole project is open source and this branch is available here: https://github.com/djjudas21/camerahub/tree/278c_m2m_error
If you override, the save method, it means you want to make some checks/changes before saving your form. I would instead do:
def save(self):
form = super(CameraModelForm, self).save(commit=False)
if ...: # some condition on form values
form.save() # remove the commit here
form.save_m2m()
return form

Why do I get 'NoneType' object is not callable when trying to delete item with m2m relations?

I'm writing an app to represent some systems : some equipments will contain hardware articles, for exemple a server will contain hard drives.
For CRUD operations i'm using DRF ModelViewSet (nothing overriden).
When I delete an equipment which m2m relation is not set it works fine, but I get an error when it is.
Here is a simplified version of the model scheme.
class Hardware(models.Model):
equipment = models.ManyToManyField('Equipment', blank=True, through='HardwareEQ')
# attributes
class HardwareEQ(models.Model):
hardware = models.ForeignKey(Hardware, on_delete=models.CASCADE)
equipment = models.ForeignKey(Equipment, on_delete=models.CASCADE)
# relation attributes
Below is full traceback.
Traceback:
File "C:\Users\USER\Envs\venv\lib\site-packages\django\core\handlers\exception.py" in inner
34. response = get_response(request)
File "C:\Users\USER\Envs\venv\lib\site-packages\django\core\handlers\base.py" in _get_response
115. response = self.process_exception_by_middleware(e, request)
File "C:\Users\USER\Envs\venv\lib\site-packages\django\core\handlers\base.py" in _get_response
113. response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "C:\Users\USER\Envs\venv\lib\site-packages\django\views\decorators\csrf.py" in wrapped_view
54. return view_func(*args, **kwargs)
File "C:\Users\USER\Envs\venv\lib\site-packages\rest_framework\viewsets.py" in view
103. return self.dispatch(request, *args, **kwargs)
File "C:\Users\USER\Envs\venv\lib\site-packages\rest_framework\views.py" in dispatch
483. response = self.handle_exception(exc)
File "C:\Users\USER\Envs\venv\lib\site-packages\rest_framework\views.py" in handle_exception
443. self.raise_uncaught_exception(exc)
File "C:\Users\USER\Envs\venv\lib\site-packages\rest_framework\views.py" in dispatch
480. response = handler(request, *args, **kwargs)
File "C:\Users\USER\Envs\venv\lib\site-packages\rest_framework\mixins.py" in destroy
93. self.perform_destroy(instance)
File "C:\Users\USER\Envs\venv\lib\site-packages\rest_framework\mixins.py" in perform_destroy
97. instance.delete()
File "C:\Users\USER\Envs\venv\lib\site-packages\django\db\models\base.py" in delete
918. collector.collect([self], keep_parents=keep_parents)
File "C:\Users\USER\Envs\venv\lib\site-packages\django\db\models\deletion.py" in collect
224. field.remote_field.on_delete(self, field, sub_objs, self.using)
File "C:\Users\USER\Envs\venv\lib\site-packages\django\db\models\deletion.py" in CASCADE
16. source_attr=field.name, nullable=field.null)
File "C:\Users\USER\Envs\venv\lib\site-packages\django\db\models\deletion.py" in collect
220. sub_objs = self.related_objects(related, batch)
File "C:\Users\USER\Envs\venv\lib\site-packages\django\db\models\deletion.py" in related_objects
236. **{"%s__in" % related.field.name: objs}
File "C:\Users\USER\Envs\venv\lib\site-packages\django\db\models\query.py" in filter
892. return self._filter_or_exclude(False, *args, **kwargs)
File "C:\Users\USER\Envs\venv\lib\site-packages\django\db\models\query.py" in _filter_or_exclude
910. clone.query.add_q(Q(*args, **kwargs))
File "C:\Users\USER\Envs\venv\lib\site-packages\django\db\models\sql\query.py" in add_q
1290. clause, _ = self._add_q(q_object, self.used_aliases)
File "C:\Users\USER\Envs\venv\lib\site-packages\django\db\models\sql\query.py" in _add_q
1318. split_subq=split_subq, simple_col=simple_col,
File "C:\Users\USER\Envs\venv\lib\site-packages\django\db\models\sql\query.py" in build_filter
1202. value = self.resolve_lookup_value(value, can_reuse, allow_joins, simple_col)
File "C:\Users\USER\Envs\venv\lib\site-packages\django\db\models\sql\query.py" in resolve_lookup_value
1037. sub_value.resolve_expression(self, reuse=can_reuse, allow_joins=allow_joins)
Exception Type: TypeError at /Sycoma2/ensemble/2/
Exception Value: 'NoneType' object is not callable
Edit : add information
To perform the deletion, I call the hardareEN view using ajax request.
The view is a ModelViewSet, like below :
class HardwareENViewSet(viewsets.ModelViewSet):
queryset = HardwareEN.objects.all()
serializer_class = HardwareENSerializer
The serializer looks like this :
class HardwareENSerializer(VerboseSerializer):
class Meta:
model = HardwareEN
fields = '__all__'
def to_representation(self, instance):
"""
Add hardware data
:param instance:
:return:
"""
data = super().to_representation(instance)
for key, value in HardwareSerializer(instance.hardware).data.items():
try:
if not data[key]:
data[key] = value
except KeyError:
data[key] = value
return data
For information, I tried removing the to_representation override, without more success.
The problem was that I overrode the __getattr__ method of HardwareEN model but forgot to add AttributeError for non-existing attributes. Therefore, when fetching the model attributes, the framework didnt get an attribute error when needed.

DRF - 'str' object has no attribute 'pk'

I've got a front-end that sends JSON to the back-end to switch the input of a digital audio stream, with an optional time component to schedule the switch for the future. Here are the components of making this work:
from views.py:
class SwitchStreamView(views.APIView):
"""
A custom endpoint for switching inputs of radio streams
"""
queryset = RadioStream.objects.all()
def post(self, request, format=None):
serializer = serializers.RadioSwitchSerializer(data=request.data, many=True)
serializer.is_valid()
for stream in serializer.data:
if stream.schedule_time is None:
tasks.switch_stream(stream.mnemonic, stream.current_input)
else:
tasks.schedule_switch(stream.mnemonic, stream.current_input, stream.schedule_time)
return HttpResponse('')
from serializers.py:
class RadioSwitchSerializer(serializers.ModelSerializer):
schedule_time = serializers.SerializerMethodField()
def get_schedule_time(self, obj):
return obj.get('schedule_time', None)
class Meta:
model = RadioStream
fields = ('mnemonic', 'current_input', 'schedule_time')
The issue I'm having is that however I try and send a test JSON snippet, I'm getting errors. With this setup, sending
[
{
"mnemonic": "TEST",
"current_input": "TEST"
}
]
results in the error 'str' object has no attribute 'pk', but if I change RadioSwitchSerializer(data=request.data, many=True) to many=False, and send
{
"mnemonic": "TEST",
"current_input": "TEST"
}
I get the response 'str' object has no attribute 'schedule_time' instead.
My plan was to use mnemonic to identify the stream, and current_input to identify which input to switch it to. My questions are; Why is this not working, and should I be using a non-Model serializer for this custom action instead of trying to fit the action into the existing fields of the model?
Edit: Here is the traceback
Internal Server Error: /api/switch/
Traceback (most recent call last):
File "...\lib\site-packages\django\core\handlers\exception.py", line 35, in inner
response = get_response(request)
File "...\lib\site-packages\django\core\handlers\base.py", line 128, in _get_response
response = self.process_exception_by_middleware(e, request)
File "...\lib\site-packages\django\core\handlers\base.py", line 126, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "...\lib\site-packages\django\views\decorators\csrf.py", line 54, in wrapped_view
return view_func(*args, **kwargs)
File "...\lib\site-packages\django\views\generic\base.py", line 69, in view
return self.dispatch(request, *args, **kwargs)
File "...\lib\site-packages\rest_framework\views.py", line 489, in dispatch
response = self.handle_exception(exc)
File "...\lib\site-packages\rest_framework\views.py", line 449, in handle_exception
self.raise_uncaught_exception(exc)
File "...\lib\site-packages\rest_framework\views.py", line 486, in dispatch
response = handler(request, *args, **kwargs)
File "...\radio_switching\views.py", line 45, in post
for stream in serializer.data:
File "...\lib\site-packages\rest_framework\serializers.py", line 738, in data
ret = super(ListSerializer, self).data
File "...\lib\site-packages\rest_framework\serializers.py", line 266, in data
self._data = self.get_initial()
File "...\lib\site-packages\rest_framework\serializers.py", line 573, in get_initial
return self.to_representation(self.initial_data)
File "...\lib\site-packages\rest_framework\serializers.py", line 656, in to_representation
self.child.to_representation(item) for item in iterable
File "...\lib\site-packages\rest_framework\serializers.py", line 656, in <listcomp>
self.child.to_representation(item) for item in iterable
File "...\lib\site-packages\rest_framework\serializers.py", line 500, in to_representation
ret[field.field_name] = field.to_representation(attribute)
File "...\lib\site-packages\rest_framework\relations.py", line 259, in to_representation
return value.pk
AttributeError: 'str' object has no attribute 'pk'
replace your views.py by this snippet,
class SwitchStreamView(views.APIView):
"""
A custom endpoint for switching inputs of radio streams
"""
queryset = RadioStream.objects.all()
def post(self, request, format=None):
serializer = serializers.RadioSwitchSerializer(data=request.data, many=True)
serializer.is_valid()
for stream in serializer.data:
if 'schedule_time' not in stream:
tasks.switch_stream(stream['mnemonic'], stream['current_input'])
else:
tasks.schedule_switch(stream['mnemonic'], stream['current_input'], stream['schedule_time'])
return HttpResponse('')
The reason for the error is, you are trying to access a python dict using dot operator. To access dictionary elements, you can use the familiar square brackets along with the key to obtaining it's value. Here is the official doc
EDIT
AttributeError: 'str' object has no attribute 'pk' this error because, somewhere you trying to access .pk from a str object
Reproducing the error
In [7]: my_str = 'this is just a string'
In [8]: my_str.pk
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-8-5bc39c990550> in <module>()
----> 1 my_str.pk
AttributeError: 'str' object has no attribute 'pk'
There were a few issues, but it turns out the root issue was that serlializer.data was for whatever reason returning a string and not an array of objects. I ended up replacing the ModelSerializer with a regular Serializer here:
class RadioSwitchSerializer(serializers.Serializer):
mnemonic = serializers.CharField(max_length=20)
new_input = serializers.CharField(max_length=20)
schedule_time = serializers.DateTimeField(allow_null=True)
As per Jerin's answer, I also fixed up the lines accessing the stream dictionary to use square brackets rather than the dot operator. These two things have fixed the issue.

django can't serialize non-model on post

New to django and trying to send an list of id's to the server to update some information. I do not want them to be a model class, theres no need for it. What I am trying to do is put them into a serializer to make sure they are "clean". Here is my code:
View Class:
class Update_Cards(APIView):
# This seems necessary or it will throw an error
queryset = Card.objects.all()
def post(self, request, board_id, format=None):
print request.DATA
serializer = CardMoveSerializer(data=request.DATA, many=True)
#this throws an error
print serializer.data
return Response(serializer.data)
Serializer:
class CardMoveSerializer(serializers.Serializer):
card_id = serializers.IntegerField()
lane_id = serializers.IntegerField()
Error I get:
[{u'lane_id': 21, u'card_id': 3}] #this is to show the data is coming across the wire
Internal Server Error: /api/board/2/updateCards
Traceback (most recent call last):
File "/Library/Python/2.7/site-packages/django/core/handlers/base.py", line 115, in get_response
response = callback(request, *callback_args, **callback_kwargs)
File "/Library/Python/2.7/site-packages/django/views/generic/base.py", line 68, in view
return self.dispatch(request, *args, **kwargs)
File "/Library/Python/2.7/site-packages/django/views/decorators/csrf.py", line 77, in wrapped_view
return view_func(*args, **kwargs)
File "/Library/Python/2.7/site-packages/rest_framework/views.py", line 327, in dispatch
response = self.handle_exception(exc)
File "/Library/Python/2.7/site-packages/rest_framework/views.py", line 324, in dispatch
response = handler(request, *args, **kwargs)
File "/Users/crob/Documents/workspace/tlckanban/python/rest/views.py", line 37, in post
print card_moves.data
File "/Library/Python/2.7/site-packages/rest_framework/serializers.py", line 499, in data
self._data = [self.to_native(item) for item in obj]
TypeError: 'NoneType' object is not iterable
What I have done is implemented this with a simplejson parser for now, but I feel like its not the best way to do it:
def update_cards(request, board_id):
json_data = simplejson.loads(request.body)
for moveIndex in range(0, len(json_data)):
#do some work
return JSONResponse(json_data, status=status.HTTP_200_OK)
Thanks for the help in advance!
You need to be accessing 'serializer.is_valid()' before accessing the data. Looks like there's a missing bit of API there - serializer.data should probably raise an expection if its accessed before validation.
Seems you are not using Django's serializers but anyway serialization is not made for validation. Use forms to validate your data then use json as you do to serialize it. Django's serializers are for querysets and models only.

Categories

Resources