3
5 Comments

How can i associate new product with current user in django

Currently If i try adding a new product , i get this error ValueError "Cannot assign "(<Merchant: aliyu>, False)": "Product.merchant" must be a "Merchant" instance."

what i want to achieve is product to be associated with the current user.

views.py

def addproduct(request):
if request.method=='POST':
form=ProductForm(request.POST)
if form.is_valid():
new_product=form.save(commit=False)
new_product.merchant__user=request.user
new_product.save()
return HttpResponseRedirect('users:users_homepage')
else:
form=ProductForm()
context={'form':form}
return render(request,'users/addproduct.html',context)

models.py

class Product(models.Model):
name = models.CharField(max_length=255, unique=True)
date_added = models.DateTimeField(auto_now_add=True)
merchant=models.ForeignKey(Merchant, on_delete=models.CASCADE,null=True)

class Merchant(models.Model):
user=models.OneToOneField(User,on_delete=models.CASCADE, primary_key=True)

thanks beforehand.

on December 7, 2020
  1. 1

    new_product.merchant__user=request.user

    As far as I know, the double-underscore notation is only used in Django query filters.

    What you want is:

    new_product.merchant.user = request.user

    PS Saw other users lecturing you about using CBVs. I actually agree with you that FBVs are a lot more readable and easier to process, particularly for novice developers.

  2. 1

    I do agree with @prettycold that CBV are the way to go for making views, and you should try to get used to them as they'll save you a lot of time and are more safe to use.

    as for the problem, you'll just need to change this line:
    new_product.merchant__user=request.user
    to:
    new_product.merchant = Merchant.objects.get(user=request.user)

    1. 2

      OK...what happens if there is no Merchant for this particular user? You might want to catch the ObjectDoesNotExist exception gracefully, perhaps by raising a 404.

      RE CBVs: they're OK I guess but they're not very good at handling anything beyond the simplest cases without becoming mixin/MRO hell and tracking state through multiple methods (ie ravioli vs spaghetti code). I used to prefer them but over time, with some exceptions (e.g. building a quick API with DRF, or creating an extensible package), I've found them to be more pain than they are worth. The FBV pattern of "request in -> response out" is easier to follow, especially for beginners, and as with any Python function they can be easily refactored when they get too repetitive and verbose.

      This set of articles pretty much matches my experience:

      https://spookylukey.github.io/django-views-the-right-way/

  3. 1

    Hi @musty474,

    I'd suggest you use Class based Views instead, they are just super neat and very less lines of code and extremely straight forward for cases like this. Will just re-write your FBV (a sample)

    Class AddProduct(CreateView, SuccessMessageMixin):
    model = models.Product
    form_class = forms.ProductForm
    success_message = 'Product added successfully'

    That's all you'd need as a starting point.

    Another suggestion is, why do you need a separate Merchant class? Instead, give User as a FK in Product class itself, something like this:

    merchant = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='merchant')
    

    Hope this helps!