I am trying to understand how to save data into my Django models. I have a form that display Questions and choices from my models. I want the user to answer the question and to be saved in the Answer model. Here are my models
class Question(models.Model):
question_text = models.CharField(max_length=200)
caption = models.CharField(max_length=200, default="this is a caption")
choices = models.ManyToManyField(Choice)
vis_image = models.ImageField(default= "this is an image", null=False, blank=False, upload_to="static/study/img")
def __str__(self):
return self.question_text
class Condition(models.Model):
name = models.CharField(max_length=200)
def __str__(self):
return self.name
class Participant(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, null=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
condition = models.ForeignKey(Condition, on_delete=models.CASCADE)
score = models.IntegerField(default=0)
def __str__(self):
return self.user.username
class Answer(models.Model):
participant = models.ForeignKey(Participant, on_delete=models.CASCADE)
question = models.ForeignKey(Question, on_delete=models.CASCADE)
answer = models.CharField(max_length=200, null=True)
completion_time = models.FloatField()
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return self.answer
views.py
#login_required
def LPSC_VIEW1(request):
participant=Participant.objects.get(user=request.user)
#GET the first question based on the participant condition
if participant.condition.name == 'LPN':
First_question= Question.objects.get(id=1)
all_choices = First_question.choices.all()
context = {'First_question': First_question, 'all_choices': all_choices}
return render(request, 'study/FirstQN.html', context)
else:
First_question= Question.objects.get(id=11)
all_choices = First_question.choices.all()
context = {'First_question': First_question, 'all_choices': all_choices}
return render(request, 'study/FirstQSC.html', context)
FirstQN.html
<form method="POST">
{% csrf_token %}
<label>
{{First_question}}
</label>
<img src="{{ First_question.vis_image.url }}" style= "height: 600px; width: 960px">
{% for i in all_choices %}
<input type="radio" id="choice" name="choice" value="{{ choice.id }}">
<label for="choice">{{ i.choice_text }}</label>
{% endfor %}
<input type="button" value="Submit" class="btn btn-primary" onclick="window.location.href = server_url +'/study/LPSC_VIEW2'">
</form>
my question is can I use the same view to read data from the database and save data submitted from the user on the same view? or do I have to create a new view but then wouldn't that result in redundancy? I have read about saving data from forms but couldn't understand how to apply it on my case where the form itself is fetched from the database. At the moment the code above all works fine.
You can reuse the view, and is a standard way of doing it using function-based views. Just check the request.method as follows:
#login_required
def LPSC_VIEW1(request):
...
if request.method == 'POST':
# do your code for saving the answers here
... the rest of your code
Related
I am trying to render out model objects that are unique to a user. All methods I've found haven't worked and I've been trying to figure this out for a while now. What is supposed to happen is that you can see the jobs you've posted in the manage-jobs.html template. Also I've removed all of my failed attempts to render out user specific content, it's not that I haven't tried to do this by myself. Thanks.
models.py
class Job(models.Model):
company = models.CharField(max_length=40, null=True, verbose_name="Company/Employer")
description = models.TextField(null=True)
role = models.CharField(max_length=25)
area_of_filming = models.CharField(max_length=50, verbose_name="Area Of Filming", default="")
contact_email = models.EmailField(verbose_name='Contact Email', max_length=60, default='')
created = models.DateTimeField(auto_now_add=True)
user = models.ForeignKey(Account, default='', null=True, on_delete=models.CASCADE)
def __str__(self):
return self.company
class Account(AbstractBaseUser):
email = models.EmailField(verbose_name='email', max_length=60, unique=True)
name = models.CharField(max_length=45, unique=False)
date_joined = models.DateTimeField(verbose_name='date joined', auto_now_add=True)
last_login = models.DateTimeField(verbose_name='last login', auto_now=True)
is_admin = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
is_employee = models.BooleanField(default=True, verbose_name='Are you using FilmLink as an employee?')
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['name', 'is_employee']
objects = MyAccountManager()
class Meta:
permissions = [
("post_jobs", "Can post jobs"),
]
def __str__(self):
return self.name
def has_perm(self, perm, obj=None):
return True
def has_perms(self, perm):
return True
def has_module_perms(self, app_label):
return True
#property
def is_staff(self):
return self.is_admin
views.py
#login_required(login_url='login')
def manage_jobs(request):
if request.user.is_employee:
return redirect('home')
else:
form = JobForm(request.POST)
if form.is_valid():
form.save()
context = {"form":form}
return render(request, 'employer/manage-jobs.html', context)
manage-jobs.html
<button id="myBtn">Post A Job</button>
<div id="main"></div>
<div id="myModal" class="modal">
<div class="modal-content">
<span class="close">×</span>
<form action="" method="POST">
{% csrf_token %}
<div id="company-container">
<p>Employer Name</p>
<p id="employer">{{form.company}}</p>
</div>
<div id="role-container">
<p>Role (e.g. Actor, Director)</p>
<p id="role">{{form.role}}</p>
</div>
<div class="area-of-filming-container">
<p>Area Of Production/Filming</p>
<p id="area-of-filming">{{form.area_of_filming}}</p>
</div>
<div id="contact-email-container">
<p>Contact Email</p>
<p id="contact-email">{{form.contact_email}}</p>
</div>
<div id="description-container">
<p>Description Of Job</p>
<p id="description">{{form.description}}</p>
</div>
<button type="submit" id="post-job">Publish Job</button>
</form>
</div>
</div>
You said that this should render out "jobs". This is only going to render out one job but I am going to assume you intend to solve that after you can actually see content on your screen.
I think the problem is to do with your frontend form.
Note that on your views.py function manage_jobs, that if the user is not an employee you create a form by POST, but the frontend is not connecting to that request.POST.
I am not sure how your urls.py file looks, but you want to link to that views.py call from your form.
In your <form action="{% url 'manage_jobs' %}" method="POST">
This may not be your solution, but I would check out this anyway.
Hope you can figure it out!
I'm trying to make a user stop adding a book into favorite when they already added and show the message into template.
Here's my class django python:
class User(models.Model):
fname = models.CharField(max_length=255)
lname = models.CharField(max_length=255)
email = models.EmailField()
password = models.CharField(max_length=255)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
objects = UserManager()
class Book(models.Model):
title = models.CharField(max_length=255)
description = models.TextField()
uploaded_by = models.ForeignKey(User,
related_name="book_uploaded", on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
objects = BookManager()
class Like(models.Model):
u_like = models.ForeignKey(
User, related_name="user_like", on_delete=models.CASCADE)
b_like = models.ForeignKey(
Book, related_name="book_like", on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
And here's my views.py:
def book_info(request, id):
user_who_like = Book.objects.get(id=id).book_like.all()
context = {
'book': Book.objects.get(id=id),
'user': User.objects.get(id=request.session["user_id"]),
'user_who_like': Book.objects.get(id=id).book_like.all(),
'user_uploaded': Book.objects.first().uploaded_by,
}
return render(request, 'book_info.html', context)
def like(request, id):
book = Book.objects.get(id=id)
user = User.objects.get(id=request.session["user_id"])
like = Like.objects.create(u_like=user, b_like=book)
return redirect(f"/books/{book.id}")
Appreciate all your help! Thank you
You can try this:
def like(request, id):
book = Book.objects.get(id=id)
user = User.objects.get(id=request.session["user_id"])
like = Like.objects.get_or_create(u_like=user, b_like=book)
if not like[1]:
message = "Already added to favourite"
return redirect(f"/books/{book.id}")
Here, what get_or_create does is it creates an object if the object is not already present and it returns a tuple, the object itself and a boolean value. If the object is newly created then it will return True otherwise False. You can then send this message on you template in a conventional way.
this is my def:
def like(request, id):
book = Book.objects.get(id=id)
user = User.objects.get(id=request.session["user_id"])
like = Like.objects.get_or_create(u_like=user, b_like=book)
if not like[1]:
messages.error(request,"Already added to favorite",extra_tags="like_error")
return redirect("/books/")
context = {
'like1': like[1],
}
return redirect(f"/books/{book.id}")
and here's my template:
<form action="/books/{{book.id}}/like/" method="post" class="like">
{% csrf_token %}
<button type="submit" class="btn far fa-thumbs-up"></button>
{% if messages %}
<ul class="messages">
{% for message in messages %}
{% if "like_error" in message.tags %}
<li class="text-danger">{{ message }}</li>
{%endif%}
{% endfor %}
</ul>
{%endif%}
</form>
I am building up a simple Django app with blogs and comments on blogs. While developing the comment thread, I am getting the error "no such table: blog_commentsonpost" when I try to enter a comment. Can someone help me to solve the issue.
models.py
class Post(models.Model):
author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='posts')
created_date = models.DateTimeField(default=timezone.now)
published_date = models.DateTimeField(blank=True, null=True)
title = models.CharField(max_length=100)
description = models.CharField(max_length=1000)
def publish(self):
self.published_date = timezone.now()
self.save()
def get_type(self):
return "post"
def get_absolute_url(self):
return reverse("post_detail", kwargs={'pk': self.pk})
def __str__(self):
return self.title
class CommentsOnPost(models.Model):
author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='comment')
post = models.ForeignKey('blog.Post', on_delete=models.CASCADE, related_name='comments')
created_date = models.DateTimeField(default=timezone.now)
published_date = models.DateTimeField(blank=True, null=True)
text = models.CharField(max_length=1000)
#classmethod
def create(cls, author, text, post):
postcomment = cls(author=author,
post_id=post,
text=text, created_date=timezone.now,
published_date=timezone.now)
return postcomment
views.py
class PostDetailView(DetailView):
model = Post
redirect_field_name = 'post_detail'
def post(self, request, *args, **kwargs):
author = request.user
text = request.POST['postcomment']
post = request.POST['post']
postcomment = CommentsOnPost()
postcomment.text = text
postcomment.author = author
postcomment.save()
return HttpResponseRedirect('/blog/post/{}'.format(post))
html
<form method="POST" class="post-form" >{% csrf_token %}
<div class="form-group">
<label for="postcomment">Comments:</label>
<textarea class="form-control" name="postcomment" rows="5"></textarea>
</div>
<input type="hidden" name="post" value="{{ post.id }}">
<div>
<input type="submit" class="btn btn-primary" style="color:blue;" value="Comment"/>
Did you run python manage.py makemigrations and python manage.py migrate?
If it is a new app, did you add it to the settings.py?
My problem is that I can not save the form. I think the problem lies in the event field in the Register model.
I do not want the user to choose an Event from the list, I want it to happen automatically, hence the code: form.cleaned_data['event'] = kwargs['pk']
This part of code kwargs['pk'] is from url.
Please any hint if this is good approch to dealing with forms and hint to solve my problem. Below is my code.
Thanks :)
Models:
class Event(models.Model):
title = models.CharField(max_length=500)
date = models.DateField()
text = models.TextField()
image = FilerImageField(null=True, blank=True)
flag = models.ForeignKey(Flag)
free_places = models.IntegerField()
class Meta:
ordering = ['-date']
def __str__(self):
return self.title
#property
def slug(self):
return slugify(self.title)
def get_absolute_url(self):
return reverse('events:detail', args=[self.slug, self.id])
class Register(models.Model):
event = models.ForeignKey(Event)
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
company = models.CharField(max_length=30, blank=True)
street = models.CharField(max_length=50, blank=True)
post_code = models.CharField(max_length=30, blank=True)
city = models.CharField(max_length=30, blank=True)
email = models.EmailField()
phone_number = models.IntegerField()
def __str__(self):
return self.first_name
def get_event_name(self):
return self.event
View:
class EventDetailView(DetailView, ModelFormMixin):
model = models.Event
form_class = forms.RegisterForm
def get_success_url(self):
return reverse('events:list')
def post(self, request, *args, **kwargs):
form = self.get_form()
print(kwargs['pk'])
print(self.form_class)
if form.is_valid():
print(form.cleaned_data['event'])
form.cleaned_data['event'] = kwargs['pk']
form.save()
return self.form_valid(form)
else:
return self.form_invalid(form)
My form:
class RegisterForm(ModelForm):
class Meta:
model = models.Register
fields = ('event', 'first_name', 'last_name', 'company', 'street', 'post_code', 'city', 'email', 'phone_number',)
My template:
{% extends 'base.html' %}
{% block content %}
<ul>
<h1>Detail page:</h1>
<li>{{ object.title }}</li>
<li>{{ object.text }}</li>
<li>{{ object.date }}</li>
</ul>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" />
</form>
{% endblock content %}
What you are doing here is to insert into a validated data. Instead of that,
Initialize the form with request POST data which should include "event" key and its value you got from kwargs['pk']. Then validate it and save. You will not get validation errors, as well as the value will be saved.
Basically, even the event id you get from the url that has to be validated. Django does with db level check against the pk value you passed when you call is_valid.
When I create or edit model CV, I need to input some data in birth_date field. It's working, but I want to add some additional text to define some date format like (yyyy-mm-dd). I'm using cripsy forms for better look of forms. How can I add this help text ?
my code:
template.html
{% block profile %}
<div class="jumbotron">
<h2>Edit your basic informations</h2>
<hr>
<form method="POST" class="post-form" enctype="multipart/form-data">
{% csrf_token %}
{{ form|crispy }}
<button type="submit" class="save btn btn-default">Save</button>
</form>
</div>
{% endblock %}
models.py
class Cv(models.Model):
author = models.ForeignKey('auth.User')
name = models.CharField(max_length=25, null = True)
surname = models.CharField(max_length=25, null = True)
city = models.CharField(max_length=100, blank=True)
birth_date = models.DateField(blank=True, null=True)
email = models.EmailField(max_length=50, null=True)
main_programming_language = models.CharField(max_length=15, null = True)
specialization = models.CharField(max_length=30, blank=True, null=True)
interests = models.TextField(blank=True, null=True)
summary = models.TextField(blank=True, null=True)
#thumbnail = models.FileField(upload_to=get_upload_file_name, blank=True)
#property
def age(self):
return int((datetime.datetime.now().date() - self.birth_date).days / 365.25 )
def zapisz(self):
self.save()
def __str__(self):
return self.surname.encode('utf-8')
forms.py
class CvForm(forms.ModelForm):
class Meta:
model = Cv
fields = ('name', 'surname', 'city', 'birth_date', 'email', 'main_programming_language', 'specialization', 'interests', 'summary',)
views.py
#login_required
def new_cv(request):
if request.method == "POST":
form = CvForm(request.POST, request.FILES)
if form.is_valid():
cv = form.save(commit=False)
cv.author = request.user
cv.save()
return redirect('proj.views.cv_detail', pk=cv.pk)
else:
form = CvForm()
return render(request, 'new_cv.html', {'form': form})
Can add help_text to your model fields:
birth_date = models.DateField(blank=True, null=True, help_text="format (yyyy-mm-dd)")
see more Django Model and Form docs.
You can also use external library JQuery Tooltip too.