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())
Related
These are my models
class Post(models.Model):
title = models.TextField(default="no title")
body = models.TextField(default="no body")
creation_date = models.DateTimeField(default=timezone.now)
creator = models.ForeignKey(User, on_delete=models.CASCADE)
document = models.FileField(upload_to="uploads/", null=True, blank=True)
the one that isn't working is document, i have set up a form and when i "post" the form the other stuff like title ,body, creation date and creator are being saved but the document isn't, cant even find it in any folder
this is my view
class Post_List(LoginRequiredMixin, View):
def get(self, request, *args, **kwargs):
posts = Post.objects.order_by("-creation_date")
form = PostForm()
context = {
"post_list" : posts,
"form" : form,
}
return render(request, 'social/post_list.html', context)
def post(self, request, *args, **kwargs):
posts = Post.objects.order_by('-creation_date')
form = PostForm(request.POST, request.FILES)
if form.is_valid():
new_post = form.save(commit=False)
new_post.creator = request.user
new_post.save()
context = {
'post_list': posts,
'form': form,
}
return redirect('/feed')
my html
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{ form | crispy }}
<div class="form-group">
<button class="btn btn-success mt-3 mb-3 float-end" type="submit">Send</button>
</div>
</form>
I tried migrating again but nothing changed
i had no space between method="POST" and enctype="multipart/form-data", fixed it when i pasted the html here, i tested again and it works now
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>
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>
I am trying to update a userprofile model that i used to save additional information over the inbuilt User model, now when i am trying to update it , the image does not gets saved. I need help to resolve this issue
# In views.py
#login_required(login_url=LOGIN_REDIRECT_URL)
def update_user_profile(request):
userobj = get_object_or_404(UserProfile, user=request.user)
form = UserProfileForm(data = request.POST or None,files= request.FILES or None, instance=userobj)
if request.method=='POST':
print(form.is_valid())
if form.is_valid():
profile = form.save(commit=False)
profile.picture = form.cleaned_data['picture']
profile.about = form.cleaned_data['about']
profile.save()
else:
print("NO picure")
return HttpResponseRedirect("/blog/profile/")
return render(request, "blog/post_update.html", {'form':form})
#models.py
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
about = models.CharField(max_length=200, null=True, blank=True)
picture = models.ImageField(upload_to="profile_images/", blank=True)
def __str__(self):
return str(self.user)
#In forms.py
class UserProfileForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(UserProfileForm, self).__init__(*args, **kwargs)
self.fields['about'].widget.attrs.update({'class': 'form-control '})
self.fields['picture'].widget.attrs.update({'class': 'form-control-file'})
class Meta:
model = UserProfile
fields = ('about', 'picture')
# userprofileform.html
{% extends 'base.html' %}
{% block content %}
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" class="btn btn-primary" value="Create Profile">
</form>
{% endblock %}
please take a look at the code and help. while registering if the image was uploaded it get's saved , but when i try to update the userprofile directly in profile section image does not get changed and shows the same as one saved while user registration else it shows None.
I did some changes on templates in settings.py and got my project runnning. Issue was that i was not mentioning the Templates directory properly
I'm trying to create a form in Django template but it is just not showing the fields
here is my files
models.py where i created the desired table
class ReportMessage(models.Model):
sender = models.ForeignKey(UserModel, related_name="report_message_sender", on_delete='CASCADE')
message = models.ForeignKey(Message, on_delete='CASCADE')
created_at = models.DateTimeField(auto_now=True)
reason = models.TextField(max_length=1500)
is_read = models.BooleanField(default=False)
forms.py where i created the form to edit only one field in the table
class ReportMessageForm(forms.Form):
class Meta:
model = ReportMessage
fields = ['reason', ]
views.py where i created the view for the form
#login_required
def report_message(request, pk):
current_user = request.user
reported_message = get_object_or_404(Message, pk=pk)
if request.method == "POST":
report_message_form = ReportMessageForm(request.POST)
if report_message_form.is_valid():
model_instance = report_message_form.save(commit=False)
model_instance.sender = current_user
model_instance.message = reported_message
model_instance.save()
return redirect('report_confirm')
else:
report_message_form = ReportMessageForm()
context = {
'report_message_form': report_message_form,
}
return render(request, 'fostania_web_app/report_message.html', context)
def report_confirm(request):
return render(request, 'fostania_web_app/report_confirm.html')
and urls.py where the urls i used for the views
path('report/messages/<int:pk>/', views.report_message, name="report_message"),
path('report/confirm', views.report_confirm, name="report_confirm"),
and finally that is how i used the form in the html template
{% extends 'fostania_web_app/base.html' %}
{% block content %}
{% load static %}
<form action="" method="post" name="ReportMessageForm" align="right">
{% csrf_token %}
{{ report_message_form }}
<input type="submit" class="btn btn-success" style="width: 100px;" value="إرسال" />
</form>
{% endblock %}
and then all what i see in the html page is the submit button and there is no form labels or input or anything.
In your forms.py if you are not using ModelForm then you have to explicitly declare the fields for the forms
reason = forms.Charfield()
Or you can use ModelForm which inherits from the model you specify.
You should specify the model in the Meta class while using ModelForm.You can also specify required fields from the Model in the fields list in Meta class
Class myform(forms.ModelForm)
Class Meta:
model = your_model_name
fields= [reason,]
Cheers
:)
I think that your problem is in your model form because you are using forms.Form and you need to use forms.ModelForm
class ReportMessageForm(forms.ModelForm):
class Meta:
model = ReportMessage
fields = ['reason', ]
def report_confirm(request):
return render(request, 'fostania_web_app/report_confirm.html', context) #add the context
You need to pass in the "context" so that it shows in the template