首页 > 解决方案 > How to assign UserProfile with WishList without using a default user

问题描述

I have an app that contains a model UserProfile()

class UserProfile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    city = models.CharField(max_length=50, default='')
    phone = models.IntegerField(default='0')
    image = models.ImageField(upload_to='profile_image', blank=True)

    def __str__(self):
        return self.user.username

connecting to a default user(User). I wanted to connect my user with a wishlist model

class WishList(models.Model):
    toy_name_wish = models.ForeignKey(Toy, on_delete=models.CASCADE)
    user_wish = models.ForeignKey(UserProfile, on_delete=models.CASCADE)

    def __str__(self):
        return self.user_wish

And using generic view with def post(self, request): I created simple logic for a toy that will be shown in admin part as a user's wish item

class DetailToyView(TemplateView):
    template_name = 'app/detail_toy.html'
    #other defs

    def post(self, request, toy_id):
        toy = get_object_or_404(Toy, pk=toy_id)
        user_profile = UserProfile()
        wishlist = WishList() 
        try:
            selected_toy = get_object_or_404(Toy, pk=toy_id) 
    except(KeyError, Toy.DoesNotExist):
        return render(request, 'app/detail_toy.html', {'toy': toy})
    else:
        user_profile.user = self.request.user
        user = user_profile.user
        wishlist.toy_name_wish = toy
        wishlist.user_wish = user
        wishlist.save()
        return HttpResponseRedirect(reverse('app:detail-category-toy', args=(toy.id,)))

If it's important here's my urls.py file

from django.urls import path
from django.conf.urls import url
from . import views
from django.contrib.auth import views as auth_views

app_name = 'app'
urlpatterns = [
    path('', views.index, name='index'), # INDEX
    path('personal-page/', views.personal_page, name='personal-page'),
    # SIGN_IN, SIGN_OUT AND SIGN_UP
    path('sign-in/', auth_views.login,
        {'template_name': 'app/sign_in.html'},
        name='sign-in'),
    path('sign-out/', auth_views.logout,
        {'next_page': '/'},
        name='sign-out'),
    path('sign-up/', views.sign_up, name='sign-up'),
    # DETAIL_PAGES
    #url(r'^book-detail/(?P<book>[0-9]+)/$', views.detail_book, name='book'),
    url(r'^detail_category_toy/(?P<category_id>[0-9]+)/$', views.detail_category_toy, name='detail-category-toy'),
    url(r'^detail-toy/(?P<toy_id>[0-9]+)/$', views.DetailToyView.as_view(), name='toy')]

So here is the problem when I click on the button I'm getting an error

ValueError at /detail-toy/2/
Cannot assign "<SimpleLazyObject: <User: admin>>": "WishList.user_wish" must be a "UserProfile" instance.

This means I cannot use user.username So how do I get UserProfile instance instead of the basic User model?

P.S: Sorry for some stupid-called variables

标签: djangodjango-modelsdjango-rest-frameworkdjango-views

解决方案


好吧,您的直接问题是您将用户设置为 WishList 对象而不是 UserProfile。保存前的行应该是:

wishlist.user_wish = user_profile

但实际上这里发生了很多奇怪的事情。一个用户只能有一个 UserProfile,这听起来不错,但在这个视图中,您总是创建一个新的;如果该用户已经有个人资料,这将导致错误。而且您的 WishList 模型并不是真正的列表,而是个人资料和玩具之间的单一关系。

这里你真正需要的是 UserProfile 和 Toy 之间的多对多关系,也就是愿望清单:

class UserProfile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    city = models.CharField(max_length=50, default='')
    phone = models.IntegerField(default='0')
    image = models.ImageField(upload_to='profile_image', blank=True)
    wishlist = models.ManyToManyField('Toy')

(而且您根本不需要 WishList 模型)

在您看来,用于get_or_create获取现有配置文件或创建新配置文件:

def post(self, request, toy_id):
    toy = get_object_or_404(Toy, pk=toy_id)
    user_profile = get_or_create(UserProfile, user=request.user)
    user_profile.wishlist.add(toy)
    return HttpResponseRedirect(reverse('app:detail-category-toy', args=(toy.id,)))

推荐阅读