Django - Error received when anonymous user submits form - python

In one of my views I have a form where when a user logs in and submits the form, it works fine.
However, when an anonymous user submits the form I get the following error:
Cannot assign "<SimpleLazyObject: <django.contrib.auth.models.AnonymousUser object at 0x1052fd3a0>>": "User_Inquiries.user" must be a "CustomUser" instance.
This form needs to be submitted whether a user is anonymous or logged in.
What do I need to do in order to resolve this issue?
Code below.
Any help is gladly appreciated. Thanks!
views.py
def account_view_contact(request):
form = ContactUsForm(request.POST or None, request.FILES or None,)
user_profile = User_Inquiries.objects.all()
user_profile = User_Info.objects.all()
user = request.user
if request.method == "POST": # checking if request is POST or Not
# if its a post request, then its checking if the form is valid or not
if form.is_valid():
contact_instance = form.save(commit=False) # "this will return the 'Listing' instance"
contact_instance.user = user # assign 'user' instance
contact_instance.save() # calling 'save()' method of model
return redirect("home")
context = {
'form': form, 'user_profile': user_profile
}
return render(request, 'contact.html', context)
models.py
class User_Inquiries(models.Model):
email = models.EmailField(max_length=100, null=True)
name = models.CharField(max_length=100, null=True)
subject = models.CharField(max_length=100, null=True)
message = models.CharField(max_length=100, null=True)
user = models.ForeignKey(settings.AUTH_USER_MODEL, null=False, on_delete=models.CASCADE)
date_submitted = models.DateTimeField(auto_now_add=True, null=True)
class Meta:
verbose_name_plural = "User Inquiries"
#property
def user_message(self):
return truncatechars(self.message, 30)

What you can do is :
First, add a user field with null=True
class User_Inquiries(models.Model):
# ....
user = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, on_delete=models.CASCADE)
# ...
Second, in your view, you need to provide the user field only if the user is authenticated. Because AnonymousUser can be saved in the database.
def account_view_contact(request):
user_profile = User_Info.objects.all()
# If it's a post request
if request.method == "POST":
form = ContactUsForm(request.POST, request.FILES or None,)
if form.is_valid():
if request.user is authenticated:
# Only authenticated user can be assigned
contact_instance = form.save(commit=False)
contact_instance.user = request.user
contact_instance.save()
return redirect("home")
else:
# Save the form without user because no user is logged in
form.save()
# Handle no POST request
else:
form = ContactUsForm()
context = {
'form': form, 'user_profile': user_profile
}
return render(request, 'contact.html', context)

the User_Inquiries model user should be blank = True and null = True. In the view check if the user is logged in before setting the contact_instance.user to user.
models.py
class User_Inquiries(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, blank=True, on_delete=models.CASCADE)
views.py
def account_view_contact(request):
form = ContactUsForm(request.POST or None, request.FILES or None,)
user_profile = User_Inquiries.objects.all()
user_profile = User_Info.objects.all()
# check if the user is authenticated
if request.user.is_authenticated:
user = request.user
if request.method == "POST": # checking if request is POST or Not
# if its a post request, then its checking if the form is valid or not
if form.is_valid():
contact_instance = form.save(commit=False) # "this will return the 'Listing' instance"
contact_instance.user = user # assign 'user' instance
contact_instance.save() # calling 'save()' method of model
return redirect("home")
context = {
'form': form, 'user_profile': user_profile
}
return render(request, 'contact.html', context)
check if user is authenticated in django
set null and blank = True

I tried the above solutions and it worked. I also used CreateView to figure this out and it worked flawlessly. Code below:
class account_view_contact(CreateView):
model = User_Inquiries
form_class = ContactUsForm
template_name = "contact.html"
success_url = reverse_lazy("home")
def form_valid(self, form):
if self.request.user.is_authenticated:
self.object = form.save(commit=False)
self.object.created_by = self.request.user
self.object.save()
else:
self.object = form.save(commit=False)
self.object.save()
return super().form_valid(form)
Thanks Everyone!

Related

How to get the current logged in user? Django models

I want to get the current logged in user to this CreateForm form. Below Im giving my current code, here request.user is not giving me error
ValueError at /create-post/
Cannot assign "<SimpleLazyObject: <User: testuser>>": "Post.author" must be a "Author" instance.
models.py
class Author(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
rate = models.IntegerField(default=0)
class Post(models.Model):
title = models.CharField(max_length= 50)
overview = models.TextField()
body_text = RichTextUploadingField(null = True)
time_upload = models.DateTimeField(auto_now_add=True)
author = models.ForeignKey(Author, related_name='author', on_delete=models.CASCADE)
thumbnail = models.ImageField(upload_to = 'thumbnails')
publish = models.BooleanField()
categories = models.ManyToManyField(Categories)
read = models.IntegerField(default=0)
slug = models.SlugField(null= True, blank= True)
Forms.py
class CreateForm(ModelForm):
class Meta:
model = Post
fields = [
'title',
'overview',
'body_text',
'thumbnail',
'categories',
'publish',
]
Views.py
def create_post(request):
if request.method == 'POST':
form = CreateForm(request.POST, request.FILES)
if form.is_valid:
post = form.save(commit=False)
post.author= request.user
post.save()
return render(request, 'index.html')
else:
form = CreateForm()
return render(request, 'create_post.html', {'form': form})
As the error says, post.author expects an Author object, not the user. You thus retrieve this with:
from django.contrib.auth.decorators import login_required
#login_required
def create_post(request):
if request.method == 'POST':
form = CreateForm(request.POST, request.FILES)
if form.is_valid():
form.instance.author= request.user.author
form.save()
return render(request, 'index.html')
else:
form = CreateForm()
return render(request, 'create_post.html', {'form': form})
You should also call the is_valid() method [Django-doc], so form.is_valid().
Note: You can limit views to a view to authenticated users with the
#login_required decorator [Django-doc].
Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation.
The author field on your Post model is a foreign key to Author model, and not user. You could replace post.author = request.user with:
if request.user.author:
post.author = request.user.author
else:
post.author = Author.objects.create(user=request.user)
The answer from Willem works if an Author instance was already created for the User, but will throw an exception if there's no Author object associated with that user.

Django: how to check if a field has been modified by the user?

I have a model in models.py; like this:
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
avatar = models.ImageField(upload_to='static/images/account/avatar', default='/static/images/default-avatar.png')
bio = models.CharField(max_length=300, blank=True, null=True)
def __str__(self):
return '#' + self.user.username
in views.py i want to check if a filed (i mean avatar) from Profile model has changed or not
in views.py:
def editProfile(request):
user = request.user.profile
form = AuthorForm(instance=user)
if request.method == 'POST':
if ...:
os.remove(request.user.profile.avatar.path)
form = AuthorForm(request.POST, request.FILES, instance=user)
if form.is_valid():
form.save()
return redirect('dashboard')
context = {'form': form}
return render(request, 'account/edit.html', context)
In fact, I want the default image (or any other photo) not to be deleted if the user does not change the avatar field.
The fields that change are listed in the .changed_data attribute [Django-doc]. You thus can check if the avatar has changed with:
if 'avatar' in form.changed_data:
os.remove(request.user.profile.avatar.path)

Form is not being saved in Django admin page

I have faced a problem in my Django project where my form is not being saved as a new listing in my model(listing) and is not even showing on Django's admin page.
my models.py :
class listing(models.Model):
title = models.CharField(max_length=64)
describtion = models.CharField(max_length=300)
bid = models.FloatField()
category = models.ForeignKey(categories, default=1, verbose_name="Category",
on_delete=models.SET_DEFAULT)
user = models.ForeignKey(User,default='', verbose_name="User", on_delete=models.SET_DEFAULT)
image = models.CharField(max_length=400)
def __str__(self):
return f"{self.title} "
create a new listing form :
class create(ModelForm):
class Meta:
model = listing
fields = [ 'title', 'describtion','bid','category','image']
views.py :
def CreateListing(request):
user = request.user
if request.method == "POST":
form = create(request.POST, instance=user)
if form.is_valid():
new_listing = form.save()
new_listing.user = request.user
new_listing.save()
return render(request, "auctions/listing.html")
else:
return render(request, "auctions/Create.html",{
"form": create
})
Ps: I have no problem with my urls.py
You need to set the user before you can save this to the database:
def CreateListing(request):
user = request.user
if request.method == "POST":
form = create(request.POST, instance=user)
if form.is_valid():
form.instance.user = user
form.save()
return redirect('%name-of-some-view')
else:
form = create(instance=user)
return render(request, "auctions/Create.html",{
'form': form
})
Note: You can limit views to a view to authenticated users with the
#login_required decorator [Django-doc].
Note: In case of a successful POST request, you should make a redirect
[Django-doc]
to implement the Post/Redirect/Get pattern [wiki].
This avoids that you make the same POST request when the user refreshes the
browser.

null value in column "user_id" violates not-null constraint Django form

Trying to implement a file upload for a user profile page. I am recieving the following error:
null value in column "user_id" violates not-null constraint
DETAIL: Failing row contains (35,
profile/{now:%Y/%m/YmdHMSext_xg2iZ6M, null, null).
I've read that it probably has something to do with the User_ID, I tried passing form.user = request.user, but that didn't work. There are also two nulls, not just one.
Models.py
class User(AbstractUser):
# First Name and Last Name do not cover name patterns
# around the globe.
name = models.CharField(_('Name of User'), blank=True,
max_length=255)
#accepted_terms_of_service = models.Booleanfield()
def __str__(self):
return self.username
def get_absolute_url(self):
return reverse('users:detail', kwargs={'username':
self.username})
# Profile Image
def upload_to(instance, filename):
now = timezone_now()
base, ext = os.path.splitext(filename)
ext = ext.lower()
return "profile/{now:%Y/%m/%Y%m%d%H%M%S}{ext}"
class Profile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL,
on_delete='CASCADE', related_name='user_profile')
school = models.CharField(max_length=30, null=True, blank=True)
image = models.ImageField(_("Picture"), upload_to=upload_to,
null=True, blank=True)
def __str__(self):
return self.user.username
views.py
#login_required
def add_image(request):
form = ProfileImageForm()
#form.user = request.user
if request.method == "POST":
form = ProfileImageForm(data=request.POST, files=request.FILES)
if form.is_valid():
form.save()
return redirect('userPage')
else:
return render(request, "users/user_image_form.html", {"form": form
})
forms.py
class ProfileImageForm(forms.ModelForm):
class Meta:
model = Profile
fields = ["image"]
This is because in your Profile model you add user column as ForeignKey which enforce to NOT NULL so the error throw.
To solve this you need to modify add_image method something like this
#login_required
def add_image(request):
form = ProfileImageForm()
#form.user = request.user
if request.method == "POST":
form = ProfileImageForm(data=request.POST, files=request.FILES)
if form.is_valid():
form = form.save(commit=False) # change is here
form.user=request.user.pk # change is here
form.save()
return redirect('userPage')
else:
return render(request, "users/user_image_form.html", {"form": form
The request.user.pk value get if you are logged in. But if you are logged in you need to assisn form.user = your_specified_id which id exists in User table.
If your case is, you are admin and you need to add an image to other users, so that you need to pass the user id in your add_image method.
Add in ProfileImageForm.py
add user in field list
I think its not necessary to have both Profile Model and Custom User Model. Because, as you are customizing the User model already, why not put Profile model's fields to User model as well. You can approach like this:
# model
def upload_to(instance, filename):
now = timezone_now()
base, ext = os.path.splitext(filename)
ext = ext.lower()
return "profile/{now:%Y/%m/%Y%m%d%H%M%S}{ext}"
class User(AbstractUser):
name = models.CharField(_('Name of User'), blank=True,
max_length=255)
school = models.CharField(max_length=30, null=True, blank=True)
image = models.ImageField(_("Picture"), upload_to=upload_to,
null=True, blank=True)
def __str__(self):
return self.username
def get_absolute_url(self):
return reverse('users:detail', kwargs={'username':
self.username})
# views
#login_required
def add_image(request):
form = ProfileImageForm(data=request.POST or None, file=request.FILES or None, instance=request.user)
if request.method == "POST":
if form.is_valid():
form.save()
return redirect('userPage')
return render(request, "users/user_image_form.html", {"form": form
})
# forms.py
class ProfileImageForm(forms.ModelForm):
class Meta:
model = User
fields = ["image"]
Update
You can create a post_save signal, which will create a Profile Instance after each User is created.
def create_user_profile(sender, instance, created, **kwargs):
if created:
profile = Profile(user=instance)
profile.save()
post_save.connect(create_user_profile,
sender=User,
dispatch_uid="profilecreation-signal")
Now in your form, you can directly pass this Profile instance:
#login_required
def add_image(request):
form = ProfileImageForm(data=request.POST, files=request.FILES, instance=request.user.profile)
if request.method == "POST":
if form.is_valid():
form.save()
return redirect('userPage')
else:
return render(request, "users/user_image_form.html", {"form": form
})
For existing user, you can create Profile from shell:
for user in User.objects.all():
Profile.objects.get_or_create(user=user)

Form submission not generating new Post object

I'm currently creating a Social platform with Django. Right now, I'm developing their Dashboard and want endusers to be able to publish their own posts. This is my Post model:
class Post(models.Model):
user = models.ForeignKey(User)
posted = models.DateTimeField(auto_now_add=True)
content = models.CharField(max_length=150)
Likes = models.IntegerField(default=0)
def __str__(self):
return self.user.username
My Form for the Post model:
class Post_form(forms.ModelForm):
class Meta:
model = Post
fields = (
'content',
]
def __init__(self, *args, **kwargs):
super(Post_form, self).__init__(*args, **kwargs)
self.fields['content'].label = ""
self.fields['content'].widget.attrs={
'id': 'id_content',
'class': 'myCustomClass',
'name': 'name_content',
'placeholder': 'What are you thinking about?',
}
When the form gets submitted, it correctly generates a POST request with the value of the content field. When I save my form in the view, no new post gets generated. What am I doing wrong?
My views.py:
def dashboard_view(request):
if request.POST:
form = Post_form(data=request.POST, instance=request.user)
if form.is_valid():
form.save() // <- no new post gets generated after saving
return redirect(reverse('dashboard'))
else:
return redirect(reverse('settings'))
else:
form = Post_form
gebruikers = User.objects.all()
all_posts = Post.objects.all().order_by('-posted')
return render(request, 'Dashboard/index.html', {'gebruiker':gebruikers, 'posts':all_posts, 'form': form},)
You can't pass the user as the instance parameter to a Post form. You should omit that argument and assign the user on the actual Post instance returned from save.
form = Post_form(data=request.POST)
if form.is_valid():
post = form.save(commit=False)
post.user = request.user
post.save()

Categories

Resources