1

I am getting an object is not callable error but I do not know why. My model is as follows.

class PetDetailView(LoginRequiredMixin, generic.DetailView):
    model = Pet

    @property
    def get_queryset(self):
        pet_owner = PetOwner.objects.get(user=self.request.user)
        pet = pet_owner.pet_set.get(pk=self.kwargs["pk"])
        queryset = pet
        return queryset

I did something very similar to return a list of pets given the current user in a different class with a ListView and when returning pets everything works fine.

This is a DetailView though and I am only returning just one thing. I want to only return the pet of the user that is currently logged in and not any pet based on the primary key. Because of this, I am overriding the get_queryset method to ensure I do not have access to any other items that do not pertain to the currently logged-in user.

I printed to the console what pet is and I get Leo instead of <Pet:Leo>. I think this might be the problem but if it is I'm not sure why it's happening when in my python shell it works as I expect it.

just incase here are my models...

class PetOwner(models.Model):
    """Model representing a pet owner."""

    user = models.OneToOneField(User, on_delete=models.CASCADE)
    first_name = models.CharField(max_length=50, help_text="Enter owner's first name")
    last_name = models.CharField(max_length=50, help_text="Enter owner's last name")
    email = models.EmailField(
        max_length=50, blank=True, null=True, unique=True, help_text="Enter owner's email"
    )
    phone_number = models.CharField(
        max_length=15, blank=True, null=True, unique=True, help_text="Enter owner's phone number"
    )
    address = models.ForeignKey(
        "Address", on_delete=models.SET_NULL, null=True, blank=True
    )

    class Meta:
        """Controls default ordering of records when querying the Model type."""

        ordering = ["first_name", "last_name"]

    def __str__(self):
        """String for representing the Model object."""
        return self.first_name

    def get_absolute_url(self):
        """Returns the url to access a detail record of this pet owner."""
        return reverse("petowner_detail", args=[str(self.id)])


class Pet(models.Model):
    """Model representing a pet."""

    first_name = models.CharField(max_length=50, help_text="Enter pet's first name")
    last_name = models.CharField(max_length=50, help_text="Enter pet's last name")
    breeds = models.ManyToManyField("Breed", help_text="Select a breed for this pet")
    weight = models.DecimalField(
        max_digits=5, decimal_places=2, help_text="Enter pet's weight"
    )
    date_of_birth = models.DateField(null=True, blank=True)
    date_of_death = models.DateField("Died", null=True, blank=True)
    owners = models.ManyToManyField(PetOwner, help_text="Select an owner for this pet")
    address = models.ForeignKey(
        "Address", on_delete=models.SET_NULL, null=True, blank=True
    )

    class Meta:
        """Controls the default ordering of records when querying the Model type."""

        ordering = ["last_name", "first_name"]

    def __str__(self):
        """String for representing the Model object."""
        return self.first_name

    def get_absolute_url(self):
        """Returns the url to access a detail record for this pet."""
        return reverse("pet_detail", args=[str(self.id)])

    def display_owner(self):
        """Create a string for the PetOwner. This is required to display owner in Admin."""
        return ", ".join(owner.first_name for owner in self.owners.all()[:3])

    def display_breed(self):
        """Create a string for the Breed. This is required to display breed in Admin."""
        return ", ".join(breed.name for breed in self.breeds.all()[:3])

    display_owner.short_description = "Parent"

1 Answers1

0

As per the Django docs,

get_queryset() : Returns the queryset that will be used to retrieve the object that this view will display. By default, get_queryset() returns the value of the queryset attribute if it is set, otherwise it constructs a QuerySet by calling the all() method on the model attribute’s default manager.

You are using pet_owner.pet_set.get(pk=self.kwargs["pk"]), the difference between get and filter is that filter returns a queryset object, whereas get returns the required object. You need to use filter instead of get to make this work.

pet_owner.pet_set.filter(pk=self.kwargs["pk"]) this should work if there is no other issue.

To make this work, just do this.

# remove property decorator and replace second get with filter.
def get_queryset(self):
    pet_owner = PetOwner.objects.get(user=self.request.user)
    pet = pet_owner.pet_set.filter(pk=self.kwargs["pk"])
    queryset = pet
    return queryset

The error Pet object is not callable is because of the property decorator, How does the @property decorator work in Python?

Kaushal Sharma
  • 1,770
  • 13
  • 16
  • I actually did try this but get a `'User' object is not iterable`. My `PetOwner` has a one-to-one field with the built in `User` model from Django. I checked my view and I'm not using anything in there that will cause this issue so it's coming from this view. – The silent one Nov 10 '21 at 07:17
  • I updated my post with my models so that this can be seen more clearly – The silent one Nov 10 '21 at 07:21
  • @Thesilentone Why are you using `@property` with the `get_queryset` method? – Kaushal Sharma Nov 10 '21 at 08:12
  • I read somewhere I can use that to get the params from the request. I'm new to Django so a lot of these things are new to me. – The silent one Nov 10 '21 at 17:17
  • @Thesilentone https://stackoverflow.com/questions/17330160/how-does-the-property-decorator-work-in-python – Kaushal Sharma Nov 11 '21 at 06:23
  • You don't need `property` decorator here. – Kaushal Sharma Nov 11 '21 at 06:23
  • I appreciate the help with that, I really do because it helps me become a better developer. I did change that earlier today, but it still doesn't solve my current issue. Not sure what else can be wrong because you did say it should work if there is no other issue but the only code I believe this depends on is what I pasted in the post. – The silent one Nov 11 '21 at 06:30
  • I just ran this whole project on my local system. I just checked it is working. I have updated my answer. – Kaushal Sharma Nov 11 '21 at 07:38
  • please upvote and accept this answer if it solved your issue. – Kaushal Sharma Nov 11 '21 at 07:43
  • 1
    I just tried it again even though I did before it must not have worked for some weird reason. It now works when I removed the `@property`. Thanks for the help! – The silent one Nov 11 '21 at 07:50
  • 1
    I can't upvote because I'm really new to stackoverflow it won't let me – The silent one Nov 11 '21 at 07:51