I am trying to compare the PK in the URL with the request.user.id so that no one can view other's profile. This might not be the conventional way to do it, but I'd still like to know what is wrong with my code. I'm a new learner so bear with me.
views.py
class UserDetail(DetailView):
queryset = Profile.objects.all()
template_name = 'details.html'
def get_queryset(self):
if self.request.user.id != self.kwargs['pk']:
queryset = Profile.objects.first()
return queryset
else:
return self.queryset
models.py
class Profile(AbstractUser):
type = models.CharField(max_length=50)
urls.py
url(r'^details/(?P<pk>\d+)/$', login_required(views.UserDetail.as_view())),
When I go to the URL:
ERROR
Exception Type: AttributeError
Exception Value: 'Profile' object has no attribute 'filter'
A Profile instance is not a queryset.
You shouldn't be overriding get_queryset, you should be overriding get_object, which returns the specific object you want to display.
Related
I am trying to add some annotation in authenticated User using rest-auth
Here is my code in serializers.py
class CustomUserSerializer(UserDetailsSerializer):
test = serializers.IntegerField()
class Meta:
model=User
fields='__all__'
And here is my code in views.py
class CustomUserView(UserDetailsView):
queryset= User.objects.annotate(test=Sum('logs__work_hours'))
serializer_class = CustomUserSerializer
but I am having this error after running the system
**
Got AttributeError when attempting to get a value for field test on
serializer CustomUserSerializer. The serializer field might be named
incorrectly and not match any attribute or key on the User instance.
Original exception text was: 'User' object has no attribute 'test'.
**
In this context, queryset is ignored.
Why? In your program, you're subclassing UserDetailsView from django-rest-auth. That implements get_object() like so:
def get_object(self):
return self.request.user
With no reference to the queryset variable.
You need to override get_object() in CustomUserView, copying the above implementation, and setting a test attribute on the user.
def get_object(self):
user = self.request.user
user.test = ... # put query to get value of test here
return user
I am learning class based views in Django. I was reading the Django documentation and read about queryset attribute and the get_queryset() method. When googled them I came across this answer.
I tried to replicate the result using my code:
class IndexView(generic.ListView):
template_name = 'polls/index.html'
context_object_name = 'latest_question_list'
def get_queryset(self):
return Question.objects.order_by('-pub_date')[:2]
class IndexView2(generic.ListView):
template_name = 'polls/index2.html'
context_object_name = 'latest_question_list2'
queryset = Question.objects.all()
In answer it is mentioned that when you set queryset, the queryset is created only once, when you start your server. On the other hand, the get_queryset method is called for every request.
But I was able to insert questions in database and they were available in the page index2.html without restarting, I was able to change the database and changes were reflected on the page index2.html after refreshing the page.
I further googled and found this link. In the DRF website, it is mentioned that queryset will get evaluated once, and those results will be cached for all subsequent requests.
Can you point where I am going wrong ? What link I am missing ?
A QuerySet is evaluated once, but the default implementation of get_queryset, will use queryset.all(), thus each time constructing a new queryset that will force reevaluation.
Indeed, the implementation of the .get_queryset(…) method [GitHub] works with:
def get_queryset(self):
if self.queryset is not None:
queryset = self.queryset
if isinstance(queryset, QuerySet):
queryset = queryset.all()
elif self.model is not None:
queryset = self.model._default_manager.all()
else:
raise ImproperlyConfigured(
"%(cls)s is missing a QuerySet. Define "
"%(cls)s.model, %(cls)s.queryset, or override "
"%(cls)s.get_queryset()." % {
'cls': self.__class__.__name__
}
)
ordering = self.get_ordering()
if ordering:
if isinstance(ordering, str):
ordering = (ordering,)
queryset = queryset.order_by(*ordering)
return queryset
THis thus means that we each time make a new "copy" of the QuerySet that will be evaluated. In case the queryset is not specified, it will look for the model attribute, and work with the _default_manager for that model.
If you specified an ordering attribute, than that means it will also order the queryset.
Django tells that the object with given slug could not be found (i.e. 404 code). Though queryset returned isn't empty
class PollDetailView(RetrieveAPIView):
serializer_class = PollSerializer
def get_queryset(self):
slug = self.kwargs['pk']
print(Poll.objects.filter(slug=slug)) # Prints '<QuerySet [<Poll: ddd>]>' reaching '/api/poll/ddd/' url
return Poll.objects.filter(slug=slug) # 404 Not Found
add look_up field in your PollDetailView
look_up = 'slug'
and in your urls.py
change PollDetailView url to
url(r'^api/polls/(?P<slug>[\w-]+)/$', views.PollDetail.as_view(),name='poll-detail'),
When using class-based generic views in Django, having a queryset attribute means to "restrict" the collection of object the view will operate on, right?
If queryset is provided, that queryset will be used as the source of objects. (Django's get_object())
Model:
from django.db import models
class Person(models.Model):
full_name = models.CharField(max_length=30)
is_active = False
View:
from django.views.generic import DetailView
from books.models import Person
class PersonDetail(DetailView):
queryset = Person.objects.filter(is_active=True)
The queryset above makes sure to only consider objects with is_active=true.
But how does this works internally?
For example: Does Django appends a SQL condition AND is_active=TRUE to every query in the view?
Ok that last example seems pretty stupid but I hope you get the idea of my question. Thank you.
Yes, this is exactly what happens. Your queryset is used as the base queryset by the view's get_object method. It then applies an additional filter to get a specific object (e.g., by ID):
queryset = queryset.filter(pk=pk)
Of course, the view needs a single object, not a queryset, so it then does:
obj = queryset.get()
Which will either return a single object, or a DoesNotExist or MultipleObjectsReturned exception. DoesNotExist results in a 404. MultipleObjectsReturned is unhandled and will propagate to your code.
I need to group and count events by day in the django admin.
Here's my current admin queryset:
class TransactionLogAdmin(ExportMixin, OrganizationRestrictedAdmin):
list_display = ['get_type_count', 'get_count']
def get_queryset(self, request):
return TransactionLog.objects.all().extra(
select={'day': 'date( date_created )'}).values('datetime')
But I'm getting the following error:
'dict' object has no attribute '_meta'
This is the problem
return TransactionLog.objects.all().extra(
select={'day': 'date( date_created )'}).values('datetime')
you have get_queryset method in the admin. As the name suggests, that method is expected to return a queryset. But you are returning a dictionary here. Remove the call to values()
When over riding get_queryset, it's always a good idea to call the method in the superclass and make modifications to it instead of making a new queryset of your own.