Submit form post from another view with input field - python

I am relatively new to Django and I'm making a small "social" project. It basically consists of user profiles, and on those profiles you can post "comments".
I have a view that displays the comments each user has, and a separate view that allows you to post comments. This works as expected.
The problem I am facing right now is the following. - I have an < input type=text > field in the view to view comments, and I want to be able to post a comment from there and have it saved in the database. I have tried grabbing the post kwargs in the form, but I couldn't get it to work correctly nonetheless have it save automatically. How can I get this done?
Here is the code that I have so far.
Comments view:
class CommentsView(auth_mixins.LoginRequiredMixin, views.ListView):
model = ProfileComments
template_name = 'comments/comments_view.html'
paginate_by = 5
def get_queryset(self):
receiver = PROFILE_MODEL.objects.get(pk=self.kwargs['pk'])
if receiver:
return self.model.objects.filter(receiver=receiver)
return None
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
receiver = PROFILE_MODEL.objects.get(pk=self.kwargs['pk'])
if receiver:
context.update({
'receiver': receiver
})
return context
View to post comments:
class CreateCommentView(auth_mixins.LoginRequiredMixin, views.CreateView):
form_class = CommentsForm
template_name = 'comments/post_comment.html'
#staticmethod
def get_profile_model_by_pk(pk):
return PROFILE_MODEL.objects.get(pk=pk)
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs['author'] = self.request.user.userprofile
kwargs['receiver'] = self.get_profile_model_by_pk(self.kwargs['pk'])
return kwargs
def get_success_url(self):
return reverse_lazy('comments', kwargs={'pk': self.kwargs['pk']})
And this is the template for viewing comments, here is the code for the input I'm using:
<div style="width: 1310px ;margin: 0 auto">
<form class="col-12 col-lg-auto mb-3 mb-lg-0 me-lg-3"
method="POST" action="{% url 'post comment' pk=receiver.pk %}">
{% csrf_token %}
<input type="text" name="post_comment_text"
class="form-control" placeholder="Leave a comment" aria-label="Leave a comment">
</form>
</div>

Related

Django - problem with writing to database

I have a problem, the urls form works but I can't see the records in url/admin, can I ask for help, thank you :D
SOF wants me to add more details otherwise it doesn't transfer, I don't know what more I can add, generally temapals and urls work.
class Note(models.Model):
"""..."""
notes = models.CharField(max_length=100, unique=True)
description = models.TextField()
class Meta:
verbose_name = "Note"
verbose_name_plural = "Notes"
def __str__(self):
return self.notes
class NoteView(View):
def get(self, request):
if request.method == 'POST':
textN = Note.objects.all().order_by('notes')
form = NoteAddForm(request.POST)
if form.is_valid():
form.save()
return redirect('Files/menu')
else:
textN = NoteAddForm()
return render(request, 'Files/note.html', {'textN': textN})
class NoteAddForm(forms.ModelForm):
"""New note add form"""
class Meta:
model = Note
fields = '__all__'
{% extends 'Files/base.html' %}
{% block title %}Notatnik{% endblock %}
<h2>Notatnik Dietetyka/ Zalecenia ręczne </h2>
{% block content %}
<form action="/send/" method="post">
{% csrf_token %}
{{ textN }}
<label>
<input type="text" class="btn btn-second btn-lg">
<button>Wyślij formularz</button>
</label>
</form>
<button type="button" class="btn btn-primary btn-lg">Powrót</button>
{% endblock %}
Within your NoteView class in views.py file is where the issue is.
I see you have an if statement checking for if request.method == 'POST' within the class-based view get(). The get() is equivalent to if request.method == 'GET'. Therefore, what you might want to do is to override the post() on the class instead. For example:
class NoteView(View):
template_name = 'Files/note.html'
# Use the get method to pass the form to the template
def get(self, request, *arg, **kwargs):
textN = NoteAddForm()
return render(request, self.template_name, {'textN': textN})
# Use the post method to handle the form submission
def post(self, request, *arg, **kwargs):
# textN = Note.objects.all().order_by('notes') -> Not sure why you have this here...
form = NoteAddForm(request.POST)
if form.is_valid():
form.save()
# if the path is... i.e: path('success/', SucessView.as_view(), name='success')
return redirect('success') # Redirect upon submission
else:
print(form.errors) # To see the field(s) preventing the form from being submitted
# Passing back the form to the template in the name 'textN'
return render(request, self.template_name, {'textN': form})
Ideally, that should fix the issue you're having.
Updates
On the form, what I'd suggest having is...
# Assuming that this view handles both the get and post request
<form method="POST"> # Therefore, removing the action attribute from the form
{% csrf_token %}
{{ textN }}
# You need to set the type as "submit", this will create a submit button to submit the form
<input type="submit" class="btn btn-second btn-lg" value="Submit">
</form>

Django Register Form redirecting to same url

i am new to django i have created a user registration form but when i click on submit it does nothing and just goes to the same page i am not under standing what i did wrong here
views.py:
class RegisterPage(FormView):
template_name = "main/register.html"
form_class = RegisterForm
success_url = reverse_lazy('blog_list')
def form_valid(self, form):
user = form.save()
if user is not None:
login(self.request, user)
return super(RegisterPage, self).form_valid(form)
def get(self, *args, **kwargs):
if self.request.user.is_authenticated:
return redirect("blog_list")
return super(RegisterPage, self).get(*args, **kwargs)
forms.py:
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
class RegisterForm(UserCreationForm):
bio = forms.CharField(max_length=400, empty_value="Max Length 400")
image = forms.ImageField()
class Meta:
model = User
fields = ["username", "image", "password1", "password2", "bio"]
register.html:
{% extends "main/main.html" %}
{% block title %}Create an Account{% endblock %}
{% block content %}
<div class="form">
<h1>Register</h1>
<form method="post">
{% csrf_token %}
<label>{{form.username.label}}</label>
{{form.username}}
<br>
<label>{{form.password1.label}}</label>
{{form.password1}}
<br>
<label>{{form.password2.label}}</label>
{{form.password2}}
<br>
<label>{{form.image.label}}</label>
{{form.image}}
<br>
<label>{{form.bio.label}}</label>
{{form.bio}}
<br>
<input style="margin-top: 10px" class="button" type="submit" value="Register"/>
</form>
<p>Already Have An Account Login</p>
</div>
{% endblock content %}
in the views.py i have also tried form_class = UserCreationForm the built in django creation form but still the same result so what is wrong
you're posting the form back but you've only implemented a get method:
def get(self, *args, **kwargs):
if self.request.user.is_authenticated:
return redirect("blog_list")
return super(RegisterPage, self).get(*args, **kwargs)
And on the form html you're saying use POST <form method="post"> which is correct, and is the prefered way to send information you don't want to be sent in the URL. For example if you used <form method="get"> you code might work, but you'd also be sending the contents of the form in the url. Post sends it in the body, so if you use https on your server only you and the browser see it.
TO MAKE POST work you need to (add)
def post(self, *args, **kwargs):
#check the form do the redirect
As you didn't have an action on the form it defaults to submitting to the current url.
You need both get and post, as get will load the form post is how you're sending it back.

Returning httpresponse with queryset for ListView after post in Django

I have a listview with formmixin after submitting the form I was trying to return the exact same view with some extra messages, but I havent been able to return the query set, hence the list is not appearing,
Can anyone pls help me.
Views.py
class NewsletterList(FormMixin, generic.ListView):
queryset = newsletter.objects.filter(status=1).order_by('-created_on')
template_name = 'newsletterlist.html'
form_class = SubscriberForm
def post(self, request, *args, **kwargs):
form = SubscriberForm(request.POST)
if form.is_valid():
sub = Subscriber(email=request.POST['email'], conf_num=random_digits())
sub.save()
return render(request, 'newsletterlist.html', {'form': SubscriberForm()})
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['newsletter_list'] = newsletter.objects.filter(status = 1)
return context
HTML
{% for newsletter in newsletter_list %}
<a href="{{newsletter.slug}}" class="d-flex justify-content-between list-group-item list-group-item-action">
<span class=""><b>{{ newsletter.title }}</b> - {{newsletter.catchy_line|slice:":200" }}</span>.
<span class="">{{ newsletter.datepublished}}</span>
</a>
{% endfor %}
Thanks in advance
try
queryset = Newsletter.objects.filter(status=1).order_by('-created_on')
spelling problem

How can i use more different forms in the same Django template?

In my project, i have a template where i'm trying to put two forms for different use cases. I've never come across this problem before, so i don't really know where to go from here to use two forms in the same page.
At first i thought of creating another view to handle each form, but i think that this solution would create problems with the rendering of my templates, other than not being sustainable if i should have this problem again with another template.
After making some research, i found a solution but it works for class based views, but i'd like to avoid that since my view is already a function based view, and i would have to make a lot of changes in my code.
Would it be possible to solve this problem with a function based view? Every advice is appreciated
First field
class FirstForm(forms.ModelForm):
firstfield = forms.CharField()
secondfield = forms.CharField()
class Meta:
model = MyModel
fields = ("firstfield", "secondfield")
def save(self, commit=True):
send = super(FirstForm, self).save(commit=False)
if commit:
send.save()
return send**
Second Form
class SecondForm(forms.ModelForm):
firstfield = forms.FloatField()
secondfield = forms.Floatfield()
thirdfield = forms.CharField()
class Meta:
model = MyModelTwo
fields = ("firstfield", "secondfield", "thirdfield")
def save(self, commit=True):
send = super(SecondForm, self).save(commit=False)
if commit:
send.save()
return send
Template
<h3> First Form </h3>
<form method="post" novalidate>
{% csrf_token %}
{% include 'main/includes/bs4_form.html' with form=form %}
<button type="submit" class="btn btn-danger" style="background-color: red;">SUBMIT</button>
</form>
<h3> Second Form </h3>
<form method="post" novalidate>
{% csrf_token %}
{% include 'main/includes/bs4_form.html' with form=form %}
<button type="submit" class="btn btn-danger" style="background-color: red;">SUBMIT</button>
</form>
EDIT: my view:
def myview(request):
# if this is a POST request we need to process the form data
if request.method == 'POST':
# create a form instance and populate it with data from the request:
form = FirstForm(request.POST)
# check whether it's valid:
if form.is_valid():
# process the data in form.cleaned_data as required
# ...
# redirect to a new URL:
send = form.save()
send.save()
messages.success(request, f"Success")
# if a GET (or any other method) we'll create a blank form
else:
form = FirstForm()
return render(request,
"main/mytemplate.html",
context={"form":form})
This answer is a bit general because you haven't included your view function. You can add each of these forms to your view's context. Something like this:
views.py
...
from .forms import FirstForm, SecondForm
...
def some_view(request):
context = {
'first_form': FirstForm(request.POST or None),
'second_form': SecondForm(request.POST or None)
}
return render(request, "app/some_template.html", context)

Create form from related models

I have 2 models, Message and Attachment.
I want to use these in one form. The Attachment should have a reference to the message (a message can have more than 1 attachment).
Models:
class Message(models.Model):
createdby = models.ForeignKey(User)
subject = models.CharField(max_length=200, null=True)
body = models.TextField(default=None, blank=True)
class Attachment(models.Model):
docfile = models.FileField(upload_to='documents/%Y/%m/%d')
message = models.ForeignKey(Message, null=True)
Forms
class MessageForm(forms.ModelForm):
class Meta:
model = Message
AttachmentFormSet = inlineformset_factory(Message, Attachment, extra=1 )
Views
class MessageCreateView(CreateView):
model = Message
fields = ["subject", "body"]
form_class = MessageForm
success_url = 'success/'
def get(self, request, *args, **kwargs):
"""
Handles GET requests and instantiates blank versions of the form
and its inline formsets.
"""
self.object = None
form_class = self.get_form_class()
form = self.get_form(form_class)
attachment_form = AttachmentFormSet()
return self.render_to_response(
self.get_context_data(form =form,
attachment_form=attachment_form,
))
def post(self, request, *args, **kwargs):
"""
Handles POST requests, instantiating a form instance and its inline
formsets with the passed POST variables and then checking them for
validity.
"""
self.object = None
form_class = self.get_form_class()
form = self.get_form(form_class)
attachment_form = AttachmentFormSet(self.request.POST)
if (form.is_valid() and attachment_form.is_valid()):
return self.form_valid(form, attachment_form)
else:
return self.form_invalid(form, attachment_form)
def form_valid(self, form, attachment_form):
"""
Called if all forms are valid. Creates a Message instance along with
associated Attachment then redirects to a success page.
"""
self.object = form.save()
attachment_form.instance = self.object
self.object = attachment_form.save()
return HttpResponseRedirect(self.get_success_url())
I tried many things, but for some reason the Attachment is never saved. There must be something missing in the form_valid() function, but I can't figure out what.
For completeness, here also the template:
<script type="text/javascript">
$(function() {
$(".inline.{{ attachment_form.prefix }}").formset({
prefix: "{{ attachment_form.prefix }}"
})
});
</script>
<form class="" action="/bugtrack/project/{{ project_id }}/tickets/{{ ticket_id }}/replyform/" method="post" id="replyform">
{% csrf_token %}
{{ form |crispy }}
{{ attachment_form.management_form }}
{% for formattach in attachment_form %}
{{ formattach.id }}
<div class="inline {{ attachment_form.prefix }}">
{{ formattach.docfile }}
</div>
{% endfor %}
<button class="btn btn-info pull-right btn-sm" type="submit" name="submit" value="createReply">Submit</button>
</form>
What would be the correct way to save the Message and Attachment correctly?
I don't think you're saving the attachment_form. You're just converting it to a variable. Note that in the tutorial, the writer called the .save() for each form. Try:
def form_valid(self, form, attachment_form):
"""
Called if all forms are valid. Creates a Message instance along with
associated Attachment then redirects to a success page.
"""
self.object = form.save()
attachment_form.instance = self.object
attachment_form.save()
return HttpResponseRedirect(self.get_success_url())

Categories