I am newbie to python as well as Django, and I have started a sample project "blog".
Currently blog posts are added to the database manually, but I want to do it at front end by providing a form to the user. I created my model.py and views.py files, but I am unable to see these fields on the front end. I have copied all of my code below:
models.py:
class posts(models.Model):
author = models.CharField(max_length = 30)
title = models.CharField(max_length = 100)
bodytext = models.TextField()
timestamp = models.DateTimeField()
class postForm(ModelForm):
class Meta:
model = posts
views.py:
def home(request):
content = posts.objects.all()[:5]
return render_to_response('index.html',{'posts' : content})
def save_blog(request):
form = postForm
if request.POST:
form = postForm(request.POST)
if form.is_valid():
form.save
return render_to_response('index.html',{'form' : form},context_instance=RequestContext(request))
url.py:
from django.conf.urls import patterns, include, url
from django.contrib import admin
admin.autodiscover()
urlpatterns =
patterns('',
url(r'^$', 'blog.views.home', name='home'),
url(r'^admin/', include(admin.site.urls))
)
index.html:
<body>
<div class="container">
<h1>Welcome To</h1>
<hr />
{% for post in posts %}
<div class="posts">
<h2>{{ post.title }}</h2>
<h3>Posted on {{ post.timestamp }} by {{ post.author }}</h3>
<p>{{ post.bodytext }}</p>
</div>
<hr />
{% endfor %}
</div>
<div class="forms">
<form action="." method="post" name="posts" id="posts">{% csrf_token %}
<table>
<tr><td>{{form.author.label}}</td><td>{{form.author}}</td></tr>
<tr><td>{{form.title.label}}</td><td>{{form.title}}</td></tr>
<tr><td>{{form.bodytext.label}}</td><td>{{form.bodytext}}</td></tr>
<tr><td></td><td><input type="button" name="btnSave" id="bntSave" value="Submit" class = "default2"/></td>
</table>
</form>
</div>
</body>
settings.MIDDLEWARE_CLASSES:
MIDDLEWARE_CLASSES = (
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
)
Please let me know if i am missing anything. Also let me know how can I achieve this without using a Django model form.
Thanks
views.py
def home(request):
content = posts.objects.all()[:5]
form = postForm()
if request.POST:
form = postForm(request.POST)
if form.is_valid():
form.save()
return render_to_response('index.html',{'posts' : content, 'form' : form}, context_instance=RequestContext(request))
index.html
<div class="forms">
<form method="post" name="posts" id="posts">
{% csrf_token %}
{{ form.as_table }}
<input type="button" name="btnSave" id="bntSave" value="Submit" class="default2"/> //<---------------
</form>
</div>
UPDATE:
Ok I see it now why it's not submitting. You put button instead of submit in the input type
<input type="submit" name="btnSave" id="bntSave" value="Submit" class="default2"/> //<---------------
Just add auto_now_add in your timestamp field
timestamp = models.DateTimeField(auto_now_add=True)
It looks like you called your form postForm but are using posts_form in your view...
I also am unsure what form_save is, you should be calling save() on the form instance like
if form.is_valid():
form.save()
And after posting, it is common practice to redirect the user to another url to prevent resubmitting data.
Related
HI I have just built an HTML-form in which the user can upload multiple images but I am getting Method Not Allowed (POST): /images/ all the time. In the image_list.html the images should be shown.
Thanks for your help
models.py
class ImageModel(models.Model):
images = models.ImageField(upload_to='products/')
forms.py
class ImageForm(ModelForm):
class Meta:
model = ImageModel
fields = ['images']
widgets = {
'images': FileInput(attrs={'multiple': True}),
}
views.py
class ImageFormView(FormMixin, TemplateView):
template_name = 'image_form.html'
form_class = ImageForm
def form_valid(self, form):
# Save the images to the database
form.save()
# Redirect to the image list view
return redirect('image_list')
class ImageListView(ListView):
model = ImageModel
template_name = 'image_list.html'
context_object_name = 'images'
image_form.html
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="btn btn-primary">Submit
</form>
image_list.html
{% load static %}
{% for image in images %}
<img src="{{image.images.url}}" alt="">
{% endfor %}
urls.py
urlpatterns = [
path('images/', views.ImageFormView.as_view(), name='image_form'),
path('', views.ImageListView.as_view(), name='image_list'),
]
You need to close button tag at HTML form
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="btn btn-primary">Submit</button>
</form>
I can't post in Django, because when I import an image it doesn't work for me. it tells me that there's no file selected but I selected one.
This is the post model that I created, models.py file:
class Post(models.Model):
publisher = models.ForeignKey(User,on_delete=models.CASCADE)
caption = models.CharField(max_length=100)
date_created = models.DateTimeField(default=timezone.now())
image = models.ImageField(upload_to="post_images")
def __str__(self):
return self.caption
here's the forms.py file for the Post model:
from django import forms
from .models import Post
class CreatePostForm(forms.ModelForm):
class Meta:
model = Post
fields = ['caption','image']
here's the Publish function in views.py file which implements the logic for my publish feature:
#login_required
def Publish(request):
if request.method == "POST":
form = CreatePostForm(request.POST,request.FILES)
if form.is_valid():
form.publisher = request.user
form.save()
return redirect("home")
else:
form = CreatePostForm()
return render(request,"posts/publish.html",{
"form":form,
})
int the urls.py file:
from django.urls import path
from . import views
urlpatterns = [
path('publish/',views.Publish,name="publish"),
path('',views.home,name="home"),
]
and here's in html template:
{% extends "users/base.html" %}
{% load crispy_forms_tags %}
{% block title %}create{% endblock title%}
{% block content %}
<div class="container-fluid">
<div class="row">
<div class="col-sm-6 col-md-5 authentification">
<div class="form-header">
<h1>
publish
</h1>
</div>
<div class="form-body">
<form method="POST">
<fieldset class="form-group" enctype="multipart/form-data">
{% csrf_token %}
{{ form|crispy }}
</fieldset>
<div class="form-group">
<button type="submit" class="btn btn-primary form-control">publish</button>
</div>
</form>
</div>
</div>
</div>
</div>
{% endblock content %}
the Django version used is 2.2 and the Python 3.8. and Windows 10 Pro
You should alter the .publisher attribute of the .instance wrapped in the form, not the form itself, so:
#login_required
def Publish(request):
if request.method == 'POST':
form = CreatePostForm(request.POST,request.FILES)
if form.is_valid():
form.instance.publisher = request.user
form.save()
return redirect('home')
else:
form = CreatePostForm()
return render(request,'posts/publish.html',{
'form': form,
})
Since you are submitting both files and data, you should specify the enctype=… attribute [mdn] in the <form>:
<form enctype="multipart/form-data" method="POST">
…
</form>
Note: Django's DateTimeField [Django-doc]
has a auto_now_add=… parameter [Django-doc]
to work with timestamps. This will automatically assign the current datetime
when creating the object, and mark it as non-editable (editable=False), such
that it does not appear in ModelForms by default.
Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation.
i want to create a todolist app with django.
i created a form for list model but when the user click on submit to submit a list, the form is'nt saved, why?
this is views.py
i have created an instance of the form and set the user field to it and then save the instance but fact it does'nt
def index(request):
if request.user.is_authenticated:
user_ = User.objects.get(username=request.user.username)
lists = user_.user.all()
form = listForm()
if request.method == "POST":
form = listForm(request.POST)
if form.is_valid():
instance = form.save(commit=False)
instance.user = request.user
instance.save()
return HttpResponseRedirect(reverse("index"))
context = {'lists':lists, 'form':form}
return render(request, 'todolists/index.html', context)
else:
return render(request, 'todolists/login.html')
this is index template
{% extends "todolists/layout.html" %}
{% block body %}
{% if user.is_authenticated %}
<div class="center-column">
<form method="POST" action="{% url 'index' %}">
{% csrf_token %}
{{form.title}}
<input type="submit" class="btn btn-info">
</form>
<div class="todo-list">
{% for list in lists %}
<div class="item-row">
<a class="btn btn-sm btn-info" href="{% url 'update' list.id %}">update</a>
<a class="btn btn-sm btn-danger" href="{% url 'update' list.id %}">delete</a>
<span>{{list}}</span>
</div>
{% endfor %}
</div>
</div>
{% endif %}
{% endblock %}
this is urls.py
from django.urls import path
from .import views
urlpatterns = [
path('', views.index, name='index'),
path('update/<str:id>/', views.update, name='update'),
path("login", views.login_view, name="login"),
path("logout", views.logout_view, name="logout"),
path("register", views.register, name="register"),
]
this is models.py
from django.db import models
from django.contrib.auth.models import AbstractUser
# Create your models here.
class User(AbstractUser):
pass
class list(models.Model):
title = models.CharField(max_length=200)
finished = models.BooleanField(default=False)
timestamps = models.DateTimeField(auto_now_add=True)
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="user")
def __str__(self):
return self.title
here is the form code
class listForm(forms.ModelForm):
title= forms.CharField(label=mark_safe("<span style='color:white;'>Title:</span>"),
widget= forms.TextInput(attrs={'placeholder':'Add new task...', 'class':'form-control'}))
finished= forms.BooleanField(label=mark_safe("<span style='color:white;'>Finished:</span>"),
widget= forms.CheckboxInput(attrs={'style':'width:25px;'}))
class Meta:
model = list
fields = '__all__'
Try updating your template file {{ form.title }} to {{ form }} as mentioned in django docs here is the link
Update your forms.py file if want only title field in the HTML
class listForm(forms.ModelForm):
title= forms.CharField(label=mark_safe("<span style='color:white;'>Title:</span>"),
widget= forms.TextInput(attrs={'placeholder':'Add new task...', 'class':'form-control'}))
class Meta:
model = list
fields = ('title', )
In my template I have a form that includes two input elements whose values can be adjusted with javascript. I want to be able to take these values and, on form submit, display them in a sentence in a for loop underneath.
index.html:
<form action="{% url 'workouts:workout' %}" method="post">
{% csrf_token %}
<div class="weight">
<h4>WEIGHT (kgs):</h4>
<button type="button" class="weight-dec">-</button>
<input type="text" value="0" class="weight-qty-box" readonly="" name="one">
<button type="button" class="weight-inc">+</button>
</div>
<div class="reps">
<h4>REPS:</h4>
<button type="button" class="rep-dec">-</button>
<input type="text" value="0" class="rep-qty-box" readonly="" name="two">
<button type="button" class="rep-inc">+</button>
</div>
<input type="submit" value="Save" name="submit_workout">
<input type="reset" value="Clear">
</form>
{% if exercise.workout_set.all %}
{% for w in exercise.workout_set.all %}
{{ w.content }}
{% endfor %}
{% endif %}
I have given the form above an action attribute for a url which maps to a view, and each of the inputs has a name in order to access their values in the view. I also have written this form in forms.py:
class WorkoutModelForm(forms.ModelForm):
class Meta:
model = Workout
fields = ['content']
And for context, here is my model:
class Workout(models.Model):
content = models.CharField(max_length=50)
created = models.DateField(auto_now_add=True)
updated = models.DateField(auto_now=True)
exercise = models.ForeignKey(Exercise, on_delete=models.CASCADE, default=None)
class Meta:
ordering = ('created',)
My problem from here is that I have no idea how to actually incorporate my model form in my template, or how to write a view that will do what I want it to. I am still new to this and have been searching for an answer for sometime, but so far have not found one. Please help.
This is able to help you, you should first have a look at the django Class-Based Views , more specifically the FormView, django already has generic views capable of handling data posted on forms. Your code would look like this:
# forms.py
# imports ...
class WorkoutModelForm(forms.ModelForm):
class Meta:
model = Workout
fields = ['content']
# urls.py
from django.urls import path
from . import views
app_name = 'myapp'
urlpatterns = [
path("test-form/", views.TesteFormView.as_view(), name='test-form'),
]
# views.py
from django.views.generic import FormView
from myapp import forms
from django.contrib import messages
class TesteFormView(FormView):
template_name = "myapp/index.html"
success_url = reverse_lazy('myapp:test-form')
form_class = forms.WorkoutModelForm
def get(self, request, *args, **kwargs):
return super(TesteFormView, self).get(request, *args, **kwargs)
def form_valid(self, form):
print(f"POST DATA = {self.request.POST}") # debug
content = form.cleaned_data.get('content')
# fieldx= form.cleaned_data.get('fieldx')
# do something whit this fields like :
Workout.object.create(content=content)
messages.success(self.request,"New workout object created")
return super(TesteFormView, self).form_valid(form=self.get_form())
def form_invalid(self, form):
print(f"POST DATA = {self.request.POST}") # debug
for key in form.errors:
messages.error(self.request, form.errors[key])
return super(TesteFormView, self).form_invalid(form=self.get_form())
And your template would look like:
# myapp/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>TestForm</title>
</head>
<body>
<form method="post">
{% csrf_token %}
{{ form }}
<button type="submit">submit</button>
</form>
</body>
</html>
recently I decide to add a comment block to my template in my django app but when I add it to my app , I faced to this error :
add_comment_to_post() got an unexpected keyword argument 'item_id'
my template.html:
{% block content %}
<form action="#" method="post" novalidate="novalidate">
{% csrf_token %}
{{ form.as_p }}
<div class="row">
<div class="col-md-4">
<p><label>Name*</label><input type="text" name="your-name" value=""
size="60" class=""
aria-required="true"
aria-invalid="false"></p>
</div>
<div class="col-md-4">
<p><label>Email*</label><input type="text" name="your-email"
value=""
size="60" class=""
aria-required="true"
aria-invalid="false"></p>
</div>
<div class="col-md-4">
<p><label>Website</label><input type="text" name="your-website"
value=""
size="60" class=""
aria-required="true"
aria-invalid="false"></p>
</div>
<div class="col-md-12">
<p><label>Message</label><textarea name="your-message" cols="60"
rows="3" class=""
aria-invalid="false"></textarea>
</p>
</div>
</div>
<div class="dividewhite2"></div>
<p>
<button type="button" href="{% url 'add_comment_to_post' pk=item.pk %}"
class="btn btn-lg btn-darker">Post Comment
</button>
</p>
</form>
{% endblock %}
my models.py :
from django.db import models
from datetime import date
from django.utils import timezone
# Create your models here.
class Blogs(models.Model):
main_image = models.ImageField(upload_to='Blogs/', help_text='This Image Is Gonna To Be Show At Blogs Page.',
blank=False, default='')
class Comment(models.Model):
post = models.ForeignKey('Blog.Blogs', on_delete=models.CASCADE, related_name='comments')
author = models.CharField(max_length=200)
text = models.TextField()
created_date = models.DateTimeField(default=timezone.now)
approved_comment = models.BooleanField(default=False)
def approve(self):
self.approved_comment = True
self.save()
def __str__(self):
return self.text
my form.py:
from django.forms import ModelForm
from .models import Blogs, Comment
class CommentForm(ModelForm):
class Meta:
model = Comment
fields = ('author', 'text',)
my views.py :
from django.shortcuts import render, get_object_or_404, redirect
from Blog.forms import CommentForm
from .models import Blogs, Comment
def item(request, items_id):
items = get_object_or_404(Blogs, pk=items_id)
return render(request, 'Blog/Items.html', {'item': items, 'comments': Comment})
def add_comment_to_post(request, pk):
post = get_object_or_404(Blogs, pk=pk)
if request.method == "POST":
form = CommentForm(request.POST)
if form.is_valid():
comment = form.save(commit=False)
comment.post = post
comment.save()
return redirect('post_detail', pk=post.pk)
else:
form = CommentForm()
return render(request, 'blog/Items.html', {'form': form})
and my urls.py:
from django.urls import path
from Blog import views
from Blog import models
urlpatterns = [
path('<int:item_id>/', views.add_comment_to_post, name='add_comment_to_post'),
path('<int:items_id>/', views.item, name='Itemz'),
]
I checked my code many times but I can't understand what is my problem.
is any body know to how can I add comment to my app or what is my problem?
In addition, I'm sorry for writing mistakes in my question.
change this
def add_comment_to_post(request, pk):
To:
def add_comment_to_post(request, item_id):
Then change everywhere inside the function you wrote pk to item_id
views.py
def add_comment_to_post(request, item_id):
post = get_object_or_404(Blogs, pk=item_id)
if request.method == "POST":
form = CommentForm(request.POST)
if form.is_valid():
comment = form.save(commit=False)
comment.post = post
comment.save()
return redirect('post_detail', pk=post.pk)
else:
form = CommentForm()
return render(request, 'blog/Items.html', {'form': form, 'item': post})
and in your template:
<button type="button" href="{% url 'add_comment_to_post' item.pk %}"
class="btn btn-lg btn-darker">Post Comment
</button>
Double check your url patterns maybe? Try:
urlpatterns = [
path('<int:pk>/', views.add_comment_to_post, name='add_comment_to_post'),
The variable name in your view method needs to match the variable name in the url. Therefore you need both to be pk or both to be item_id
The Problem happen because in urls.py there were two subject that was pass to one views.
change views to this :
urlpatterns = [
path('<int:pk>/', views.item, name='Itemz'),
]
then change html part to this :
{% if not user.is_authenticated %}
<p><a href="{% url 'login' %}" class="btn btn-gr btn-xs">Login To Send
A Command.</a></p>
{% endif %}
<div class="dividewhite2"></div>
{% if user.is_authenticated %}
<form method="post" novalidate="novalidate">
{% csrf_token %}
{{ form.as_p }}
<div class="dividewhite2"></div>
<p>
<button href="{% url 'Itemz' item.id %}" type="submit"
class="btn btn-lg btn-darker">Post Comment
</button>
</p>
</form>
{% endif %}
now the Django project will run properly.