Django Form and Image Upload on same page - django

I'm trying to figure out how to upload an image and get user input on a single form.
My models:
class Image(models.Model):
artist = models.ForeignKey('Artist')
image = models.ImageField(upload_to="assets/images")
class Album(models.Model):
artist = models.ForeignKey(Artist,null=True)
notes = models.CharField(max_length = 50)
display = models.BooleanField()
date_created = models.DateTimeField(auto_now_add=True)
My forms
class AlbumForm(forms.ModelForm):
class Meta:
model = Album
fields = ('notes',)
class ImageForm(forms.ModelForm):
class Meta:
model = Image
exclude = ('artist')`
I think my view is wrong and how would I pass the two forms to the template? What would the template look like to render the two forms? I want to use a single submit button.
def create(request):
form1 = ImageForm(request.POST, request.FILES or None)
form2= AlbumForm(request.POST or None)
if form2.is_valid() and form1.is_valid():
image = form1.save(commit=False)
image.artist = Artist.objects.get(pk=3)
image.save()
album = form2.save(commit=False)
album.save()
if 'next' in request.POST:
next = request.POST['next']
else:
next = reverse('art_show')
return HttpResponseRedirect(next)
return render_to_response(
'art/create.html',
{'ImageForm':form1},
{ 'AlbumForm': form2},
context_instance = RequestContext(request)
)

You could probably do something like this:
<form action="." method="post" enctype="multipart/form-data">
{{ImageForm.image}} <br />
{{AlbumForm.notes}} <br />
{{AlbumForm.display}} <br />
...
<input type="submit" value="Save" />
</form>
This will return both form1 and form2 objects in your request.POST object.
views.py:
...
return render_to_response('art/create.html',
{'ImageForm': form1, 'AlbumForm': form2},
context_instance = RequestContext(request)
)
Or you could do this:
...
return render_to_response('art/create.html',
locals(),
context_instance = RequestContext(request)
)
Although, the second one will add all variables your function uses so you should make sure that if you use it that your function won't be using any builtin names. Usually uncommon, but you should just make sure.
EDIT: Added a submit button to make it clear you only need one. Also added the view's response.

Related

Django set ModelForm field without including it in the form

In my app, I have Users create Post objects. Each Post has a User
class Post(models.Model):
user = models.ForeignKey(User, on_delete = models.CASCADE)
...
I want to create a post-submission form for editing and submission, so I plan to use Django's ModelForm functionality.
class PostForm(ModelForm):
class Meta:
model = Post
fields = "__all__"
However, if I do this, then whoever is viewing the form will be able to set who the Post author is. I want to make sure that the resulting user field is them. But, if I exclude the user field from the ModelForm,
class PostForm(ModelForm):
class Meta:
model = Post
exclude = 'user'
then the user will not be set on form submission. I've hacked my way around this by making a custom form and updating the post field
def submit_view(request):
....
request.POST = request.POST.copy()
request.POST.update({
'user' : request.user.id
})
form = PostForm(request.POST, request.FILES)
....
but then I lose automatic UI generation and form validation, which in some ways defeats the purpose of the Form class. Could somebody point me to the idiomatic way of setting the user field without including it in the Form?
Try this view:
def submit_view(request):
form = PostForm(request.POST or None)
if form.is_valid():
new_post = form.save(commit=False)
new_post.user = request.user
new_post.save()
view.py
from django.views.generic import CreateView
from .models import Post
class PostCreate(CreateView):
model = Post
template_name ="new_Post_form.html"
fields = ['text']
def form_valid(self, form):
object = form.save(commit=False)
object.user = self.request.user
object.save()
return super(PostCreate, self).form_valid(form)
def get_success_url(self):
return "/"
url.py
url(r'^newpost$',views.PostCreate.as_view(),name='post_new',),
new_post_form.html
<form method="post" enctype="multipart/form-data" class="form" action="newpost" id="new-post-form">
<div class="modal-body">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" />
</div>

Uploading image in template

I created two models:
class Country(models.Model):
name = models.CharField(max_length=50)
class City(models.Model):
name = models.CharField(max_length=50)
country = models.ManyToManyField(Country)
image = models.ImageField('New photos', upload_to='img/newphotos', blank=True)
I want add new cities through template so i created:
views.py
def newcity(request):
if request.method == "POST":
form = CityForm(request.POST)
if form.is_valid():
city = form.save(commit=False)
city.save()
form.save_m2m()
return redirect('city.views.detailcity', pk=city.pk)
else:
form = CityForm()
return render(request, 'city/editcity.html', {'form': form})
forms.py:
class CityForm(forms.ModelForm):
class Meta:
model = City
fields = ('name', 'country', 'image',)
Everything is ok but when I add image there is nothing happens - image is chosen but when I click save button new city is added without image (in admin panel it works). What must I add to my code? And how can i make possibility to add to one city few images? When i will add first image there should appear button to add second etc. Now I have place only for one.
Add request.FILES in your views
form = CityForm(request.POST, request.FILES)
and make sure you have enctype="multipart/form-data" and method="post" in your template
<form method="post" enctype="multipart/form-data">{% csrf_token %}
</form>
https://docs.djangoproject.com/en/dev/ref/request-response/#django.http.HttpRequest.FILES

Django Model form is not shown

I am probably missing something very simple, because my model form is not shown at the template. The code is very simple:
models.py:
class Story(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL)
title = models.CharField(max_length=200)
content = models.TextField()
picture = models.ImageField(upload_to = 'images/post_images')
date = models.DateTimeField(auto_now_add=True)
forms.py:
class StoryForm(forms.ModelForm):
class Meta:
model = Story
views.py:
from sfv.forms import StoryForm
#login_required(redirect_field_name=None)
def restricted(request):
user = request.user
form = StoryForm()
#graph = get_persistent_graph(request)
return render(request, "restricted.html", {user : 'user', form : 'form',})
template:
<form method = 'POST' action = ''>
<table>
{{ form }}
<table>
</form>
I have also tried form.as_p, that didnt help.
Change your render method from
return render(request, "restricted.html", {user : 'user', form : 'form',})
to
return render(request, "restricted.html", { 'user' : user, 'form' : form})
The key and value in the context dictionary were interchanged. Hence the issue.

Storing form data in the database

I can't figure out how to store a simple form in the database. I think I'm quite close but there is probably something wrong in my views.py. Here is my code, any ideas what I'm doing wrong? (also on dpaste)
# models.py
class IngredienceCategory(models.Model):
name = models.CharField(max_length=30, unique=True)
user = models.ForeignKey(User, null=True, blank=True)
class Meta:
verbose_name_plural = "Ingredience Categories"
def __unicode__(self):
return self.name
# forms.py
class CategoryForm(forms.Form):
name = forms.CharField(max_length=30)
# views.py
#login_required
def newCategory(request):
if request.method == 'POST':
username = request.user.username
cform = CategoryForm(request.POST)
if cform.is_valid():
formInstance = cform.save(commit = False)
formInstance.user = username
formInstance.name = cform.cleaned_data['name']
formInstance = IngredienceCategory.objects.filter(name=formInstance.name, user=formInstance.user)
formInstance.save()
# return HttpResponseRedirect('new-category/')
else:
form = CategoryForm()
context = {'form': form}
return render_to_response('new-category.html', context, context_instance=RequestContext(request))
# new-category.html
<h3>Insert New Category</h3>
<form action="/" method="post" id="food-form">{% csrf_token %}
{{ form.as_p }}
<input type="submit" name="foodForm" value="Save" />
</form>
The line below is not useful at it current position. That command will perform a database query and assign the result as a queryset, before you have saved the form data.
formInstance = IngredienceCategory.objects.filter(name=formInstance.name, user=formInstance.user)
This should work:
With cform as a normal Form:
if cform.is_valid():
formInstance = IngredienceCategory(user=request.user, cform.cleaned_data['name'])
formInstance.save()
If cform had been a ModelForm you could do:
if cform.is_valid():
formInstance = cform.save(commit=False)
formInstance.user = request.user
formInstance.save()
I do recommend you to check out ModelForms since it will build the cleaning functionality based on your model.
You should inherit from ModelForm
from django.forms import ModelForm
class CategoryForm(ModelForm):
class Meta:
model = IngredienceCategory
Refer to https://docs.djangoproject.com/en/dev/topics/forms/modelforms/ for how to render form and save it to database.

django - how to create a preview view

i have an add page to create a new post.and i want to add a link(ahref) to preview the post at the moment. i have one form and one submit button to save the post into db. i should use the same form to preview. when i click 'preview' link the page must redirect to 'preview.html' which i can display values of form in.
i am stuck. i cannot create the algorhytm for this in my mind. there is one page.one form. one view(addPost) . and i need to reach the values of this form by another view which has another template file.
and i have two fields in models py , called 'titlepreview' and 'bodyPreview'. to see values of form in preview page ; form datas should be written into these two fields.
here models.py:
class Post(models.Model):
owner = models.ForeignKey(User)
title = models.CharField(max_length = 100)
body = models.TextField()
bodyPreview = models.TextField() #preview
titlePreview = models.CharField(max_length=100) # preview
slug = AutoSlugField(populate_from='title',unique=True)
posted = models.DateField(auto_now_add=True)
isdraft = models.BooleanField(default=False)
here is my add_post view:
#login_required(login_url='/login/')
def add_post(request):
if request.method=="POST":
form = addForm(request.POST)
if form.is_valid():
titleform=form.cleaned_data['title']
bodyform=form.cleaned_data['body']
checkform=form.cleaned_data['isdraft']
owner = request.user
n = Post(title = titleform, body = bodyform, isdraft=checkform, owner=owner)
n.save()
return HttpResponseRedirect('/admin/')
else:
form=addForm()
return render(request,'add.html',{'form':form,})
return render_to_response('add.html',{'form':form,},context_instance=RequestContext(request))
my addForm form :
class addForm(forms.Form):
title = forms.CharField(max_length=100,widget=forms.TextInput(attrs={'placeholder':'Buraya Başlık Gelecek',}))
body = forms.CharField(widget=forms.Textarea(attrs={'placeholder':'Buraya Metin Gelecek','rows':'25','cols':'90',}))
isdraft = forms.BooleanField(required=False)
#ispreview = forms.BooleanField(required=False) i just added this line as first step. :)
if another code needed ; you can comment below
thank you
Convert your addForm to a modelForm, and then add a submit button to your add.html template with the name '_preview' (make sure your other submit button is named '_save'). The code would look something like this:
class addForm(forms.ModelForm):
class Meta:
model = Post
#login_required(login_url='/login/')
def add_post(request):
post = None
template_name = 'add.html'
if request.method == 'POST':
form = addForm(request.POST)
if form.is_valid():
if '_preview' in request.POST:
# don't save the post
post = form.save(commit=False)
template_name = 'preview.html'
elif '_save' in request.POST:
# save the post
post = form.save()
return HttpResponseRedirect('/admin/')
else:
form = addForm()
return render_to_response(template_name, {'form': form, 'post': post}, context_instance=RequestContext(request))
Your template would have something like this at the bottom:
<input type='submit' name='_save' value='Save Post' />
<input type='submit' name='_preview' value='Preview Post' />
By doing it this way, you can let the user preview their post without saving it to the database - just make sure that on preview.html, you embed the form and include a save button so that they can save the post if they like what they see.