I am busy building a conference website application where is is necessary to be able to upload articles. These articles should also be able to assigned to reviewers to get downloaded and scored. My problem comes with the uploading of the files. I am not sure what I am doing wrong, but I think my form is submitting the incorrect data since it doesn't run through the 'if form.is_valid:' part. I am still a beginner at this. I have watched multiple tutorials.
This is what my model.py file looks like:
from django.db import models
from time import time
def get_upload_file_name(instance, filename):
return "uploaded_files/%s_%s" % (str(time()).replace('.','_'), filename)
class Article(models.Model):
title = models.CharField(max_length=50)
abstract = models.TextField()
pub_date = models.DateTimeField('Date published')
ffile = models.FileField(upload_to=get_upload_file_name)
def __str__(self):
return "%s" % (self.title)
This is my admin.py file:
from django.contrib import admin
from .models import Article
admin.site.register(Article)
This is my forms.py file:
from django import forms
from .models import Article
class ArticleForm(forms.ModelForm):
class Meta:
model = Article
fields = ('title','abstract','pub_date','ffile')
This is my views.py file:
from django.shortcuts import render, render_to_response
from django.http import HttpResponseRedirect
from .forms import ArticleForm
def upload_article(request):
if request.method == 'POST':
form = ArticleForm(request.POST, request.FILES)
if form.is_valid():
instance = ArticleForm(file_field=request.FILES[''])
form.save()
instance.save()
return HttpResponseRedirect('/articles/')
else:
form = ArticleForm()
return render_to_response('submit/form.html', {'form' : form})
And then my HTML template:
{% extends 'base.html' %}
{% block content %}
<form method="post" action="../upload/" enctype="multipart/form-data"> {% csrf_token %}
{{form.as_p}}
<input type="submit" value="Submit" />
</form>
{% endblock %}
There is no problems with my urls.. Can someone please help me. Or at least suggest a third party app that might make this easier?
I can post normal forms that is not uploading files, but I just can't seem to get this one.
Ok, so I found the solution to the posting problem.
models.py
from django.db import models
from django.forms import ModelForm
from time import time
# Function to determine where to place uploaded documents
# Taken from youtube tutorial: https://www.youtube.com/watch?v=b43JIn-OGZU&index=15&list=PLxxA5z-8B2xk4szCgFmgonNcCboyNneMD
def get_upload_file_name(instance, filename):
# return a string: folder_name/time-of-upload + seperated by underscore + filename
# Example: media_files/15-10-2015_Submission1
return "uploaded_files/%s_%s" % (str(time()).replace('.','_'), filename)
class Document(models.Model):
file = models.FileField( blank=False, null=True)
title = models.CharField(max_length=200, default=None)
def __str__(self):
return "%s" % self.title
class DocumentForm(ModelForm):
class Meta:
model = Document
fields = ['title', 'file']
forms.py
from django import forms
from .models import Document
class UploadFileForm(forms.ModelForm):
title = forms.CharField(max_length=200)
file = forms.FileField(
label = 'Select a file',
help_text = 'maximum file size: 50mb',
allow_empty_file=False
)
views.py
##login_required
def upload_file(request):
# Handle file upload
if request.POST:
form = DocumentForm(request.POST, request.FILES)
#print(request.POST['title'], ' ', request.POST['file'])
# print(request.FILES['file'])
if form.is_valid():
#newdoc = Document(title = request.FILES['title'])
form.save()
# Redirect to the document list after POST
# return HttpResponseRedirect(reverse('submissions.views.upload_file'))
return HttpResponseRedirect('/success/')
else:
form = DocumentForm() #A empty, unbound form
args = {}
args.update(csrf(request))
args['form'] = form
return render_to_response('submissions/submission.html', args, context_instance=RequestContext(request))
So one of the problems was that I had to create a FileField in the model as weel as in the form.
Related
I created a Form using one of my models i.e (Post), for my blog website. The form is meant for writers to post articles. In that form there is an Image attribute where the writer can upload an image. However, when i try to upload an image and post it, i get a feedback saying "field required", i think the form is not recognizing the image am trying to upload onto the the database. please help:
this is the form view from views.py:
def formview(request):
form = PostForm(request.POST or None)
if form.is_valid():
instance = form.save(commit=False)
instance.save()
return render(request, 'form.html', {'form':form})
this is from forms.py:
from django import forms
from .models import Post
class PostForm(forms.ModelForm):
image = forms.FileField
class Meta:
model = Post
fields = ['category', 'title', 'body', 'image', 'author']
this from my models.py:
class Post(models.Model):
category = models.ForeignKey(Category)
title = models.CharField(max_length=100)
pub_date = models.DateTimeField(auto_now_add=True)
body = models.TextField()
image = models.FileField()
author = models.ForeignKey(User, on_delete=models.CASCADE)
likes = models.IntegerField(default=1)
def __str__(self):
return self.title
this is my forms.html template:
<form method="POST" action="">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Post</button>
this is my urls.py:
from django.conf.urls import url
from . import views
app_name = 'posts'
urlpatterns = [
url(r'^$', views.homeview, name='homeview'),
url(r'^(?P<pk>[0-9]+)$', views.postview, name='postview'),
url(r'^category/(?P<pk>[a-zA-Z0-9]+)/$', views.categoryview,
name='categoryview'),
url(r'^author/(?P<pk>[a-zA-Z0-9]+)/$', views.authorview, name='authorview'),
url(r'^add_post/$', views.formview, name='formview'),
]
these are the pics might help explain what am trying to say:
Filling the form and selecting the picture
Error message after trying to post
Thank you
def formview(request):
if request.method == 'POST':
form = PostForm(request.POST,request.FILES)
if form.is_valid():
instance = form.save(commit=False)
instance.save()
else:
form = PostForm()
return render(request, 'form.html', {'form':form})
this form = PostForm(request.POST,request.FILES),you need add FILES to PostForm
I've been using this great post http://kevindias.com/writing/django-class-based-views-multiple-inline-formsets/ to setup my site. I was wondering how to save the user field automatically to an inline formset in views (I used the blockquote for changes to the original). The RecipeForm in (see also below for context)
self.object = form.save(commit=False)
self.object.owner = self.request.user
self.object.save()
saves nicely automatically but not the
ingredient_form.owner= self.request.user
I know Django suggests using BaseInlineFormSet, but most people suggest saving user field in views.py and not forms or models for many different reasons. I would appreciate any suggestions or answers. Here's the full code:
models.py
from django.db import models
class Recipe(models.Model):
owner = models.ForeignKey(User)
title = models.CharField(max_length=255)
description = models.TextField()
class Ingredient(models.Model):
owner = models.ForeignKey(User)
recipe = models.ForeignKey(Recipe)
description = models.CharField(max_length=255)
class Instruction(models.Model):
recipe = models.ForeignKey(Recipe)
number = models.PositiveSmallIntegerField()
description = models.TextField()
forms.py
from django.forms import ModelForm
from django.forms.models import inlineformset_factory
from .models import Recipe, Ingredient, Instruction
class RecipeForm(ModelForm):
class Meta:
model = Recipe
IngredientFormSet = inlineformset_factory(Recipe, Ingredient)
InstructionFormSet = inlineformset_factory(Recipe, Instruction)
views.py
from django.http import HttpResponseRedirect
from django.views.generic import CreateView
from .forms import IngredientFormSet, InstructionFormSet, RecipeForm
from .models import Recipe
class RecipeCreateView(CreateView):
template_name = 'recipe_add.html'
model = Recipe
form_class = RecipeForm
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)
ingredient_form = IngredientFormSet()
instruction_form = InstructionFormSet()
return self.render_to_response(
self.get_context_data(form=form,
ingredient_form=ingredient_form,
instruction_form=instruction_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)
ingredient_form = IngredientFormSet(self.request.POST)
instruction_form = InstructionFormSet(self.request.POST)
if (form.is_valid() and ingredient_form.is_valid() and
instruction_form.is_valid()):
return self.form_valid(form, ingredient_form, instruction_form)
else:
return self.form_invalid(form, ingredient_form, instruction_form)
def form_valid(self, form, ingredient_form, instruction_form):
"""
Called if all forms are valid. Creates a Recipe instance along with
associated Ingredients and Instructions and then redirects to a
success page.
"""
self.object = form.save(commit=False)
self.object.owner = self.request.user
self.object.save()
ingredient_form.instance = self.object
ingredient_form.owner= self.request.user
ingredient_form.save()
instruction_form.instance = self.object
instruction_form.save()
return HttpResponseRedirect(self.get_success_url())
def form_invalid(self, form, ingredient_form, instruction_form):
"""
Called if a form is invalid. Re-renders the context data with the
data-filled forms and errors.
"""
return self.render_to_response(
self.get_context_data(form=form,
ingredient_form=ingredient_form,
instruction_form=instruction_form))
I did some more research and the solution looks somewhat complex following this guide of how to add custom formset saving but modified for BaseInlineFormset as mentioned above. I realized it will be simpler just to make ModelForms for each Model and then linking them in a view, since I only need one child form at a time in the add a new recipe view and can reuse the ModelForm code.
here's the new code that works great! Feel free to contact if you need more info.
forms.py
from django.forms import ModelForm
from .models import Recipe, Ingredient, Instruction
class RecipeForm(ModelForm):
class Meta:
model = Recipe
exclude = ['owner',]
class IngredientForm(ModelForm):
class Meta:
model = Ingredient
exclude = ['owner','recipe',]
class InstructionForm(ModelForm):
class Meta:
model = Instruction
exclude = ['recipe',]
views.py
from .forms import IngredientForm, InstructionForm, RecipeForm
def add_new_value(request):
rform = RecipeForm(request.POST or None)
iform = IngredientForm(request.POST or None)
cform = InstructionForm(request.POST or None)
if rform.is_valid() and iform.is_valid() and cform.is_valid():
rinstance = rform.save(commit=False)
iinstance = iform.save(commit=False)
cinstance = cform.save(commit=False)
user = request.user
rinstance.owner = user
rinstance.save()
iinstance.owner = user
cinstance.owner = user
iinstance.recipe_id = rinstance.id
cinstance.recipe_id = rinstance.id
iinstance.save()
cinstance.save()
return HttpResponseRedirect('/admin/')
context = {
'rform' : rform,
'iform' : iform,
'cform' : cform,
}
return render(request, "add_new_recipe.html", context)
template: add_new_recipe.html
<!DOCTYPE html>
<html>
<head>
<title>Add Recipe</title>
</head>
<body>
<div>
<h1>Add Recipe</h1>
<form action="" method="post">
{% csrf_token %}
<div>
{{ rform.as_p }}
{{ iform.as_p }}
{{ cform.as_p }}
</div>
<input type="submit" value="Add recipe" class="submit" />
</form>
</div>
</body>
</html>
I am a newbie for Django and working on a project. I am stucked with setting up a forms.py and integrate the same with my template. I did all the required things with the help of all sort of tutorial I got online but I was unable to see the fields I declared in form on the HTML Page. Below is the code I used for each of the module. It would be great if anyone can help me out with this.
models.py
from django.db import models
class EarlyBirds(models.Model):
name = models.CharField(max_length=200)
email = models.CharField(max_length=200)
contact_number = models.IntegerField()
def __str__(self):
return '%s - %s' % (self.name, self.email)
views.py
from django.shortcuts import render
from django.http import HttpResponse
from django.template import RequestContext, loader
from django.shortcuts import render_to_response
from .forms import EarlyBirdsForm
from .models import EarlyBirds
def register(request):
context = RequestContext(request)
success=''
if request.method == 'POST':
form = EarlyBirdsForm(request.POST)
if form.is_valid():
name = request.POST.get('name','')
email = request.POST.get('email','')
number = request.POST.get('number','')
if email:
email_exist = EarlyBirds.objects.filter(email=email)
if email_exist:
success = 'Thankyou for your intrest! This email is already registered with us. We will get back to you soon.'
else:
eb_obj = EarlyBirds(name=name,email=email,contact_number=number)
eb_obj.save()
success = 'Thankyou for your intrest! We will get back to you soon.'
else:
success = 'Please fill out the required fields'
else:
success = form.errors
else:
form = EarlyBirdsForm()
return render_to_response('ComingSoon.html', {'success':success}, context)
forms.py
from django import forms
from django.forms import ModelForm
from app_name.models import EarlyBirds
class EarlyBirdsForm(forms.Form):
name = forms.CharField(required=True,max_length=100)
email = forms.CharField(required=True,max_length=100)
number = forms.IntegerField(required=True)
class Meta:
model = EarlyBirds
fields = ("name", "email", "number")
template
<html xmlns="http://www.w3.org/1999/xhtml">
<body align="center">
<form method="POST" action="{%url 'comingsoon:register'%}">
{% csrf_token %}
<div class="header-blog-comingSoon" align="center">
<!--<form method="post">
<span>{{ form.as_p }}</span>
<br/>
<span><button class="comingsoon-Reg" type="submit">Register</button></span>
<br/><br/>
<br/><label class="successLabel">{{success}}</label>
</div>
</form>
</body>
</html>
project.urls.py
from django.conf.urls import include, url
from django.contrib import admin
urlpatterns = [
url(r'^ComingSoon/', include('app_name.urls', namespace="comingsoon")),
url(r'^admin/', include(admin.site.urls)),
]
When I try to execute this code, the all I was able to see in the "Register" button on my html page. The three text fields for Name, Email and Contact number were missing. Please let me know what I am missing over here.
You forgot to add the form to your context:
def register(request):
...
return render_to_response('ComingSoon.html', {'success':success, 'form': form}, context)
Maybe you should try writing your form like this:
class EarlyBirdsForm(forms.ModelForm):
class Meta:
model = EarlyBirds
fields = '__all__'
Much easier and simpler. Since you're using all the attributes in the model, might as well connect the form directly with the model.
And César Bustíos said it right. You didn't add the form in the context dictionary for your template.
I'm following Mike Hibbert's tutorial on links. The site works perfectly fine, however, the input I put in the form is not being updated or transmitted in the database.
from forms import LocationForm
from django.http import HttpResponseRedirect
from django.core.context_processors import csrf
from django.shortcuts import render_to_response
from django.http import HttpResponse
from core.models import Location
from django.shortcuts import render
class LocationListView(ListView):
model = coremodels.Location
template_name='location/list.html'
def create2(request):
if request.method =='POST':
form = LocationForm(request.POST)
if form.is_valid():
form.save
return HttpResponseRedirect('/location/')
else:
form = LocationForm()
args = {}
args.update(csrf(request))
args['form'] = form
return render_to_response('location/create_location.html', args)
my models.py
class Location(models.Model):
title = models.CharField(max_length=300)
description = models.TextField(null=True, blank=True)
address = models.TextField(null=True, blank=True)
hours = models.TextField(null=True, blank=True)
my create_location.html:
{% block sidebar %}
<ul>
<li> Cancel</li>
</ul>
{% endblock %}
<form action="" method="post"> {% csrf_token %}
<ul>
{{form.as_ul}}
</ul>
and finally my forms.py
from django import forms
from models import Location
class LocationForm (forms.ModelForm):
class Meta:
model = Location
fields =('title', 'description', 'address')
<input type="submit" name="submit" value="create location">
</form>
No error or anything, site works perfect, however if I click on create new location and try submit a new location on the create_location.html it goes back to the locations (list.html) but without the new one.
I also tried updating the views with the code from the documentation
return render(request, 'location/create_location.html',{'form': form})
but didn't work.
What do I do wrong?
Thanks in advance
def create2(request):
if request.method =='POST':
form = LocationForm(request.POST)
if form.is_valid():
form.save
You're not calling form.save(), you're just "stating" the function name (which here does nothing).
Use
def create2(request):
if request.method =='POST':
form = LocationForm(request.POST)
if form.is_valid():
form.save()
and you should be good to go.
I have a small question to ask the community. I am wondering why my foreign key will not show up when I go to my edit form. When I go to edit the information, all my data is populated except for status (which is a foreignkey that points from the status table to project table), which is left with nothing selected. I use the same forms.py for both adding and editing information.
models.py
from django.db import models
from clients.models import Clients
from django.contrib.auth.models import User
from settings import STATUS_CHOICES
class Project(models.Model):
client = models.ForeignKey(Clients, related_name='projects')
created_by = models.ForeignKey(User, related_name='created_by')
#general information
proj_name = models.CharField(max_length=255, verbose_name='Project Name')
pre_quote = models.CharField(max_length=3,default='10-')
quote = models.IntegerField(max_length=10, verbose_name='Quote #', unique=True)
desc = models.TextField(verbose_name='Description')
starts_on = models.DateField(verbose_name='Start Date')
completed_on = models.DateField(verbose_name='Finished On')
def __unicode__(self):
return u'%s' % (self.proj_name)
def current_status(self):
try:
return self.status.all().order_by('-id')[:1][0]
except:
return None
class Status(models.Model):
project = models.ForeignKey(Project, related_name='status')
value = models.CharField(max_length=20, choices=STATUS_CHOICES, verbose_name='Status')
date_created= models.DateTimeField(auto_now=True)
def __unicode__(self):
return self.value
class Meta:
verbose_name = ('Status')
verbose_name_plural = ("Status")
views.py
#login_required
def addProject(request):
if request.method == 'POST':
form = AddSingleProjectForm(request.POST)
if form.is_valid():
project = form.save(commit=False)
project.created_by = request.user
project.save()
project.status.create(
value = form.cleaned_data.get('status', None)
)
return HttpResponseRedirect('/project/')
else:
form = AddSingleProjectForm()
return render_to_response('project/addProject.html', {
'form': form, 'user':request.user}, context_instance=RequestContext(request))
#login_required
def editProject(request, proj_id):
proj = Project.objects.get(pk=proj_id)
if request.method == 'POST':
form = AddSingleProjectForm(request.POST,instance=proj)
if form.is_valid():
form.save()
return HttpResponseRedirect('/project/')
else:
form = AddSingleProjectForm(instance=proj)
return render_to_response('project/edit_project.html', {
'form': form}, context_instance=RequestContext(request))
forms.py
from django.db import models
from project.models import Project, Status
from django.forms import *
from django import forms
from settings import STATUS_CHOICES
class AddSingleProjectForm(ModelForm):
status = forms.ChoiceField(choices=STATUS_CHOICES)
class Meta:
model = Project
exclude = ('pre_quote', 'created_by')
Snippet from editproject template:
{% block content %}
<FORM METHOD="POST" ACTION="">
{% csrf_token %}
<table>
{{ form.as_table }}
</table>
<input type="submit" value="Save Project">
</FORM>
{% endblock %}
Any suggestions would be greatly appreciated.
Thank you.
I think this is because project is defined as a ForeignKey on status, and not the other way around. ForeignKey is a One-To-Many relationship. Each project can have multiple statuses connected to it.
That's why on the project instance you'll find: project.status_set and not project.status.
You'll need to add the status to the form manually, by looking for the latest status connected to the project. Or perhaps change the ForeignKey to a OneToOne relationship, depending on your requirements.