Django-모델 객체를 업데이트하려고 할 때 ValueError

Sep 07 2020

나는 수업을 위해 Django 프로그램에서 일하고 있습니다. 오류가 외래 키 할당과 관련이 있다는 것을 알고 있지만 논리의 결함이 어디에 있는지 이해할 수 없습니다.

다음은 두 가지 관련 모델입니다.

    class listing(models.Model):    
        title = models.CharField(max_length=100)
        description = models.TextField()
        url = models.URLField(default="", null=True, max_length=100)
        category = models.CharField(default="", max_length=50)
        user_name = models.CharField(max_length=100)
        date = models.DateTimeField(auto_now_add=True)
        is_active = models.BooleanField(default=True)
        min_bid = models.DecimalField(max_digits=8, decimal_places=2)


    class watchlist(models.Model):
        item_id = models.IntegerField(null=False)
        user_id = models.IntegerField(null=False)
        
        #item_id = models.ForeignKey("auctions.listing", on_delete=models.CASCADE, related_name="item_watchlist")
        #user_id = models.ForeignKey("auctions.User", on_delete=models.CASCADE, related_name="user_watchlist")

의 마지막 두 줄 watchlist Class은 주석 처리되어 코드가 작동 할 수 있습니다. 그러나 원래 의도 한대로이 작업을 수행하는 방법을 이해하고 싶습니다. 다음과 같습니다. (아래 코드는 객체가 섹션을 만들 때 실패합니다. ValueError, cannot assign <value>: item_id must be an instance of listings.)

    @login_required
    def item_listing(request, id):
        itemID = id
    
        # GET call coming in from clicking a title link
        if request.method == "GET":
            item = listing.objects.filter(id=id)
            
            # Check if the item is on the user's watchlist
            if watchlist.objects.filter(item_id=id, user_id=request.user.id).exists():
                watch = True
            else:
                watch = False
    
            return render(request, "auctions/ItemPage.html", {
                "item": item,
                "name": item[0].title,
                "url": item[0].url,
                "description": item[0].description,
                "user_name": item[0].user_name,
                "price": item[0].min_bid,
                "category": item[0].category,
                "watch": watch
            })
    
        # POST call coming in from clicking the watchlist button
        if request.method == "POST":
            
            q = request.POST.get('wl')
            
            # Remove from watchlist. Delete entry in database.
            if q == "Remove from Watchlist":
                watchlist.objects.filter(item_id=id, user_id=request.user.id).delete()
    
            # Add to watchliset. Create entry.
            else:
                watchlist.objects.create (
                    item_id=id, 
                    user_id=request.user.id
                )
    
        # Redirect back to thet page
        pathname = "/" + str(itemID)
        return redirect(pathname)

내 가정은 감시 목록 모델 에서 외래 키를 만들면 선택 항목이 목록 PK 로 제한된다는 것 입니다. 개체 삭제는 문제가되지 않았으며 정상적으로 작동했습니다. 예를 들어 Item_id가 7 인 개체를 만들면 목록을 쿼리 할 수 ​​있고 실제로 Id가 7 인 경우에도 관심 목록에 추가하지 못했습니다.

listing.objects.all()
<QuerySet [<listing: Japanese Tea pot>, <listing: Kindle paperwhite>]>
>>> listing.objects.filter(id=7)
<QuerySet [<listing: Japanese Tea pot>]>

그래서 나는 ForiegnKey에 대한 나의 이해와 사용에 결함이 있다고 생각합니다. 이 작업을 올바르게 수행하려면 어떻게해야합니까?

또한 내 서식이 꺼져 있으면 죄송합니다. 여기에 처음 게시합니다.

답변

NicoGriffioen Sep 07 2020 at 17:28

나는 이것이 매우 흔한 실수라고 생각합니다. ForeignKey필드 를 만들 때 실제 데이터베이스 외래 키 관계에서 추상화 역할을합니다. 이것은 (귀하의 경우) 호출하면을 watchlist.item_id반환하지 id않고 실제 listing객체를 반환 한다는 것을 의미 합니다. 객체를 생성 할 때도 마찬가지입니다.

ID의 정수 값 대신 실제 항목으로 관심 목록을 만듭니다.

 watchlist.objects.create (
                    item_id=item, 
                    user_id=request.user.id
                )

모델의 필터 메서드에 인스턴스 대신 키를 전달하는 것이 작동하는지 확실하지 않지만 실제 객체도 거기에 전달하는 것이 좋습니다.

watchlist.objects.filter(item_id=item, user_id=request.user)

이것은 약간 이상해 보입니다. 외래 키를 item_id로 언급하는 데 익숙 할 수 있지만 실제 관계를 따라 외래 키의 이름을 지정하는 것이 가장 좋습니다. 그래서이 경우 당신은 변경해야 item_idwatchlist단지에 클래스 item.

또한 Django 클래스는 대문자로 작성해야하므로 클래스는 다음과 같아야합니다.

class Listing(models.Model):    
        ...

class WatchList(models.Model):
    item = models.ForeignKey("auctions.listing", on_delete=models.CASCADE, related_name="item_watchlist")
    user = models.ForeignKey("auctions.User", on_delete=models.CASCADE, related_name="user_watchlist")

물론 코드를 다음과 같이 변경해야합니다.

 WatchList.objects.create (
                    item=item, 
                    user=request.user.id
                )

과:

WatchList.objects.filter(item=item, user=request.user)