Home > front end >  Manager isn't accessible via WatchList instances How do I fix this error?
Manager isn't accessible via WatchList instances How do I fix this error?

Time:06-06

I am trying to create an e-commerce site (CS50 Project 2) through Django and have a Django view with multiple forms. In this view I am trying to use a Boolean Field in a Django form to enable the user to add a listing to his watchlist, both of which are models. While trying to do that, I am receiving the above error.

part of the views.py

def listing(request, id):
    #gets listing
    listing = Listings.objects.get(id=id)
    watchlist_form = WatchListForm()
    if request.method == "POST":
        watchlist_form = WatchListForm(request.POST)
        if watchlist_form.is_valid():
            watchlist = watchlist_form.save(commit=False)
            watchlist.user = request.user
            watchlist.add_to_watchlist = True
            new_watchlist_listing = watchlist.objects.listings.add(listing) 
            return render(request, "auctions/listing.html",{
                "auction_listing": listing,
                "watchlistForm": watchlist_form
            })
        else:
            return render(request, "auctions/listing.html",{
                "auction_listing": listing,
                "form": comment_form,
                "comments": comment_obj,
                "bidForm": bid_form,
                "bids": bid_obj,
                "watchlistForm": watchlist_form
            })
    return render(request, "auctions/listing.html",{
        "auction_listing": listing,
        "form": comment_form,
        "comments": comment_obj,
        "bidForm": bid_form,
        "bids": bid_obj,
        "watchlistForm": watchlist_form
    })

models.py

class Listings(models.Model):
    CATEGORY = [
    ("Miscellaneous", "Miscellaneous"),
    ("Movies and Television", "Movies and Television"),
    ("Sports", "Sports"),
    ("Arts and Crafts", "Arts and Crafts"),
    ("Clothing", "Clothing"),
    ("Books", "Books"),
]
    title = models.CharField(max_length=64)
    description = models.CharField(max_length=500)
    bid = models.DecimalField(max_digits=1000000000000, decimal_places=2)
    image = models.URLField(null=True, blank=True)
    category = models.CharField(max_length=64, choices=CATEGORY, default=None)
    user = models.ForeignKey(User, on_delete=models.CASCADE, default="")


class WatchList(models.Model):
    listings = models.ManyToManyField(Listings)
    user = models.ForeignKey(User, on_delete=models.CASCADE, default="")
    add_to_watchlist = models.BooleanField(default=False)

error message

raise AttributeError("Manager isn't accessible via %s instances" % cls.__name__)
AttributeError: Manager isn't accessible via WatchList instances

This error is happening because of this line: new_watchlist_listing = watchlist.objects.listings.add(listing).

CodePudding user response:

You add elements with modelobject.manytomanyfield.add(), so without the .objects part. Your view should thus look like:

from django.contrib.auth.decorators import login_required
from django.shortcuts import get_object_or_404, redirect

@login_required
def listing(request, id):
    listing = get_object_or_404(Listings.objects, pk=id)
    watchlist_form = WatchListForm()
    if request.method == "POST":
        watchlist_form = WatchListForm(request.POST)
        if watchlist_form.is_valid():
            watchlist_form.instance.user = request.user
            watchlist_form.instance.add_to_watchlist = True
            watchlist = watchlist_form.save()
            watchlist.listings.add(listing)
            return redirect('name-of-the-view')
    return render(request, 'auctions/listing.html',{
        'auction_listing': listing,
        'form': comment_form,
        'comments': comment_obj,
        'bidForm': bid_form,
        'bids': bid_obj,
        'watchlistForm': watchlist_form
    })

Note: It is often better to use get_object_or_404(…) [Django-doc], then to use .get(…) [Django-doc] directly. In case the object does not exists, for example because the user altered the URL themselves, the get_object_or_404(…) will result in returning a HTTP 404 Not Found response, whereas using .get(…) will result in a HTTP 500 Server Error.


Note: In case of a successful POST request, you should make a redirect [Django-doc] to implement the Post/Redirect/Get pattern [wiki]. This avoids that you make the same POST request when the user refreshes the browser.


Note: You can limit views to a view to authenticated users with the @login_required decorator [Django-doc].


Note: Usually it is better not to work with commit=False when saving the form with the .save(…) method [Django-doc]: this will revent saving many-to-many relations since these can only be saved if the item is committed. Usually it is better to alter the .instance wrapped in the form. For more information, see my article[Django-antippaterns] on this.

  • Related