Home > Enterprise >  Django ValueError: Cannot assign "<SimpleLazyObject: <CustomUser: >>": "B
Django ValueError: Cannot assign "<SimpleLazyObject: <CustomUser: >>": "B

Time:11-26

The objective is simple: I'm building a car rental platform where customers can place an order for a car. The simple 'order' contains the car, start, and end-dates. The form should automatically save the authenticated user as the creator.

It uses a CreateView with this code:

class BookingCreate(CreateView):
    model = Booking
    fields = ['car', 'start_date', 'end_date']

    permission_classes = [permissions.IsAuthenticated]

    def form_valid(self, form):
        form.instance.user = self.request.user
        return super().form_valid(form)

The form works fine, but when submitted, it raises this error:

ValueError at /rentals/booking/create Cannot assign "<SimpleLazyObject: <CustomUser: Test2 Two>>": "Booking.user" must be a "Customer" instance.

I've looked up previous answers, and the best solution came from this thread, which recommended using this code instead

 def form_valid(self, form):
     form.instance.user = Booking.objects.get(user=self.request.user)
         return super().form_valid(form)

However, this change returns a slightly different error:

ValueError at /rentals/booking/create Cannot query "Test2 Two": Must be "Customer" instance. I have a customUser Model and a "customer" model that inherits from it.

For additional context, I am using a customUser model. Because I have multiple user types (in particular (car) Owners and Customers), I use a special table with boolean fields to mark each type as True based on the registration form they use per this this tutorial.

Here's the relevant code (there's a lot, so I've only added the relevant parts):

models.py

from accounts.models import CustomUser

class User(CustomUser):
    is_customer = models.BooleanField(default=False)
    is_owner = models.BooleanField(default=False)
    

class Owner(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)
    
    def __str__(self):
        return self.user.first_name


class Customer(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)
    cars = models.ManyToManyField('Car', blank=True)
    ...

    def get_absolute_url(self):
        return reverse('rental:customer-detail', args=[str(self.id)])

    def __str__(self):
        return f'{ self.user.first_name } { self.user.last_name }' 

class Booking(models.Model):
    """Stores the bookings, for example when it was made, the booking date, and the car ID."""

    # Unique ID for this booking.
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, help_text="Automatically generated unique ID. Do not change.")
    user = models.ForeignKey('Customer', on_delete=models.SET_NULL, null=True)
    car = models.ForeignKey(Car, on_delete=models.SET_NULL, null=True)
    start_date = models.DateField(default=timezone.now)
    end_date = models.DateField(null=True)
    ...
    

Solution and extra resources for future explorers

Both answers below helped, but the issue kept coming back. The permanent solution was this line of code:

  def form_valid(self, form):
        form.instance.created_by = Customer.objects.get(pk=self.request.user.pk)
        return super().form_valid(form)

As alluded to in the question above, this is a common problem. So here are three other threads to look at, each with great answers:

ValueError at /post/new/ Cannot assign "<SimpleLazyObject:<User: chetan>>": "Post.author" must be a "User" instance

Cannot assign "<SimpleLazyObject: <User: XXX>>": "Comment.user" must be a "MyProfile" instance

Cannot assign "<SimpleLazyObject: <User: JohnDoe12>>": "Profile.user" must be a "User" instance

CodePudding user response:

I'd recommend you to use get_object_or_404() and you need to assign user not Booking instance so:

def form_valid(self, form): 
    form.instance.user=get_object_or_404(Booking,user=self.request.user).user 
    return super().form_valid(form)

CodePudding user response:

Your self.request.user (or the user you're logged in as) seems to be the CustomUser instance, but you're trying to assign the User instance to the Booking. Though it has the same fields (as it inherits from CustomUser class), it is a different object.

I think you want to make the CustomUser an abstract model? You should add abstract to the CustomUser class. See: https://docs.djangoproject.com/en/4.1/topics/db/models/#abstract-base-classes

    class Meta:
        abstract = True

Then you would also need to select the correct user model in you'r settings like: AUTH_USER_MODEL = 'users.User' for example

https://docs.djangoproject.com/en/4.1/topics/auth/customizing/#substituting-a-custom-user-model

Also in the second option you're assigning the Booking instead of the related user. Do this instead:

def form_valid(self, form): 
    form.instance.user = Booking.objects.get(user=self.request.user).user 
    return super().form_valid(form)
  • Related