I have a view where they are multiple posts and I want when the user like one of them, the form take the user_id and the post_id and save it into the DB. This is th Models.py:
class LikePost(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
post = models.ForeignKey(Posts, on_delete=models.CASCADE)
def __str__(self):
return '{} - {}'.format(self.user.username, self.post.name)
Forms.py:
class LikePostForm(forms.ModelForm):
class Meta:
model = LikedShops
fields = ['user', 'post']
widgets = {
'user': forms.HiddenInput(),
'post': forms.HiddenInput()
}
Views.py:
def posts(request):
if request.method == 'POST':
form = LikePostForm(request.POST)
if form.is_valid():
u = form.save(commit=False)
u.user = request.user
u.save()
return redirect('posts')
else:
form = LikePostForm()
context = {
'posts': Posts.objects.all(),
'form': form
}
return render(request, "posts.html", context)
and this the form in posts.html:
{% for post in posts %}
<div class="col-md-3">
<article class="card mb-4">
<header class="card-header">
<h4 class="card-title"><b>{{ post.name }}</b></h4>
</header>
<img style="width: 100%; height: 150px;" class="card-img" src="{{ post.image.url }}"/>
<div class="card-body">
<p class="card-text">{{ post.description }}</p>
</div>
{% if user.is_authenticated %}
<div class="card-footer">
<div class="row">
<div class="col">
<form action="/posts/" method="post">
{% csrf_token %}
{{ l_form|crispy }}
<button type="submit" class="btn btn-outline-success">Like</button>
</form>
</div>
</div>
</div>
{% endif %}
</article><!-- /.card -->
</div>
{% endfor %}
This is my edit, I did what you said, I made changes to:
forms.py:
class Meta:
model = Liked
fields = ['user', 'post']
widgets = {
'user': forms.HiddenInput(),
'post': forms.HiddenInput()
}
posts.html:
<form action="/posts/" method="post">
{% csrf_token %}
<input type="hidden" name="post" value="{{ post.pk }}">
{{ l_form|crispy }}
<button type="submit" class="btn btn-outline-success">Like</button>
</form>
views.py:
def posts(request):
if request.method == 'POST':
l_form = LikePostForm(request.POST, instance=request.user.profile)
if l_form.is_valid():
u = l_form.save(commit=False)
u.post = Posts.objects.filter(pk=l_form.cleaned_data.get('post')).first()
u.save()
messages.success(request, f"Form is valid!")
else:
messages.warning(request, f'Form is not valid! {request.POST}')
else:
l_form = LikePostForm(instance=request.user.profile)
context = {
'post': Posts.objects.all(),
'l_form': l_form
}
return render(request, "posts.html", context)
Now when I click the Like button, I got this message **Form is not valid! <QueryDict: {'csrfmiddlewaretoken': ['cNk9ZDS33Nj0l95TBfwtedL1jjAbzDSrH15VjMNZAcxjQuihWNZzOkVnIyRzsjwN'], 'post': ['1', ''], 'user': ['1']}>**
There are a couple of issues with your code.
First, the __str__() method should return a string and not a tuple
class LikePost(models.Model):
...
def __str__(self):
return '{} - {}'.format(self.user.username, self.post.name)
Second, there is a typo; change Pots to Posts:
context = {
'posts': Posts.objects.all(),
'form': form,
}
return render(request, "posts.html", context)
And third and last, the line u.post = request.post is throwing the error you mention, because the request object has no attribute post.
So change your form code to add the post in hidden state (I used fields instead of exclude):
class LikePostForm(forms.ModelForm):
class Meta:
model = LikePost
fields = ['post', ]
widgets = {
'post': forms.HiddenInput(),
}
and then change your view:
form = LikePostForm(request.POST)
if form.is_valid():
u = form.save(commit=False)
u.user = request.user
u.save()
After edit to the question:
Try adding post.pk as a hidden input in your form:
<form action="/posts/" method="post">
{% csrf_token %}
<input type="hidden" name="post" value="{{ post.pk }}">
{{ l_form|crispy }}
<button type="submit" class="btn btn-outline-success">Like</button>
</form>
or you can also do in your view:
u.post = Posts.objects.filter(pk=form.cleaned_data.get('post')).first()
Related
I was creating a post based website i want to show the author's name to show up in the post it works in the admin site when adding posts but when i try uploading a post from the site the form is not getting validated therefore it is not getting saved please help
model :
from django.conf import settings
class MemeImg(models.Model):
Title = models.CharField(max_length=500)
op = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, default=None, blank=True, null=True)
date_created = models.DateTimeField(auto_now_add=True)
Post_Img = CloudinaryField('Post')
forms :
class PostImg(forms.ModelForm):
class Meta:
model = MemeImg
fields = ['Title', 'op', 'Post_Img']
view :
#login_required(login_url='/login')
def post(request):
func = data(request)
if request.method == 'POST':
form = PostImg(request.POST, request.FILES, instance=request.user)
form.op = request.user
if form.is_valid():
print('success')
posts = form.save(commit=False)
posts.op = request.user
form.save()
return HttpResponseRedirect('https://youtu.be/dQw4w9WgXcQ')
else:
print("fail")
form = PostImg(request)
ctx = {
'form': form,
'url': func[0],
'name': func[1],
'date': func[2],
}
return render(request, 'Post.html', ctx)
and finally the post page template :
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
<div class="container">
{{ form.Title|materializecss }}
<div class="file-field input-field">
<div class="btn">
<span>File</span>
<input type="file">
</div>
<div class="file-path-wrapper">
{{ form.Post_Img }}
<input class="file-path validate" type="text">
</div>
</div>
<button class="btn waves-effect waves-light" type="submit" name="action">Submit
<i class="material-icons right">send</i>
</button>
</div>
</form>
If anymore code is required please comment it
Thanks a lot
I think your problem come from the form instance which is instance=request.user, actually the instance is supposed to be the MemeImg object instance and not the user, that's making it not to save the image. So i have deleted the instance and also i don't know what you are using those extra context variable for 'url': func[0],'name': func[1], 'date': func[2] ?, so i deleted them too keep things simple. Now i think you should be able to save without any Issues.
#login_required(login_url='/login')
def post(request):
if request.method == 'POST':
form = PostImg(request.POST, request.FILES)
if form.is_valid():
print('success')
data = form.save(commit=False)
data.op = request.user
form.save()
return HttpResponseRedirect('https://youtu.be/dQw4w9WgXcQ')
else:
print("fail")
form = PostImg(request.POST)
ctx = {
'form': form,
}
return render(request, 'Post.html', ctx)
Also your form had in it {{ form.Post_Img }} which i don't no what you are looking to accomplish with that variables?, the right way is doing {{ form.as_p }} or simply just calling the form like this {{ form }} so i have made the correction in you HTML
too.
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
<div class="container">
{{ form.Title|materializecss }}
<div class="file-field input-field">
<div class="btn">
<span>File</span>
<input type="file">
</div>
<div class="file-path-wrapper">
{{ form }}
<input class="file-path validate" type="text">
</div>
</div>
<button class="btn waves-effect waves-light" type="submit" name="action">Submit
<i class="material-icons right">send</i>
</button>
</div>
</form>
I want my users to be able to add comments under a transfernews [I am creating a sports related website], I tried this code, but for some reason I am getting this error TypeError at /transfernews/ Field 'id' expected a number but got <Transfernews: Transfernews object (3)>., I can add comments manually from the admin page but can't from the comment form. Can anyone please tell me how to fix my code?
My models.py:
class Transfernews(models.Model):
player_name = models.CharField(max_length=255)
player_image = models.CharField(max_length=2083)
player_description = models.CharField(max_length=3000)
date_posted = models.DateTimeField(default=timezone.now)
class Comment(models.Model):
user = models.ForeignKey(to=User, on_delete=models.CASCADE)
transfernews = models.ForeignKey(Transfernews, related_name="comments", on_delete=models.CASCADE)
body = models.TextField()
date_added = models.DateTimeField(auto_now_add=True)
def __str__(self):
return '%s - %s' % (self.transfernews.player_name, self.user.username)
My forms.py:
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = ('body',)
My views.py:
def transfer_targets(request):
transfernews = Transfernews.objects.all()
news = request.POST.get("transfer_id", None)
form = CommentForm(request.POST or None)
if form.is_valid():
new_comment = form.save(commit=False)
new_comment.user = User.objects.get(id=request.user.id)
new_comment.transfernews_id = Transfernews.objects.get(id=news)
new_comment.save()
return redirect(request.path_info)
return render(request, 'transfernews.html', {'transfernews': transfernews, 'form': form})
My html file:
{% for transfer in transfernews %}
<h2>Comments...</h2>
{% if not transfer.comments.all %}
No comments Yet...
{% else %}
{% for comment in transfer.comments.all %}
<strong>
{{ comment.user.username }} - {{ comment.date_added }}
</strong>
<br/>
{{ comment.body }}
<br/><br/>
{% endfor %}
{% endif %}
<hr>
<div>Comment and let us know your thoughts</div>
<form method="POST">
{% csrf_token %}
<input type="hidden" value="{{ transfer.id}}">
<div class="bg-alert p-2">
<div class="d-flex flex-row align-items-start">
</div>
<div class="mt-2 text-right">
{{ form|crispy }}
<br>
<button class="btn btn-primary btn-sm shadow-none" type="submit">Post comment</button>
<button class="btn btn-outline-primary btn-sm ml-1 shadow-none" type="button">Cancel</button>
</div>
</div>
</form>
{% endfor %}
Try using new_comment.transfernews = transfernews instead of new_comment.transfernews_id = transfernews.id.
Also change redirect(request.path_info) to redirect(reverse('<app_name>:<url_namespace>')).
You have to add a name attribute to your hidden input, then only the hidden input data will be included in the form data.
<input type="hidden" name="transfer_id" value="{{ transfer.id}}">
and in your transfer_targets view make these changes
def transfer_targets(request):
transfernews = Transfernews.objects.all()
transfernews = request.POST.get("transfer_id", None)
form = CommentForm(request.POST or None)
if form.is_valid():
new_comment = form.save(commit=False)
new_comment.user = User.objects.get(id=request.user.id)
new_comment.transfernews_id = transfernews.id
new_comment.transfernews_id = Transfernews.objects.get(id=transfernews)
new_comment.save()
return redirect(request.path_info)
return render(request, 'transfernews.html', {'transfernews': transfernews, 'form': form})
I have two models with two different forms. One has a ForeignKey for another model, making a 1-N relationship. The problem is when i try to add images , is not working. The form where i change the (name/TabletForm2) is working so , only when i try to add (image/TabletFormImagem) is not working.
The problem is that
My model's
def get_image(instance, filename):
return os.path.join('intervencao/fotografias', str(instance.intervencao), filename)
class Intervencao(models.Model):
name= models.CharField(verbose_name="Name", max_length=200, blank=True, null=True)
class Imagem(models.Model):
intervencao = models.ForeignKey(Intervencao, related_name='intervencaoObjectsImagem', on_delete=models.CASCADE)
imagem = models.ImageField(upload_to=get_image, blank=True, null=True, verbose_name="Fotografia")
def __str__(self, ):
return str(self.intervencao)
My View
def project_detail_chefe(request, pk):
form = TabletForm2(request.POST)
form2 = TabletFormImagem(request.POST, request.FILES)
if request.method == "POST":
if form.is_valid():
form.save()
return redirect('index')
else:
form = TabletForm2(request.POST)
if form2.is_valid():
//when i print something here to see if the form2 is valid , never enter here.
form2.save()
return redirect('index')
else:
form2 = TabletFormImagem()
context = {
'form':form,
'form2':form2,
}
return render(request, 'tablet/info_chefes.html', context)
tablet/info_chefes.html
<div class="col-md-12">
<div class='form-group'>
<label for="{{ form.subject.id_for_label }}" id="titulo">Name:</label>
<em>{{ form.name}}</em>
</div>
</div>
<div class="col-md-12">
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form2.as_p }}
<button type="submit">Upload</button>
</form>
</div>
Forms
class TabletForm2(forms.ModelForm):
class Meta:
model=Intervencao
fields = ['data_intervencao_fim','ferramenta']
class TabletFormImagem(forms.ModelForm):
class Meta:
model=Imagem
fields = ['imagem']
def project_detail_chefe(request, pk):
form = TabletForm2()
form2 = TabletFormImagem()
if request.method == "POST":
form = TabletForm2(request.POST)
form2 = TabletFormImagem(request.POST, request.FILES)
if form.is_valid() and form2.is_valid():
instance_form1 = form.save()
instance_form2 = form2.save(commit=False)
instance_form2.intervencao = instance_form1
instance_form2.save()
return redirect('index')
else:
form = TabletForm2()
form2 = TabletFormImagem()
context = {
'form':form,
'form2':form2,
}
return render(request, 'tablet/info_chefes.html', context)
HTML
<form method="post" enctype="multipart/form-data">
<div class="col-md-12">
<div class='form-group'>
<label for="{{ form.subject.id_for_label }}" id="titulo">Name:</label>
<em>{{ form.name}}</em>
</div>
</div>
<div class="col-md-12">
{% csrf_token %}
{{ form2.as_p }}
<button type="submit">Upload</button>
</div>
</form>
I have an image upload function in django. However, images cannot be uploaded. The page is redirected to successURL. I don't understand the cause.
The view is current because it uses multiple forms.
#view
def UserEdit(request):
if request.method == 'POST':
form = forms.UserUpdateForm(request.POST, instance=request.user)
subform = forms.ProfileUpdateForm(request.POST, instance=request.user.profile)
if all([form.is_valid(), subform.is_valid()]):
user = form.save()
profile = subform.save()
return redirect('person:myaccount', username=request.user)
else:
form = forms.UserUpdateForm(instance=request.user)
subform = forms.ProfileUpdateForm(instance=request.user.profile)
return render(request, 'accounts/accounts_edit.html', {
'form': form,
'subform': subform,
})
#form
class UserUpdateForm(forms.ModelForm):
#...
class ProfileUpdateForm(forms.ModelForm):
class Meta:
model = profile
fields = ('first_name','last_name','birthday','image',)
#model
class profile(models.Model):
image = models.ImageField(upload_to='profile/',default='profile/default.jpg')
#html
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
<div class="text-center col-lg-6 col-md-6 col-sm-10 mx-auto">
<div class="form-group">
{{ form }}
</div>
<div class="form-group">
{{ subform }}
</div>
<button type="submit" class="fadeIn fourth btn btn-light">Submit</button>
</div>
</form>
I am trying to fill out a form in my Django web application and post it. It is giving me an error
object Application has no attribute cleaned_data
I looked around Stack Overflow at similar questions, but the resolutions for others are not issues with my code. Here is my view:
def single_career(request, a_slug):
a_slug = a_slug.strip('/')
try:
career = Career.objects.get(slug=a_slug)
except:
career = None
if request.method == "POST":
form = Application(request.POST, request.FILES)
Post = True
if form.is_valid():
cleaned_data = Application.cleaned_data
is_valid = True
clean_first = cleaned_data['first_name']
clean_last = cleaned_data['last_name']
clean_email = cleaned_data['email']
clean_phone = cleaned_data['phone']
clean_file = cleaned_data['resume']
clean_message = cleaned_data['message']
date = datetime.datetime.now()
else:
is_valid = False
else:
form = Application()
Post = False
is_valid = False
context = {'career': career, 'form': form, 'post': Post, 'is_valid': is_valid}
template = 'overrides/careers.html'
set_detail_context(request, context)
return render_to_response(template, context, context_instance=RequestContext(request))
the html:
<form action="" method="POST" enctype="multipart/form-data" class="application-form">
{% csrf_token %}
<div class="firstname">
<p>FIRST NAME</p>
{{ form.first_name }}
</div>
<div class="lastname">
<p>LAST NAME</p>
{{ form.last_name }}
</div>
<div class="email">
<p>EMAIL</p>
{{ form.email }}
</div>
<div class="phone">
<p>PHONE</p>
{{ form.phone }}
</div>
{# form fileupload-input is hidden, and extra readonly text-input is there #}
{# to be able to override the styling of the fileupload-input button #}
<div>
<p>ATATCH PDF RESUME</p>
<input class="readonly" type="text" READONLY>
<div class="resume">
{{ form.resume }}
<div>
<a id="browse">BROWSE</a>
</div>
</div>
</div>
<div>
<p>MESSAGE</p>
{{ form.message }}
</div>
<button class="submit-button" type="submit">
APPLY
</button>
</form>
and the form class:
from django import forms
class Application(forms.Form):
first_name = forms.CharField(label="First Name", max_length=50)
last_name = forms.CharField(label="Last Name", max_length=50)
email = forms.EmailField(label="Email", max_length=80)
phone = forms.CharField(label="Phone Number", max_length=30)
resume = forms.FileField(label="Resume", max_length=1000)
message = forms.CharField(label="Message", max_length=800, widget=forms.Textarea)
The validated form is form, not Application.
The cleaned_data belongs to the form instance. You should have:
if form.is_valid():
cleaned_data = form.cleaned_data
You are getting the error because you are trying to fetch it from the form class.
if form.is_valid():
cleaned_data = Application.cleaned_data