Django - ValueError ketika mencoba memperbarui objek model
Saya sedang mengerjakan program Django untuk sebuah kelas. Saya tahu kesalahan itu berkaitan dengan penugasan kunci asing tetapi saya tidak dapat memahami di mana kekurangan saya dalam logika.
Berikut dua model terkait:
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")
Dua baris terakhir di watchlist Classberi komentar, memungkinkan kode untuk bekerja. Namun, saya ingin memahami cara membuat ini berfungsi seperti yang saya inginkan. Yaitu sebagai berikut: (kode di bawah gagal pada objek membuat bagian, dengan a 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)
Asumsi saya adalah bahwa membuat kunci asing pada model daftar pantauan akan membatasi pilihan pada daftar PK . Menghapus objek bukanlah masalah, itu berfungsi dengan baik. Membuat objek dengan say, Item_id of 7 gagal ditambahkan ke daftar pantauan, meskipun saya dapat menanyakan daftar dan memang Id 7 ada:
listing.objects.all()
<QuerySet [<listing: Japanese Tea pot>, <listing: Kindle paperwhite>]>
>>> listing.objects.filter(id=7)
<QuerySet [<listing: Japanese Tea pot>]>
Jadi saya berasumsi bahwa pemahaman dan penggunaan ForiegnKey saya cacat. Bagaimana saya melakukannya dengan benar?
Juga, saya minta maaf jika pemformatan saya tidak aktif, ini adalah pertama kalinya saya memposting di sini.
Jawaban
Saya pikir ini adalah kesalahan yang cukup umum. Saat Anda membuat ForeignKeybidang, ini bertindak sebagai abstraksi dari hubungan kunci asing database yang sebenarnya. Ini berarti bahwa memanggil a (dalam kasus Anda) watchlist.item_idtidak akan mengembalikan id, melainkan listingobjek sebenarnya . Ini sama saat membuat objek.
Buat daftar pantauan Anda dengan item sebenarnya, bukan dengan nilai integer id-nya:
watchlist.objects.create (
item_id=item,
user_id=request.user.id
)
Saya tidak yakin apakah meneruskan kunci alih-alih sebuah instance ke metode filter model berfungsi, tetapi lebih baik juga meneruskan objek sebenarnya di sana:
watchlist.objects.filter(item_id=item, user_id=request.user)
Ini terlihat agak aneh: meskipun Anda mungkin terbiasa menyebut kunci asing sebagai item_id, sebaiknya beri nama kunci asing setelah hubungan yang sebenarnya. Jadi dalam hal ini Anda harus mengubah item_iddalam watchlistkelas hanya item.
Selanjutnya, kelas Django harus ditulis dengan huruf kapital, jadi kelas Anda akan terlihat seperti ini:
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")
dan tentu saja kode Anda harus diubah menjadi:
WatchList.objects.create (
item=item,
user=request.user.id
)
dan:
WatchList.objects.filter(item=item, user=request.user)