ValueError: Cannot use Queryset for "": Use a Queryset for "" - django

I'm working on a little project using these models here and I'm trying to figure out a way to get a set of all the posts associated with users the currently authenticated user is following.
But I keep getting:
Cannot use QuerySet for "Profile": Use a QuerySet for "User".
class Profile(models.Model):
user = models.OneToOneField(User)
isInstructor = models.BooleanField(default=False)
isTutor = models.BooleanField(default=False)
isStudent = models.BooleanField(default=False)
isAdmin = models.BooleanField(default=False)
following = models.ManyToManyField('self', related_name = "followers", blank=True, symmetrical=False)
profile_image = ImageField(upload_to=get_image_path, blank=True, null=True)
class Post(models.Model):
title = models.CharField(max_length=100)
topic = models.CharField(max_length=50)
description = models.CharField(max_length=1200)
poster = models.ForeignKey(User, related_name="posts")
likes = models.IntegerField(default=0)
created = models.DateTimeField(auto_now_add=True)
tags = models.ManyToManyField(Tag, blank=True, related_name="posts")
def __str__(self):
return self.title
This is what keeps giving me the error.
current_user = Profile.objects.get(user = self.request.user)
Post.objects.filter(poster__in = current_user.following.all())
I searched around an found out that I had to use the __in operator whenever you want to filter by a list of things. But I keep getting the same error. Any help with explaining what the error means and what I can do to get around it would be much appreciated.

Maybe try something like this,
Post.objects.filter(poster__id__in=current_user.following.all().values_list('user_id'))

profile class is different to the user class. Therefore, the Profile instance is different to User's instance.
Instead of use current_user you need to use current_user.user.
You can check the documentation.

This is old, but I do not see a clear explanation of the error yet.
Consider this:
Post.poster is a foreign key to the User model.
current_user is a Profile object, not, as the name would suggest, a User object.
Profile.following is a m2m relation back to Profile, so it represents a Profile queryset.
Thus, when you filter on poster__in=current_user.following.all(), you're actually trying to compare a User with a Profile queryset.
This cannot be done, and Django is telling you exactly that:
Cannot use QuerySet for "Profile": Use a QuerySet for "User".
To fix this, you should provide a User queryset in the filter, e.g. something similar to zaidfazil's answer:
current_user_profile = Profile.objects.get(user=self.request.user)
Post.objects.filter(
poster__in=current_user_profile.following.values('user_id')
)
Or do something like this: https://stackoverflow.com/a/67247647

This does not answer the original post, but may help people who end up here based on the title:
A similar error message can also arise when your lookup refers to a reverse relation using '<fieldname>_set'.
For example, if a Bar model has a foreign key to a Foo model, then Foo will get a default related manager called Foo.bar_set. However, a lookup attempt like foo__bar_set__in=... would yield the following error:
ValueError: Cannot use QuerySet for "Bar": Use a QuerySet for "Foo".
This can be fixed by removing the _set from the lookup, so foo__bar_set__in=... should actually be foo__bar__in=....

Related

how to build query with several manyTomany relationships - Django

I really don't understand all the ways to build the right query.
I have the following models in the code i'm working on. I can't change models.
models/FollowUp:
class FollowUp(BaseModel):
name = models.CharField(max_length=256)
questions = models.ManyToManyField(Question, blank=True, )
models/Survey:
class Survey(BaseModel):
name = models.CharField(max_length=256)
followup = models.ManyToManyField(
FollowUp, blank=True, help_text='questionnaires')
user = models.ManyToManyField(User, blank=True, through='SurveyStatus')
models/SurveyStatus:
class SurveyStatus(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
survey = models.ForeignKey(Survey, on_delete=models.CASCADE)
survey_status = models.CharField(max_length=10,
blank=True,
null=True,
choices=STATUS_SURVEY_CHOICES,
)
models/UserSurvey:
class UserSurvey(BaseModel):
user = models.ForeignKey(User, null=True, blank=True,
on_delete=models.DO_NOTHING)
followups = models.ManyToManyField(FollowUp, blank=True)
surveys = models.ManyToManyField(Survey, blank=True)
questions = models.ManyToManyField(Question, blank=True)
#classmethod
def create(cls, user_id):
user = User.objects.filter(pk=user_id).first()
cu_quest = cls(user=user)
cu_quest.save()
cu_quest._get_all_active_surveys
cu_quest._get_all_followups()
cu_quest._get_all_questions()
return cu_quest
def _get_all_questions(self):
[[self.questions.add(ques) for ques in qstnr.questions.all()]
for qstnr in self.followups.all()]
return
def _get_all_followups(self):
queryset = FollowUp.objects.filter(survey__user=self.user).filter(survey__user__surveystatus_survey_status='active')
# queryset = self._get_all_active_surveys()
[self.followups.add(quest) for quest in queryset]
return
#property
def _get_all_active_surveys(self):
queryset = Survey.objects.filter(user=self.user,
surveystatus__survey_status='active')
[self.surveys.add(quest) for quest in queryset]
return
Now my questions:
my view sends to the create of the UserSurvey model in order to create a questionary.
I need to get all the questions of the followup of the surveys with a survey_status = 'active' for the user (the one who clicks on a button)...
I tried several things:
I wrote the _get_all_active_surveys() function and there I get all the surveys that are with a survey_status = 'active' and then the _get_all_followups() function needs to call it to use the result to build its own one. I have an issue telling me that
a list is not a callable object.
I tried to write directly the right query in _get_all_followups() with
queryset = FollowUp.objects.filter(survey__user=self.user).filter(survey__user__surveystatus_survey_status='active')
but I don't succeed to manage all the M2M relationships. I wrote the query above but issue also
Related Field got invalid lookup: surveystatus_survey_status
i read that a related_name can help to build reverse query but i don't understand why?
it's the first time i see return empty and what it needs to return above. Why this notation?
If you have clear explanations (more than the doc) I will very appreciate.
thanks
Quite a few things to answer here, I've put them into a list:
Your _get_all_active_surveys has the #property decorator but neither of the other two methods do? It isn't actually a property so I would remove it.
You are using a list comprehension to add your queryset objects to the m2m field, this is unnecessary as you don't actually want a list object and can be rewritten as e.g. self.surveys.add(*queryset)
You can comma-separate filter expressions as .filter(expression1, expression2) rather than .filter(expression1).filter(expression2).
You are missing an underscore in surveystatus_survey_status it should be surveystatus__survey_status.
Related name is just another way of reverse-accessing relationships, it doesn't actually change how the relationship exists - by default Django will do something like ModelA.modelb_set.all() - you can do reverse_name="my_model_bs" and then ModelA.my_model_bs.all()

How to define models in django that provides custom values based on pre-selection for a field?

Given the following model that stores the user's wish list for reading books:
class ReadingList(models.Model):
user_id = models.ForeignKey(UserInfo, on_delete=models.DO_NOTHING, null=False, blank=False, default=None, db_column='user_id')
book= models.CharField(max_length=255, blank=False)
creation_time = models.DateTimeField(blank=True)
class Meta:
unique_together = (('user_id', book),)
I want to create a model that helps in tracking the time spent in the reading the book on different days which looks something like this:
class ReadingTracker(models.Model):
user_id = models.ForeignKey(ReadingList, on_delete=models.DO_NOTHING, related_name='user', blank=False, db_column='user_id')
book= models.ForeignKey(ReadingList, on_delete=models.DO_NOTHING, related_name='book-to-read', blank=False, db_column='book')
time = models.DateTimeField(blank=True)
time_spent = models.floatfield()
On the client-side (corresponding to ReadingTracker) for both the fields user_id and book
I see that ReadingList object (1), ReadingList object (2), ... are listed. But, this is not working as expected.
What I want to achieve are the following:
For user_id field I want to see the something like dummy_uid1, dummy_uid2, ... to be listed.
Consider dummy_uid1 wants to read book1 and book2 whereas dummy_uid2 wants to read book1 and book3.
When dummy_uid1 is selected as user_id, I want only book1 and book2 to be listed for selection.
How do I define the model in django rest framework to achieve this?
Any suggestions related to the above would be much appreciated and thank you in advance.
There are two parts to this question:
If you want to see a different value than ReadingList object (1) then you need to define the __str__ value of your model, you can do this like so:
class ReadingList(models.Model):
...
def __str__(self):
return f'{self.user_id}' # return whatever string you want to display
If you want to just display the books for a particular user then you can use a filter() (see the Django documentation):
reading_list = ReadingList.objects.get(...)
ReadingTracker.objects.filter(user_id=reading_list)
However, I would add that you have a user_id on your ReadingList object which does seem to connect to a User model, but your user_id on ReadingTracker is a ForeignKey relation to ReadingList, which is confusing. I would suggest renaming the field or actually making it link to the User model (though this is unnecessary as you can still filter by User through the ReadingList model).

How to I automatically filter out is_deleted records in an associated table in Django?

I am using soft deletes on one of my models in Django, and I am overwriting the default manager to always return active records only, using something like:
class ActiveRecordManager(models.Manager):
def get_queryset(self):
return super().get_queryset().filter(is_deleted=False)
class Tag(models.Model):
is_deleted = models.BooleanField(default=False, db_index=True)
objects = ActiveRecordManager()
class Photo(models.Model):
tag = models.ForeignKey(Tag, on_delete=models.CASCADE, related_name="photos")
objects = ActiveRecordManager()
All works well. However, when I do:
tag = Tag.objects.get(pk=100)
And then I try to get the associated photos:
photos = tag.photos.all()
Then I get photos that are deleted. I only want to return objects that are not deleted (so my regular objects list. I was reading about _base_mangers in Django, which seems to control this, but the documentation recommends against filtering objects out:
If you override the get_queryset() method and filter out any rows,
Django will return incorrect results. Don’t do that. A manager that
filters results in get_queryset() is not appropriate for use as a base
manager.
But what I am not clear about is how I am supposed to filter these results. Any thoughts?
UPDATE:
I was asked to explain how this question is different from this one:
How to use custom manager with related objects?
In this 8 year old question they mention a deprecated method. That deprecated method is superseded by the method I outline below (base_managers) which according to the documentation I should not use. If people think I should use it, can you please elaborate?
why not use custom query methods instead of overriding manager as it may produce problems for example in admin pages?
class ActiveModelQuerySet(models.QuerySet):
def not_active(self, *args, **kwargs):
return self.filter(is_deleted=True, *args, **kwargs)
def active(self, *args, **kwargs):
return self.filter(is_deleted=False, *args, **kwargs)
class Tag(models.Model):
is_deleted = models.BooleanField(default=False, db_index=True)
objects = ActiveModelQuerySet().as_manager()
class Photo(models.Model):
tag = models.ForeignKey(Tag, on_delete=models.CASCADE, related_name="photos")
is_deleted = models.BooleanField(default=False, db_index=True)
objects = ActiveModelQuerySet().as_manager()
you can then filter your models however you want
tag = Tag.objects.active(pk=100)
deleted_tags = Tag.objects.not_active()
photos = tag.photos.active()
also note that you need is_deleted attribute in all your models that have the soft delete functionality like Photo in your case

Django Query Does not exist

I'm been trying to create an app that allows users to follow each other profile since yesterday and today and I haven't been successful so far.
I'm having trouble creating a following function that allows me to retrieve users from a particular user he follows.
Example . If John follows Diana . I want to able to retrieve the user called Diana and use it with my modules.
I'm really sorry if this doesn't make sense . I'm trying my hardest to explain my situation.
class Person(models.Model):
user = models.ForeignKey(User)
name = models.CharField(max_length=100)
image = models.FileField(upload_to="images/",blank=True,null=True)
class Board(models.Model):
user = models.ForeignKey(User)
name = models.CharField(max_length=100)
def __unicode__(self):
return self.name
Most of these solutions gave me no query
This was one of the solutions I tried.
class UserLink(models.Model):
from_user = models.ForeignKey(User , related_name = "following_set")
to_user = models.ForeignKey(User , related_name = "follower_set")
date_added = models.DateTimeField(default = datetime.now)
def __unicode__(self):
return "%s is following %s" % (self.from_user.username,self.to_user.username)
def save(self,**kwargs):
if self.from_user == self.to_user:
raise ValueError("Cannot follow yourself ")
super(UserLink , self).save(**kwargs)
class Meta:
unique_together = (('to_user','from_user'),)
I tried to retrieve the users that a particular user followed and use it against my modules such as Person but it gave me an error No query exist.
def Follow(request,username=""):
if request.method == "POST":
username = request.POST.get('follow',False)
user = User.objects.get(username=username)
UserLink.objects.create(from_user=request.user,to_user=user)
return HttpResponseRedirect(reverse('world:Profile'))
return HttpResponseRedirect(reverse('world:Profile'))
I also tried this following function but it only followed himself and I changed self to User but it didn't allow me to put the person to follow
class UserProfile(models.Model):
user = models.OneToOneField(User)
follows = models.ManyToManyField('self', related_name='followed_by', symmetrical=False)
>>>from pet.models import *
>>>from django.contrib.auth.models import User
>>>user = User.objects.get(username='Peter')
>>>user1 = User.objects.get(username='Sarah')
>>>p = UserProfile.objects.filter(user=user,follows=user1)
>>>Error no field called follows
How can I create a following class that allows retrieve the people that they followed and use it with my modules such as Person?
Can someone help me . Thannk you community!
If I understand correctly, youu are on the right track with the many to many relationship. What you need is to modify your existing Person class to include this information.
Since information about who someone follows or is following is essentially information about that person and so you shouldn't really need to define a new class to implement that functionality.
I would suggest modifying your Person like so.
class Person(models.Model):
user = models.ForeignKey(User)
name = models.CharField(max_length=100)
image = models.FileField(upload_to="images/",blank=True,null=True)
following = models.ManyToManyField('self', related_name='followers', symmetrical=False, blank=True, null=True)
What this line does is makes a many to many relationship between the class Person and its self.
Many to many relationships work a little different to other relationships and I suggest you read the Django documentation https://docs.djangoproject.com/en/dev/topics/db/examples/many_to_many/.
But you should now be able to setup and access the relationship like this.
>>>john = Person.objects.get(name="John")
>>>diana = Person.objects.get(name="Diana")
>>>john.following.add(diana)//setup the many to many relationship
>>>john.save()
>>>john.following.all()
//This should return a queryset of Person objects which john is following.
//eg Diana
>>>diana.followers.all()
//This should return a queryset of Person objects which are following Diana.
//eg. John.
Easy, how awesome is Django!

How do you set the initial value for a ManyToMany field in django?

I am using a ModelForm to create a form, and I have gotten the initial values set for every field in the form except for the one that is a ManyToMany field.
I understand that I need to give it a list, but I can't get it to work. My code in my view right now is:
userProfile = request.user.get_profile()
employer = userProfile.employer
bar_memberships = userProfile.barmembership.all()
profileForm = ProfileForm(
initial = {'employer': employer, 'barmembership' : bar_memberships})
But that doesn't work. Am I missing something here?
Per request in the comments, here's the relevant parts of my model:
# a class where bar memberships are held and handled.
class BarMembership(models.Model):
barMembershipUUID = models.AutoField("a unique ID for each bar membership",
primary_key=True)
barMembership = USStateField("the two letter state abbreviation of a bar membership")
def __unicode__(self):
return self.get_barMembership_display()
class Meta:
verbose_name = "bar membership"
db_table = "BarMembership"
ordering = ["barMembership"]
And the user profile that's being extended:
# a class to extend the User class with the fields we need.
class UserProfile(models.Model):
userProfileUUID = models.AutoField("a unique ID for each user profile",
primary_key=True)
user = models.ForeignKey(User,
verbose_name="the user this model extends",
unique=True)
employer = models.CharField("the user's employer",
max_length=100,
blank=True)
barmembership = models.ManyToManyField(BarMembership,
verbose_name="the bar memberships held by the user",
blank=True,
null=True)
Hope this helps.
OK, I finally figured this out. Good lord, sometimes the solutions are way too easy.
I need to be doing:
profileForm = ProfileForm(instance = userProfile)
I made that change, and now everything works.
Although the answer by mlissner might work in some cases, I do not think it is what you want. The keyword "instance" is meant for updating an existing record.
Referring to your attempt to use the keyword "initial", just change the line to:
bar_memberships = userProfile.barmembership.all().values_list('pk', flat=True)
I have not tested this with your code, but I use something similar in my code and it works.