Django - update model with user input by id - python

I stuck with my first app in Django.
Basically it will be several objects on webpage, every object with input form. If user types and email address to input, this object should be marked as 'reserved'.
I tried several solutions (and problably because of this multi-solution none of them worked). At the beggining I used AJAX to update the status of the object and it worked, but when I implemented email address input it failed. So I found out that I should give up on AJAX and go after ModelForm.
So for now my not-working code is looking like this:
urls.py
urlpatterns = [
url(r'^$', views.index),
url(r'^occupy/$', views.occupy, name='occupy'),
index.html
{% for gift in gifts %}
<div class="panel-heading">
<h2 class="panel-title"> {{ gift.name }}</h2>
</div>
<div class="panel-body">
{{ gift.link }}
<form role="form" action="" method="POST">
{% csrf_token %}
{{ form }}
<input type="submit" value="szukaj" name='q' data-id="{{ gift.id }}">
</form>
</div>
{% endfor %}
models.py
class Gift(models.Model):
name = models.CharField(max_length=100)
link = models.URLField(max_length=100)
email = models.EmailField(blank=True, default='')
occupied = models.BooleanField(default=0)
forms.py
class ContactForm(forms.ModelForm):
class Meta:
model = Gift
fields = ('email',)
views.py
def index(request, id):
gifts = Gift.objects.all()
form_class = ContactForm()
if request.method == 'POST':
occupy(request)
def occupy(request):
print('hrj')
gift_id = request.GET.get('gift_id', None)
if (gift_id):
gift = Gift.objects.get(id=int(gift_id))
I guess that this parts are ok, but I am missing data flow (emails and ids).
Any help will be very appreciated.

Related

why my submit input isn't working in django?

I have a form so an user can ask for a loan and it will tell them if it´s approved or not. The problem is not the logic, it´s the submit input that doesn't work. It will not save the form in the database or show me the errors because of the submit input. Maybe is something wrong with the succes_url? I don't know, but here's my code:
views.py:
#don't worry about the logic part of the form, it's just to show how it´s supposed to work
class LoanRequest(LoginRequiredMixin, generic.CreateView):
form_class = LoanForm
success_url = reverse_lazy('Prestamos')
template_name = 'Prestamos/template/Prestamos/prestamos.html'
def form_valid(self, form):
user = self.request.user
cliente = Cliente.objects.get(user_id = user.id)
if not cliente.approve_loan(form.cleaned_data.get('loan_total')):
form.add_error(field=None, error='loan not approved')
return self.form_invalid(form)
else:
form.instance.customer_id = cliente
super(LoanRequest, self).form_valid(form)
return render(self.request, 'Prestamos/template/Prestamos/prestamos.html', context={'form': form, 'success_msg': 'loan approved!'})
urls.py:
urlpatterns = [
path('prestamos/', views.LoanRequest.as_view(), name = 'prestamos'),
]
forms.py:
class LoanForm(forms.ModelForm):
class Meta:
model = Prestamo #loan in English
fields = ['loan_type', 'loan_total', 'loan_date']
and the template:
<div class="container">
{%if success_msg%}
<p class="alert alert-success">{{success_msg}}</p>
{%endif%}
<form action="" method="POST">
{%csrf_token%}
{%for field in form%}
<div class="form-group">
<label for="{{field.label}}">{{field.label}}</label>
{{field}}
</div>
{%for error in field.errors%}
<p>{{error}}</p>
{%endfor%}
{%endfor%}
<input type="submit" value="request"></input>
</form>
</div>
models.py:
class Prestamo(models.Model):
loan_id = models.AutoField(primary_key=True)
loan_type = models.CharField(max_length=20,
choices = [('PERSONAL', 'PERSONAL'), ('HIPOTECARIO', 'HIPOTECARIO'), ('PRENDARIO', 'PRENDARIO')])
loan_date = models.DateField()
loan_total = models.IntegerField()
customer_id = models.IntegerField()
class Meta:
db_table = 'prestamo'
Well, <input> is an empty tag, it does not contain anything, so don't close it.
Additionally, I'd recommend you to make gaps between template tags, like it should be {% endfor %} not {%endfor%}.
Also, remove the empty action attribute from form, as Django always take current page route if not mentioned or empty string.
Also use novalidate on form for rendering custom errors.
Try this template:
<div class="container">
{% if success_msg %}
<p class="alert alert-success">{{success_msg}}</p>
{% endif %}
<form method="POST" novalidate>
{% csrf_token %}
{% for field in form %}
<div class="form-group">
<label for="{{field.label}}">{{field.label}}</label>
{{field}}
</div>
{% for error in field.errors %}
<p>{{error}}</p>
{% endfor %}
{% endfor %}
<input type="submit" value="request">
</form>
</div>
Edit:
One mistake I could see the name for the view is prestamos and you have mentioned it as Prestamos, which is wrong.
So:
class LoanRequest(LoginRequiredMixin, generic.CreateView):
form_class = LoanForm
success_url = reverse_lazy('prestamos')
template_name = 'Prestamos/template/Prestamos/prestamos.html'

Getting id of instance in form and save in it

I am building a Blog App and I am working on a feature in which A user can report comment so I created another model for storing reports so i am saving which comment is reported But I placed report form in detail view so report form will be below the comment in post detail page, In which I am not getting the comment id when reporting.
models.py
class Blog(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
title = models.CharField(max_length=1000)
class Comment(models.Model):
commented_by = models.ForeignKey(User, on_delete=models.CASCADE)
body = models.CharField(max_length=1000)
class ReportComment(models.Model):
reported_by = models.ForeignKey(User, on_delete=models.CASCADE)
reported_comment = models.ForeignKey(Comment, on_delete=models.CASCADE)
text = models.CharField(max_length=1000)
views.py
def blog_detail_page(request, blog_id):
post = get_object_or_404(Blog, pk=blog_id)
if request.method == 'POST':
reportform = CommentReportForm(data=request.POST)
if FlagCommentForm.is_valid():
form = reportform.save(commit=False)
# Saving in this line
flagForm.reported_comment = reportform.id
form.reported_by = request.user
form.save()
return redirect('home')
else:
reportform = CommentReportForm()
context = {'reportform':reportform, 'post':post}
return render(request, 'blog_detail_page.html', context)
blog_detail_page.html
{{post.title}}
{% for comment in post.comment_set.all %}
{{comment.body}}
<div class="container">
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
<table>
{{ reportform }}
</table>
<button type="submit">Save</button>
</form>
</div>
{% endfor %}
What have I tried :-
I have also tried by using loop like :-
comments = post.comment_set.all()
for com in comments:
if request.method == 'POST':
......
if reportform.is_valid():
....
......
......
form.reported_by = com
But it always saved the first comment id.
Then I tried by request.POST method, Like :-
comment_ID = request.POST['comment_id']
But is showed MultiValueDictKeyError error.
I have tried many times But the id of comment is not saving with report instance.
You will need to add the primary key of the comment to the form, or to the URL where you submit the form to. For example as a hidden form element:
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
<input type="hidden" name="comment_id" value="{{ comment.pk }}">
<table>
{{ reportform }}
</table>
<button type="submit">Save</button>
</form>
An alternative is to make a URL where you report a comment to with:
urlpatterns = [
path('comment/<int:comment_id>/report', some_view, name='report-comment')
]
then you can submit the form to that view with:
<form method="post" action="{% url 'report-comment' comment_id=comment.pk %}" enctype="multipart/form-data">
{% csrf_token %}
<table>
{{ reportform }}
</table>
<button type="submit">Save</button>
</form>

How to dynamically update form data in django

I am new to django and I am trying to create a review system, whereby each team member reviews all the other members within their team.
Here is my models.py file:
from django.db import models
from django.contrib.auth.models import User
class Team(models.Model):
name = models.CharField(max_length=25)
def __str__(self):
return self.name
class Trait(models.Model):
name = models.CharField(max_length=25)
def __str__(self):
return self.name
class Review(models.Model):
reviewer = models.ForeignKey(User, on_delete=models.CASCADE,
related_name='reviewer_id')
reviewee = models.ForeignKey(User, on_delete=models.CASCADE,
related_name='reviewee_id')
trait = models.ForeignKey(Trait, on_delete=models.CASCADE)
trait_score = models.IntegerField()` return
This is my views.py file:
from django.shortcuts import render, redirect
from review.forms import ReviewForm
from django.http import HttpResponse
from django.contrib.auth.models import User
from accounts.models import UserProfile
def positivity_review(request):
if request.method == 'POST':
form = ReviewForm(request.POST)
if form.is_valid():
form.save()
return redirect('/review/relationships')
else:
form = ReviewForm()
users = UserProfile.objects.filter(review_team=1)
args = {'form': form, 'team_members': users}
return render(request, 'review/positivity.html', args)` return
This is my forms.py file:
from django import forms
from django.forms.widgets import NumberInput
from review.models import Team, Review
class RangeInput(NumberInput):
input_type = 'range'
class ReviewForm(forms.ModelForm):
trait_score = forms.IntegerField(widget=RangeInput, min_value=0,
max_value=100, label='')
class Meta:
model = Review
fields = (
'trait_score',
)` return
This is the HTML file:
{% extends 'base.html' %}
{% block head %}
<title>Review</title>
{% endblock %}
{% block content %}
<br>
<h1>Review</h1>
<h2>Do they foster a postive climate?</h2>
<div class="row">
<div class="col-md-2">
<p>Exhibits a lack of awareness for a positive climate. Resistance to prompting.</p>
</div>
<div class="col-md-2">
<p>Cooperates at times, within structured activities and friendly under prompting.</p>
</div>
<div class="col-md-2">
<p>Cooperates within the team environment without prompting.</p>
</div>
<div class="col-md-2">
<p>Cooperates well with others, enthusiastic and positve. Occationally prompts others to engage positively.</p>
</div>
<div class="col-md-4">
<p>Seeks to continuously and consistently create a positive environment. Acts as a role model for the team through prompting being supportive and encouraging and showing genuine concern for others.</p>
</div>
</div>
<div>
<form method="post">
{% for user in team_members %}
<p>Reviewing: {{ user.first_name }} {{ user.last_name }}</p>
{% csrf_token %}
{{ form.as_p }}
{% endfor %}
<button class="btn btn-primary" type="submit">Next</button>
</form>
</div>
{% endblock %}`
Currently I am passing in the queryset through the views.py into the html file and looping through it to load the relevant number of team members.
Since I am loading a form each time for each individual in the team, how can I make the form submit so that it knows who is being reviewed? For example, submitting the reviewer, trait and score is simple as most of that can be passed directly into the view, however, submitting the reviewee (person being reviewed) is the part im not sure how to handle, as they are loaded within the form using the template tagging. I was wondering if it is possible to submit some kind of data back into the form such as first + last name or thier user id, anything so that when I go to publish the results I have a way of filtering individuals results.
Hopefully the description is sufficient. Thanks in advance!
If I understand your question correctly, this might be the answer.
First, create a simple form (rather than ModelForm) and add this, among other things:
pk = forms.CharField(
widget=forms.TextInput(
attrs={
'type': 'hidden',
}
),
label=''
)
This will hold the pk of the reviewee and won't be visible to reviewer.
Then, in the html file, I think you have to generate a separate form for each user rather than only the input (I'm not sure, try it). You can do this:
{% for user in team_members %}
<form method="post" id="review_form_{{user.pk}}">
<p>Reviewing: {{ user.first_name }} {{ user.last_name }}</p>
{% csrf_token %}
{{ form.as_p }}
<button class="btn btn-primary" type="submit">Next</button>
</form>
<script type="text/javascript">
$('#review_form_{{user.pk}}').children('#id_pk').val("{{user.pk}}");
</script>
{% endfor %}
Remember that when django generates a form, each input will have to get an id and django adds id_ to the beginning of the name of the field you create in fields.py
And lastly, when the reviewer submit a form, you can find your reveiwee in views.py this way:
form = ReviewForm(request.POST)
if form.is_valid():
reviewee_id = request.POST.get('pk')
reviewee = User.objects.get(pk=reviewee_id)

How to make add replies to comments in Django?

I'm making my own blog with Django and I already made a Comments system.. I want to add the replies for each comment (like a normal comment's box) and I don't know what to do this is my current models.py comments:
class Comment(models.Model):
post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='comments')
author = models.ForeignKey(User, on_delete=models.CASCADE)
text = models.TextField()
created_date = models.DateField(auto_now_add=True)
parent = models.ForeignKey('self', null=True, related_name='replies')
def __str__(self):
return self.text
and this is the .html where I use the comments
{% for comment in post.comments.all %}
<ul>
{{ comment.text }}
{% for reply in comment.replies.all %}
<li>
{{ reply.text }}
</li>
{% endfor %}
<ul>
{% endfor %}
and apparently It is working but when I try to make a comment in the admin site of Django it forces me to put a "Parent" to each comment (and this is not obligatory beacuse not every comment is a reply) I also don't know how to add the reply "button" in the HTML file. Please help tell me what changes can I do to make a simple comment box with replies . Thanks a lot
I had the same problem and resolved it as follows:
1.
For admin site as mentioned above just set blank=True for parent field. My comment model:
class Comment(models.Model):
post = models.ForeignKey(Post, related_name='comments')
name = models.CharField(max_length=80)
email = models.EmailField(max_length=200, blank=True)
body = models.TextField()
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
# manually deactivate inappropriate comments from admin site
active = models.BooleanField(default=True)
parent = models.ForeignKey('self', null=True, blank=True, related_name='replies')
class Meta:
# sort comments in chronological order by default
ordering = ('created',)
def __str__(self):
return 'Comment by {}'.format(self.name)
remember to run makemigrations and migrate
2.Let's start with views. I'm using the post_detail
view to display the post and its comments. We add a QuerySet to retrieve all parent active comments for this post. After this, we validate the submitted data using the form's is_valid(). If the form is valid we check if submitted data comes from hidden input in replay button form. Next if parent_id exits we create parent object(parent_obj) for replay comment and replay_comment object, then we assign parent_obj to replay_comment.
If parent_obj is equal to None we just proceed with normal comment by creating new_comment object and saving it to the database.
def post_detail(request, post):
# get post object
post = get_object_or_404(Post, slug=post)
# list of active parent comments
comments = post.comments.filter(active=True, parent__isnull=True)
if request.method == 'POST':
# comment has been added
comment_form = CommentForm(data=request.POST)
if comment_form.is_valid():
parent_obj = None
# get parent comment id from hidden input
try:
# id integer e.g. 15
parent_id = int(request.POST.get('parent_id'))
except:
parent_id = None
# if parent_id has been submitted get parent_obj id
if parent_id:
parent_obj = Comment.objects.get(id=parent_id)
# if parent object exist
if parent_obj:
# create replay comment object
replay_comment = comment_form.save(commit=False)
# assign parent_obj to replay comment
replay_comment.parent = parent_obj
# normal comment
# create comment object but do not save to database
new_comment = comment_form.save(commit=False)
# assign ship to the comment
new_comment.post = post
# save
new_comment.save()
return HttpResponseRedirect(post.get_absolute_url())
else:
comment_form = CommentForm()
return render(request,
'core/detail.html',
{'post': post,
'comments': comments,
'comment_form': comment_form})
Simple comment form:
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = ('name', 'email', 'body')
* More about ModelForm
And lastly template. We need to create two forms. One form for comments and the second one for replays. Here you have simple template:
<!-- Comments Form -->
<h2>Add a new comment</h2>
<form action="." method="post">
{{ comment_form.as_p }}
{% csrf_token %}
<button type="submit">Add comment</button>
</form>
<!-- Comment with nested comments -->
{% for comment in comments %}
<div class="comment" style="background-color: powderblue">
<p class="info">{{ comment.name }} | {{ comment.created }}</p>
{{ comment.body|linebreaks }}
{% for replay in comment.replies.all %}
<p class="info">{{ replay.name }} | {{ replay.created }}</p>
<li>{{ replay.body }}</li>
{% endfor %}
<h5>Replay</h5>
<form action="." method="post">
{{ comment_form.as_p }}
{% csrf_token %}
<!-- Hidden input for parent comment.id -->
<input type="hidden" name="parent_id" value="{{ comment.id }}">
<input class="btn btn-primary" type="submit" value="Replay">
</form>
</div>
{% empty %}
<h4>There are no comments yet.</h4>
{% endfor %}
just add some nice css and maybe jquery to have fade in reply comments and that's all.
first Question:parent must be set in admin.
parent = models.ForeignKey('self', null=True, blank=True, related_name='replies')
blank=True can let you don't set parent in admin.
second Question:add comment dynamicly.
<form id="comment-form" method="post" role="form">
{% csrf_token %}
<textarea id="comment" name="comment" class="form-control" rows="4" placeholder="input comment!"></textarea>
<button type="submit" class="btn btn-raised btn-primary pull-right">submit</button>
</form>
$('#comment-form').submit(function(){
$.ajax({
type:"POST",
url:"{% url 'article_comments' article.en_title %}",
data:{"comment":$("#comment").val()},
beforeSend:function(xhr){
xhr.setRequestHeader("X-CSRFToken", $.cookie('csrftoken'));
},
success:function(data,textStatus){
$("#comment").val("");
$(".comment ul").prepend(data);
},
error:function(XMLHttpRequest, textStatus, errorThrown){
alert(XMLHttpRequest.responseText);
}
});
return false;
});
view.py:
print_comment = u"<p>comment:{}</p>".format(text)
if parent:
print_comment = u"<div class=\"comment-quote\">\
<p>\
<a>#{}</a>\
{}\
</p>\
</div>".format(
parent.user.username,
parent.text
) + print_comment
# current comment
html = u"<li>\
<div class=\"comment-tx\">\
<img src={} width=\"40\"></img>\
</div>\
<div class=\"comment-content\">\
<a><h1>{}</h1></a>\
{}\
<p>{}</p>\
</div>\
</li>".format(
img,
comment.user.username,
print_comment,
datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
)
return HttpResponse(html)
models.py
class Comment(models.Model):
author = models.CharField(max_length=100)
comment_field = models.TextField()
date_created = models.DateTimeField(auto_now_add=True)
post = models.ForeignKey('Post', on_delete=models.CASCADE)
reply = models.ForeignKey('Comment', on_delete=models.CASCADE, related_name="replies", null=True)
def __str__(self):
return self.author
views.py
def post_detail(request, slug):
post = Post.objects.get(slug=slug)
if request.method == 'POST':
form = CommentForm(request.POST)
if form.is_valid():
reply_obj = None
try:
reply_id = int(request.POST.get('reply_id'))
except:
reply_id = None
if reply_id:
reply_obj = Comment.objects.get(id=reply_id)
author = form.cleaned_data['author']
comment = form.cleaned_data['comment']
if reply_obj:
Comment(author=author,comment_field=comment, reply=reply_obj, post=post).save()
else:
Comment(author=author,comment_field=comment, post=post).save()
return redirect(reverse('post_detail', args=[post.slug]))
else:
form = CommentForm()
comments = Comment.objects.filter(post=post, reply=None).order_by('-date_created')
context = {
'post':post,
'form':form,
'comments':comments
}
return render(request, 'post_detail.html', context)
template (post_detail.html)
{% for comment in comments %}
{{comment.author}}
{{comment.date_created.date}}
{{comment.comment_field}}
{% for reply in comment.replies.all %}
{{reply.author}}
{{reply.date_created.date}}
{{reply.comment_field}}
{% endfor %}
<a class="text-decoration-none" data-bs-toggle="collapse" href="#collapseExample{{comment.id}}" role="button" aria-expanded="false" aria-controls="collapseExample">
Reply </a>
<div class="collapse" id="collapseExample{{comment.id}}">
<div>
<form action="" method="POST" enctype="multipart/form-data">
{% csrf_token %}
<div class="form-group">
{{ form.author }}
</div>
<div class="form-group mt-md-2">
{{form.comment}}
</div>
<input type="hidden" name="reply_id" value="{{ comment.id }}">
<button class="btn btn-primary mt-md-1" type="submit" value="Reply">Reply</button> </form>
</div>
</div>
<hr>
{% endfor %}
You need to create a field called parent which is a ForeignKey with the Comment model itself.
parent = models.ForeignKey('self' , null=True , blank=True , on_delete=models.CASCADE , related_name='replies')
Also, you can create a property called children in the Comment model which returns all the replies of the comment.
#property
def children(self):
return BlogComment.objects.filter(parent=self).reverse()
For detail explanation of comment and reply system in django you can read my article about that.

How can I get data from a form model into a database in Django

I am trying to get data from a model form and then put it into a database. I have figured out how to make the form, but when clicking the submit button it doesn't seem to be put anywhere in my database. Am I doing anything wrong or am I not looking in the correct place in the database.
forms.py
from django import forms
from sxsw.models import Account
class AccountForm(forms.ModelForm):
class Meta:
model = Account
fields = ['firstName', 'lastName', 'email']
views.py
from django.shortcuts import render
from django.shortcuts import redirect
from .forms import AccountForm
from .models import Account
def sxsw(request):
if request.method == 'POST':
form = AccountForm(request.POST)
if form.is_valid():
form.save()
else:
print form.errors
else:
form = AccountForm()
return render(request, 'sxsw/sxsw.html', {'form': form})
def formSubmitted(request):
return render(request, 'sxsw/formSubmitted.html',{})
models.py
from __future__ import unicode_literals
from django.db import models
# Create your models here.
class Account(models.Model):
firstName = models.CharField(max_length = 50)
lastName = models.CharField(max_length = 50)
email = models.EmailField()
def __unicode__(self):
return self.firstName
class Module(models.Model):
author = models.ForeignKey(Account, on_delete = models.CASCADE)
nameOfModule = models.CharField(max_length = 150) #arbitrary number
moduleFile = models.FileField(upload_to = 'uploads/')#Not exactly sure about the upload_to thing
public = models.BooleanField()
def __unicode__(self):
return self.nameOfModule
sxsw.html
{% extends "base.html" %}
{% block content %}
<div class="container-fluid">
<div class="jumbotron text-center">
<h3>SXSW Form</h3>
</div>
</div>
<div align="center">
<h1>New Form</h1>
<form role='form' action="/sxsw/formSubmitted/" method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Submit</button>
</form>
</div>
</div>
{% endblock %}
formSubmitted.html
{% extends "base.html" %}
{% block content %}
<div class="container-fluid">
<div class="jumbotron text-center">
<h3>Form Successfully submitted</h3>
</div>
</div>
<div align="center">
Submit Another Response
</div>
</div>
{% endblock %}
Your form is posting to what I presume is the wrong url
<form role='form' action="/sxsw/formSubmitted/" method="post">
should use the url for the sxsw view
<form role='form' action="/sxsw/" method="post">
Once submitted, you'll likely want to redirect to the submitted view
return redirect('/sxsw/formSubmitted/') # Preferably use the url pattern name here
It looks like your form's action is set to /sxsw/formSubmitted/ that always simply return the submitted page, instead of the url that will call the sxsw view where the form's save method is called.

Categories

Resources