I got the problem with form that is not saving to the datebase.
views.py
...
#login_required
def create_task(request):
if request.method == 'POST':
form = CreateTaskForm(request.POST, instance=request.user)
if form.is_valid():
form.save()
return redirect('index')
else:
form = CreateTaskForm()
context = {'form': form}
return render(request, 'tasks/task_form.html', context)
...
forms.py
from django import forms
from .models import Task
class CreateTaskForm(forms.ModelForm):
class Meta:
model = Task
fields = (
'name',
'end_date',
'description',
)
Is it the problem with a create_task view or CreateTaskForm?
The problem is with the create_task view:
if request.method == 'POST':
form = CreateTaskForm(request.POST)
if form.is_valid():
# if you have user in your model task make commit to false then set the user
form.save(commit=false)
form.user = request.user
#if not save directly you form
form.save()
return redirect('index')
then check if your url is:
path('create_task', create_task, name="create_task")
First off, since you are using POST, which means you are creating, there is no need for instance=request.user - which is used to compare previous data against new data provided by the form. Looking at your form, it does not look like it has anything to do with the user.
Second, you are not displaying or returning form errors. So it may be silently failing validation at the model level without your knowledge. Try adding a return with form errors.
#login_required
def create_task(request):
form = CreateTaskForm()
if request.method == 'POST':
form = CreateTaskForm(request.POST)
if form.is_valid():
form.save()
return redirect('index')
context = {'form': form}
return render(request, 'tasks/task_form.html', context)
You can look in form.errors on the template side to see validation errors.
Related
I would like to automatically add the User who submitted the form to the users many to many field on the below-given model when the form submits, how could I do this from the view?
The model:
class Project(MainAbstractModel):
users = models.ManyToManyField(User)
title = models.CharField(max_length=25, default="Conflict")
The view:
def myconflicts(request):
if request.method == "POST":
form = ProjectForm(request.POST)
if form.is_valid():
form.save()
else:
form = ProjectForm()
return render(request, 'conflictmanagement/myconflicts.html')
And my form is simply:
class ProjectForm(ModelForm):
class Meta:
model = Project
fields = ["title"]
You can add the user in the view, for example with:
from django.contrib.auth.decorators import login_required
from django.shortcuts import redirect
#login_required
def myconflicts(request):
if request.method == 'POST':
form = ProjectForm(request.POST)
if form.is_valid():
project = form.save()
project.users.add(request.user)
return redirect('name-of-some-view')
else:
form = ProjectForm()
return render(request, 'conflictmanagement/myconflicts.html', {'form': form})
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.
Note: You can limit views to a view to authenticated users with the
#login_required decorator [Django-doc].
this is my blog : http://gorani-dncvb.run.goorm.io/
I am trying to build a signup page for my django blog.
I finished writing codes for template/view/form/url, and successfully connected to the page : http://gorani-dncvb.run.goorm.io/accounts/signup.
So I came to think there is no problem in template/url. but the problem arises after trying signup, It saids :
IntegrityError at /accounts/signup
UNIQUE constraint failed: auth_user.username
and this is my view code :
def signup(request):
if request.method == "POST":
form = SignupForm(request.POST)
if form.is_valid():
form.save()
username = form.cleaned_data.get('username')
raw_password = form.cleaned_data.get('password')
user = User.objects.create_user(username=username, password=raw_password)
return redirect("post_list")
else:
form = SignupForm()
return render(request, 'registration/signup.html', {'form':form})
and this is form code :
class SignupForm(forms.ModelForm):
class Meta:
model = User
fields = ('username','password',)
(I didn't used UserCreateForm on purpose)
There's definitely no overlapping another user, so why I'm seeing this error message?
The reason for duplicating the user is that django creates the user when saving the form.
When a form is a child of ModelForm, saving it will create a new object of the model class related to the form.
Just delete or comment the code lines for user creation and it wil work fine:
def signup(request):
if request.method == "POST":
form = SignupForm(request.POST)
if form.is_valid():
user = form.save()
user.set_password(user.password)
user.save()
return redirect("post_list")
else:
form = SignupForm()
return render(request, 'registration/signup.html', {'form':form})
Best regards.
I would like to be able to check if the user accessing a page is a specific user.
For instance, when a user accesses the "Edit Post" page on my blog app, I want to ensure that the user is the author of the post.
Currently, I check that the user accessing '/Blog/Edit//' has the blog.change_post permission.
However, if a second user (who also has that permission) were to enter the URL to change someone else's post, they would pass that permission check and be able to edit someone else's post.
What I want is a #user_passes_test function that check's the user object accessing the view against the author attribute of the post.
#/Blog/urls.py
urlpatterns = [
...
path('Edit/<int:pk>', views.BlogEdit, name='BlogEdit'),
...
]
#/Blog/views.py
#permission_required('blog.change_post', login_url='/Portal/login')
def BlogEdit(request, pk):
post = get_object_or_404(Post, pk=pk)
if request.method == "POST":
form = PostForm(request.POST, instance=post)
if form.is_valid():
post = form.save(commit=False)
post.save()
return redirect('/Blog', pk=post.pk)
else:
form = PostForm(instance=post)
return render(request, 'Blog/Edit.html', {'form': form})
You can add an extra filter to your get_object_or_404:
#permission_required('blog.change_post', login_url='/Portal/login')
def BlogEdit(request, pk):
post = get_object_or_404(Post, pk=pk, author=request.user)
if request.method == "POST":
form = PostForm(request.POST, instance=post)
if form.is_valid():
form.save()
return redirect('/Blog', pk=post.pk)
else:
form = PostForm(instance=post)
return render(request, 'Blog/Edit.html', {'form': form})
Here author is the hypothetical ForeignKey from Post to the user model. It is possible that the name is different, but the idea is still the same.
This thus means that in case the pk is the pk of a Blog for which request.user is not the author, then we will have a 404 response.
The advantage of filtering here, is that we use a single query for the filtering. We will not (lazily) load the author to check if it is the same as the logged in user.
Note: post = form.save(commit=False) and post.save() are equivalent to post = form.save() (so with commit=True).
In a class based view change the get_queryset method to filter by current user.
class MyView(LoginRequiredMixin, UpdateView):
...
def get_queryset(self):
"""
Only the current logged in user can edit ...
"""
return super().get_queryset().filter(created_by=self.request.user)
I figured it out from This Post in the end. What urbanspaceman suggests works for class based views, but for function based views you can do:
#permission_required('blog.change_post', login_url='/Portal/login')
def BlogEdit(request, pk):
post = get_object_or_404(Post, pk=pk)
if post.author != request.user:
raise Http404("You are not allowed to edit this Post")
# ... Rest of view here ... #
When I upload a photo, the photo is loaded successfully, but the photo is placed in the wrong directory.
Instead of placing the image on the path to 'media/posts-pics/' - as I have outlined in my Post model - it is placed on the 'media' path.
These are my files:
models.py
class Post(models.Model):
index_pic = models.ImageField(upload_to='posts-pics/')
Project.urls.py
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
views.py
def add_post(request):
if request.method == "POST":
form = AddPostForm(request.POST, request.FILES)
if form.is_valid():
new_post = form.save(commit=False)
new_post.index_pic = form.cleaned_data['index_pic']
new_post.save()
return redirect('view_post')
else:
form = AddPostForm()
template = 'post/add_edit_post.html'
context = {'form': form}
return render(request, template, context)
def edit_post(request, slug):
post = get_object_or_404(Post, slug=slug)
if request.method == "POST":
form = AddPostForm(request.POST, request.FILES, instance=post)
if form.is_valid():
Post.objects.filter(id=post.id).update(title=request.POST['title'],
index_pic=form.cleaned_data['index_pic'],
)
return redirect('view_post')
else:
form = AddPostForm(instance=post)
template = 'post/add_edit_post.html'
context = {'form': form}
return render(request, template, context)
I used exactly the same code for add_post, and the photo was in its place, but I got into trouble in edit_post. what's wrong ?
Notice:
Technically I can delete 'media/post-pics' but this is done with a
special purpose and the purpose is: Each app have its folder for
saving images.
The problem is that you're no using your ModelForm the right way.
In the edit_post view, you want to replace this:
Post.objects.filter(id=post.id).update(
title=request.POST['title'],
index_pic=form.cleaned_data['index_pic'],
)
with a plain simple:
form.save()
which will take care of the updating the post passed as form.instance (using sanitized data, which is not the case with your current code)
FWIW, in your add_post view, you also want to replace this
new_post = form.save(commit=False)
new_post.index_pic = form.cleaned_data['index_pic']
new_post.save()
with a plain simple:
new_post = form.save()
Once again, the whole point of ModelForms is that they know how to create and update model instances.
after uploading the image to a form when i submit the form it still shows "the field is required" error
in models.py:
class Members(models.Model):
image=models.ImageField(upload_to="images/",default='')
in forms.py:
class CreateOne(forms.Form):
image=forms.ImageField(required=True)
in create.html:
<form class="form-inline" action="create" method="POST"
enctype="multipart/form-data" novalidate>
in views.py:
def create(request):
member = Members(image=request.FILES['image'])
if request.method == 'POST':
form = forms.CreateOne(request.POST)
if form.is_valid():
member.save()
return redirect('/')
else:
form = CreateOne()
I think you understand the way to use a Form the wrong way. The idea of such Form when you write some_form.save() it makes the changes (and for example create a model instance and save it to the database).
Since most forms (like probably this one) are related to a single model, Django has a ModelForm, which offers extra convenience:
class CreateOne(forms.ModelForm):
image=forms.ImageField(required=True)
class Meta:
model = Members
fields = ['image']
Then we can make a view that will create an instance in case of a valid form with:
def create(request):
if request.method == 'POST':
form = forms.CreateOne(request.POST, request.FILES)
if form.is_valid():
form.save()
return redirect('/')
else:
form = CreateOne()
return render(request, 'some_template.html', {'form': form}
You probably also do not want to redirect in case the form was not valid, since then you probably want to give the user feedback that the form was not valid (and show the corresponding errors).