I am trying to create a simple form in Django but it is not showing the input form in HTML and there is not error appearing so that I can track the error.
Here is the model:
class Log(models.Model):
log_weight = models.FloatField(validators=[MinValueValidator(0)],blank=True, null=True)
log_repetitions = models.IntegerField(validators=[MinValueValidator(1)],blank=True, null=True)
class LogForm(forms.Form):
log_weight = forms.IntegerField()
log_repetitions = forms.IntegerField()
class Meta:
model = Log
fields = ['log_weight', 'log_repetitions']
Here is the views:
class workout_details(DetailView):
model = Workout
template_name = 'my_gym/start_workout.html'
context_object_name = 'workout'
def get_context_data(self, **kwargs):
exercises = Exercise.objects.filter(workout_id=self.object)
context = super().get_context_data(**kwargs)
context['exercises'] = exercises
return context
def addlog(request, id):
url = request.META.get('HTTP_REFERER') # get last url
# return HttpResponse(url)
if request.method == 'POST': # check post
form = LogForm(request.POST)
if form.is_valid():
data = Log() # create relation with model
data.log_repetitions = form.cleaned_data['log_repetitions']
data.log_weight = form.cleaned_data['log_weight']
data.workout_id = id
data.save() # save data to table
return HttpResponseRedirect(url)
return HttpResponseRedirect(url)
Here is the template:
<form
class="review-form" action="{% url 'my_gym:addlog' workout.id %}" method="post">
{% csrf_token %}
{{ form }}
</form>
Here is the url:
urlpatterns = [
path('', home.as_view(), name='home'),
path('workout/<int:pk>/', workout_details.as_view(), name='workout'),
path('workout/addlog/<int:pk>', addlog, name='addlog'),
]
My question:
What is the reason that the form is not showing in the details page? How can I fix it.
You missed to pass the form to the View context. Add the following to your DetailView get_context_data method:
context['form'] = LogForm()
Related
i have two pages profile and add notes. i want to fill the patient field in the add notes form with the users first name whenever i click add notes on any users profile will i need to change the url path? if yes, how do i get the data from the url and fill it in the form.
urls.py
urlpatterns = [
path('', dashboard, name='dashboard'),
path('profile/', profile, name='profile'),
path('profile/<str:slug>/<int:pk>', profile, name='profilepk'),
path('edit_profile/<int:id>/', edit_profile, name='editprofile'),
path('addnotes/', addnotes, name='addnote'),
]
views.py
def addnotes(request):
profile = Profile.objects.get(user_id=id)
form = PatientNotesForm(request.POST or None)
if form.is_valid():
form.save()
return redirect(f'/dashboard/profile/{user.profile.slug}/{user.pk}')
return render(request, 'core/addnotes.html', {'form': form})
def profile(request, slug, pk):
profil = Profile.objects.get(slug=slug)
profile = Profile.objects.get(pk=pk)
context = {'profile': profile, 'profil': profil}
return render(request, 'dashboard/profile.html', context)
models.py
class Note(models.Model):
illness = models.CharField(max_length=1000, blank=True)
patient = models.ForeignKey(Profile, on_delete=models.CASCADE, related_name='patientnote', null=True)
Doctor = models.CharField(max_length=100, blank=True)
Description = models.CharField(max_length=10000, blank=True)
created = models.DateTimeField(auto_now_add=True)
def __str__(self):
return f"{self.illness}"
forms.py
class PatientNotesForm(ModelForm):
illness = forms.CharField(max_length=100, help_text='First Name')
patient = forms.CharField(max_length=100, help_text='Last Name')
doctor = forms.CharField(max_length=100, help_text='address')
description = forms.CharField(max_length=100,widget=forms.Textarea)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['illness'].widget.attrs.update(
{'placeholder': ('illness')})
self.fields['doctor'].widget.attrs.update(
{'placeholder': ("Doctor's name")})
self.fields['patient'].widget.attrs.update(
{'placeholder': ("Patient's name")})
self.fields['description'].widget.attrs.update(
{'placeholder': ("Description")})
self.fields['illness'].widget.attrs.update({'class': 'log'})
self.fields['doctor'].widget.attrs.update({'class': 'log'})
self.fields['patient'].widget.attrs.update({'class': 'log'})
self.fields['description'].widget.attrs.update({'class': 'textarea'})
class Meta:
model = Note
fields = ('illness', 'patient', 'doctor', 'description')
addnotes.html
<form method="post" class="fum"> {%csrf_token%}{{form.illness}}{{form.patient}}{{form.doctor}}{{form.description}}
<li class="btnn "><button type="submit " class="conf ">Confirm</button></li>
</form>
profile.html
<ul class="main-menu">
<li>
<img class="nav-items" src="{% static 'images/home.svg'%}" alt=""><span>Home</span>
</li>
<li>
<img class="nav-items" src="{% static 'images/male.svg'%}" alt=""><span>Patients</span>
</li>
<li>
<img class="nav-items" src="{% static 'images/doctor.svg'%}" alt=""><span>Add notes</span>
</li>
<li>
<a href="#"><img class="nav-items" src="{% static 'images/lab.svg'%}" alt=""><span>Edit profile</span>
</a>
</li>
</ul>
</div>
It is not clear if the form should contain a field for patient in the first place. If the URL is constructed for a specific patient.
You should add this value somehow. For example in the path:
urlpatterns = [
# …
path('addnotes/<int:pk>', addnotes, name='addnote'),
]
Next we can decide to either prefill this in the form, or just omit the field.
Option 1: omit the patient field
So in that case it means that the ModelForm looks like:
class PatientNotesForm(ModelForm):
# …
class Meta:
model = Note
# no patient ↓
fields = ('illness', 'doctor', 'description')
In that case you can spec
from django.shortcuts import get_object_or_404
def addnotes(request, id):
profile = get_object_or_404(Profile.objects.get, user_id=id)
if request.method == 'POST':
form = PatientNotesForm(request.POST)
if form.is_valid():
form.instance.patient = profile
form.save()
return redirect(f'/dashboard/profile/{user.profile.slug}/{user.pk}')
else:
form = PatientNotesForm()
form.instance.patient = profile
return render(request, 'core/addnotes.html', {'form': form})
Option 2: Prefill it in the form
An alternative is to still allow to modify this in the form, but specify an intial=… parameter [Django-doc]. In that case the PatientNotesForm remains the same but we pass an initial value.
def addnotes(request, id):
if request.method == 'POST':
form = PatientNotesForm(request.POST)
if form.is_valid():
form.save()
return redirect(f'/dashboard/profile/{user.profile.slug}/{user.pk}')
else:
form = PatientNotesForm(initial={'patient': id})
return render(request, 'core/addnotes.html', {'form': form})
I have made a new Comment Model in my Django Project but the form is not showing in the browser although I added the form in the template.
Here is the models.py
class Comment(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
post = models.ForeignKey(Post, on_delete=models.CASCADE)
body = models.TextField(max_length=300)
def __str__(self):
return str(self.pk)
Here is the views:
def comment_create(request, self):
post = get_object_or_404(Post, slug=self.kwargs['slug'])
user = User.objects.get(user=request.user)
c_form = CommentModelForm()
context = {
'post': post,
'user': user,
'c_form': c_form,
}
return context
Here is the forms.py
class CommentModelForm(forms.ModelForm):
body = forms.CharField(label='',
widget=forms.TextInput(attrs={'placeholder': 'Add a comment...'}))
class Meta:
model = Comment
fields = ('body',)
Here is the urls.py
path('blogs/comment', comment_create, name='comment-post'),
Here is the template:
<form action="" method="POST"class='ui fluid form'>
{% csrf_token %}
<input type="hidden" name="post_id" value={{post.id}}>
{{ c_form }}
<button type="submit" name="submit_c_form" class="">Send</button>
</form>
First, you have to get the type of request, I added a if/else for GET and POST requests. Added form.is_valid check.
In your function you are trying to get a kwarg form the url but you don't have a kwarg in your path.
path('blogs/<slug:slug>/comment', comment_create, name='comment-post'),
views.py
def comment_create(request, self):
post = get_object_or_404(Post, slug=self.kwargs['slug'])
if request.method == 'POST': # If user submitted form
c_form = CommentModelForm(request.POST) # Get form response
if c_form.is_valid(): # Chekc if form is valid
c_form.user = User.objects.get(user=request.user) # Get user and add it to form
c_form.post = post # Add post to form
c_form.save() # Save form
else:
c_form = CommentModelForm() # Pass form
context = {
'post': post,
'c_form': c_form,
}
return render(request, 'app/comment.html', context) # change template
forms.py
class Meta:
model = Comment
fields = ['body'] # When I set tuples it normally gives me an error
I am trying to create a "restaurant rating" app on Django 3.
I have set up the following models:
# Table storing the different restaurants
class Restaurant(models.Model):
restaurant_name = models.CharField(max_length=200, unique=True)
restaurant_address = models.CharField(max_length=200)
restaurant_street_number = models.CharField(max_length=10)
restaurant_city = models.CharField(max_length=200)
restaurant_cuisine_type = models.CharField(max_length=200)
def __str__(self):
return self.restaurant_name + ' - ' + self.restaurant_city
class UserReview(models.Model):
# Defining the possible grades
Grade_1 = 1
Grade_2 = 2
Grade_3 = 3
Grade_4 = 4
Grade_5 = 5
# All those grades will sit under Review_Grade to appear in choices
Review_Grade = (
(1, '1'),
(2, '2'),
(3, '3'),
(4, '4'),
(5, '5')
)
restaurant = models.ForeignKey(Restaurant, on_delete=models.CASCADE)
user_review_grade = models.IntegerField(default=None, choices=Review_Grade) # default=None pour eviter d'avoir un bouton vide sur ma template
user_review_comment = models.CharField(max_length=1500)
def get_absolute_url(self):
return reverse('restaurants:reviews', args=[self.id])
This is the form I am using:
# Form for user reviews per restaurant
class UserReviewForm(forms.ModelForm):
class Meta:
model = UserReview
# restaurant = forms.ModelChoiceField(queryset=Restaurant.objects.filter(pk=id))
fields = [
'restaurant',
'user_review_grade',
'user_review_comment'
]
widgets = {
'restaurant': forms.HiddenInput,
'user_review_grade': forms.RadioSelect,
'user_review_comment': forms.Textarea
}
labels = {
'user_review_grade': 'Chose a satisfaction level:',
'user_review_comment': 'And write your comments:'
}
Here are my URLs:
app_name = 'restaurants'
urlpatterns = [
# ex: /restaurants/
path('', views.index, name='index'),
# ex: /restaurants/15
path('<int:restaurant_id>/', views.details, name='details'),
# ex: /restaurants/test
path('<int:restaurant_id>/test', views.Test.as_view(), name='test')
]
Template:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>TEST</title>
</head>
<body>
<h1>Write a review for this restaurant:</h1>
<form method="post">
{% csrf_token %}
<input type="Hidden" name="restaurant" value="{{restaurant.restaurant_id}}">
{{ form.as_p }}
<br>
<input type="submit" value="Submit">
</form>
</body>
</html>
And finally my view:
# Test class to be renamed posts reviews as it should
class Test (CreateView):
template_name = 'restaurants/TEST.html'
form_class = UserReviewForm
# Get the initial information needed for the form to function: restaurant field
def get_initial(self, restaurant_id, *args, **kwargs):
initial = super(Test, self).get_initial(**kwargs)
initial['restaurant'] = 9
return initial()
# Post the data into the DB
def post(self, request, *args, **kwargs):
form = UserReviewForm(request.POST)
if form.is_valid():
review = form.save()
print(review) # Print so I cna see in cmd prompt that something posts as it should
review.save()
return render(request, 'restaurants/reviews.html', {'form': form})
I am facing an issue as when I define initial as an integrer (let's say 9 - as I put it to test if my form was actually posting) it posts with no issue the review in the DB for restaurant that holds id=9
However I can't get it to have the restaurant_id automatically populated depending on which restaurant's page we're visiting.
I tried the following as well as few other 'tricks' found here and there but nothing seems to do the cut...
# Test class to be renamed later IF it works...
class Test (CreateView):
template_name = 'restaurants/TEST.html'
form_class = UserReviewForm
# Get the initial information needed for the form to function: restaurant field
def get_initial(self, restaurant_id, *args, **kwargs):
restaurant = get_object_or_404(Restaurant, pk=restaurant_id)
initial = super(Test, self).get_initial(**kwargs)
initial['restaurant'] = self.request.restaurant.pk
return initial()
# Post the data into the DB
def post(self, request, *args, **kwargs):
form = UserReviewForm(request.POST)
if form.is_valid():
review = form.save()
print(review) # Print so I cna see in cmd prompt that something posts as it should
review.save()
return render(request, 'restaurants/reviews.html', {'form': form})
Any help would be appreciated to point me in the right direction :)
You can obtain the restaurant_id in the url parameters with self.kwargs['restaurant_id']. So you can ue:
class Test(CreateView):
def get_initial(self, *args, **kwargs):
initial = super(Test, self).get_initial(**kwargs)
initial['restaurant'] = self.kwargs['restaurant_id']
return initial
# …
That being said, it is rather odd to store this in a form anyway. You can simply set this when the form is valid. So we define the form without a restaurant:
class UserReviewForm(forms.ModelForm):
class Meta:
model = UserReview
fields = [
'user_review_grade',
'user_review_comment'
]
widgets = {
'user_review_grade': forms.RadioSelect,
'user_review_comment': forms.Textarea
}
labels = {
'user_review_grade': 'Chose a satisfaction level:',
'user_review_comment': 'And write your comments:'
}
and in the CreateView, we then set the restaurant of that instance:
class Test(CreateView):
template_name = 'restaurants/TEST.html'
model = UserReview
form_class = UserReviewForm
success_url = …
def form_valid(self, form):
form.instance.restaurant_id = self.kwargs['restaurant_id']
super().form_valid(form)
You here need to specify a success_url to which it will redirect in case the submission is succesful. In case a POST is successful, you need to make a redirect to implement the Post/Redirect/Get pattern [wiki].
I'm writing what should be a very simple todo app. The problem is that the edit view is giving me fits! I'm trying to populate a form with data from the database, and it's just not doing the right thing. I've tried the info from this page, but the translation into class-based views must have broken something, or I'm just not using the right kind of form.
Here's the code for the model:
class Todo(models.Model):
id = models.AutoField(primary_key=True)
todo = models.CharField(max_length=255, unique=True)
todo_detail = models.TextField(default='')
date_created = models.DateField(default=timezone.now())
estimated_completion = models.DateTimeField(default=timezone.now())
maybe_completed = models.BooleanField("Completed?", default=False)
def __unicode__(self):
return self.todo
The view code, the commented out bit is from the link:
class TodoEditView(FormView):
model = Todo
form_class = TodoEditForm
template_name = 'todo_edit.html'
#def get(self, request, *args, **kwargs):
# form = self.form_class()
# form.fields['todo'].queryset = Todo.objects.get(id=self.kwargs['pk'])
# form.fields['todo_detail'].queryset = Todo.objects.get(
# id=self.kwargs['pk'])
# form.fields['date_created'].queryset = Todo.objects.get(
# id=self.kwargs['pk'])
# form.fields['estimated_completion'].queryset = Todo.objects.get(
# id=self.kwargs['pk'])
# form.fields['maybe_completed'].queryset = Todo.objects.get(
# id=self.kwargs['pk'])
# template_vars = RequestContext(request, {
# 'form': form
# })
# return render_to_response(self.template_name, template_vars)
def get_context_data(self, **kwargs):
context = super(TodoEditView, self).get_context_data(**kwargs)
context['todo'] = Todo.objects.get(id=self.kwargs['pk'])
return context
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST)
if form.is_valid():
todo = request.POST['todo']
todo_detail = request.POST['todo_detail']
estimated_completion = request.POST['estimated_completion']
date_created = request.POST['date_created']
t = Todo(todo=todo, todo_detail=todo_detail,
estimated_completion=estimated_completion,
date_created=date_created)
t.save()
return redirect('home')
The form code:
class TodoEditForm(forms.ModelForm):
class Meta:
model = Todo
exclude = ('id', )
And the template code:
{% extends 'todos.html'%}
{% block content %}
<form method="post" action="{% url 'add' %}">
<ul>
{{ form.as_ul }}
{% csrf_token %}
</ul>
{{todo.todo}}
</form>
{% endblock %}
What the heck am I doing wrong?
You should use an UpdateView, not a FormView. That will take care of prepopulating your form.
Also note you don't need any of the logic in the post method - that is all taken care of by the generic view class.
I am trying to create a ModelForm that updates a record in my database, but for some reason it isn't working. It turns out blank. What am I doing wrong here?
this is my forms.py:
class PageForm(ModelForm):
class Meta:
model = Page
this is my views.py:
def detail(request, page_id):
p = get_object_or_404(Page, pk=id)
if request.method == 'POST':
form = PageForm(request.POST, instance=p)
if form.is_valid():
form.save()
messages.success(request, "Detail updated successfully.")
return HttpResponseRedirect('/thanks/')
return render(request, 'pages/pageform.html', {
'form': PageForm(instance=p),
})
this is my model.py:
class Page(models.Model):
pub_date = models.DateTimeField('date published')
title = models.CharField(max_length=255)
keywords = models.CharField(max_length=255)
description = models.CharField(max_length=255)
content = models.TextField()
def __unicode__(self):
return self.title
this is my pageform.html
<form action="/detail/" method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" />
</form>
this is my urls.py
urlpatterns = patterns('',
url(r'^page/(?P<id>\d+)/$', 'detail', name='detail'),
)
You need to create form for get request as well.
Update your view as
def detail(request, page_id):
if request.method == 'POST':
....
else:
p = Page.objects.get(pk=page_id)
form = PageForm(instance=p)
....
Also, do not create new form when form is not valid as it will not show any errors.
Thank you Cathy and Rohan! This worked for me:
views.py
def detail(request, page_id):
p = get_object_or_404(Page, pk=page_id)
if request.method == 'POST':
form = PageForm(request.POST or None, instance=p)
if form.is_valid():
form.save()
return HttpResponseRedirect('/thanks/')
else:
form = PageForm(instance=p)
return render_to_response('pages/detail.html', {'page': p, 'form': form}, context_instance=RequestContext(request))
urls.py:
urlpatterns = patterns('',
url(r'^page/(?P<page_id>\d+)/$', 'pages.views.detail'),
)