Uploading image in template - django

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

Related

Can not add values from forms to Django models

I made a form and there I had a multiple-choice field called artists which I got from my database and while adding a song a user can select multiple artists and save the song.
The artists are a ManyToManyField in Django models.
models.py
class Artists(models.Model):
""" Fields for storing Artists Data """
artist_name = models.CharField(max_length = 50, blank = False)
dob = models.DateField()
bio = models.TextField(max_length = 150)
def __str__(self):
return self.artist_name
class Songs(models.Model):
""" Fields for storing song data """
song_name = models.CharField(max_length = 30, blank = False)
genre = models.CharField(max_length = 30, blank = False)
artist = models.ManyToManyField(Artists)
release_date = models.DateField()
forms.py
class Song_input(forms.Form):
queryset = Artists.objects.only('artist_name')
OPTIONS = []
for i in queryset:
s = []
s = [i, i]
OPTIONS.append(s)
artist_name = forms.MultipleChoiceField(widget=forms.CheckboxSelectMultiple,choices=OPTIONS)
song_name = forms.CharField()
genre = forms.CharField()
release_date = forms.DateField(widget=DateInput)
Now I want to get all the values selected from the form and save to my database. Here the artist_name may have multiple values.
I have tried using the add() and create() methods but can not figure out how to add all the data where one field (artist_name) having multiple data to my database.
I strongly advise to make use of a ModelForm [Django-doc]. Especially since you make use of ManyToManyFields, which are more cumbersome to save yourself.
# app/forms.py
from django import forms
class SongForm(forms.ModelForm):
class Meta:
model = Songs
fields = '__all__'
widgets = {
'artist': forms.CheckboxSelectMultiple,
'release_date': forms.DateInput
}
There is thus no need to specify the fields yourself, you can change the widgets by adding these to the widgets dictionary [Django-doc] of the Meta subclass.
In your view, you can then both render and sae objects with that form:
# app/views.py
from app.forms import SongForm
def add_song(request):
if request.method == 'POST':
form = SongForm(request.POST, request.FILES)
if form.is_valid():
form.save()
return redirect('name-of-some-view')
else:
form = SongForm()
return render(request, 'some-template.html', {'form': form})
The form.save() will save the object in the database.
In the template, you can then render the template:
<form method="post" action="{% url 'name-of-add_song-view' %}">
{% csrf_token %}
{{ form }}
<input type="submit" value="Submit">
</form>

How can I autofill author with a model form (video upload)

I need to tie the user to their post but 'author' is not included in the fields of the video upload form so I can't access the field when I save the form.
When I add 'author' to the fields it gives a drop down box. (users shouldn't be able to post as anyone but themselves) I tried just listing the fields individually like so {{form.title}} to keep the author field but not show it to the user, it showed anyway.
In the 'author' field of the VideoPost model I've tried changing out the null=True for these variants on default default=None, default=0, default='None', default=User, default=User.id where User = get_user_model()
When I used default='None' the author dropdown box had the current users name in it, but still allowed a choice, when I tried to post it I got
ValueError: invalid literal for int() with base 10: 'None'
Also, in the views.py, I tried form = VideoPostForm(request.user,request.POST or None, request.FILES or None)
and got CustomUser object has no .get() attribute and that was caused by form.save()
I feel like this might be obvious to someone else but I've been staring at this code for a while now to figure it out.(a couple hours a day doing research and gaining better understanding as to how all of the things I'm doing actually work 'under the hood', I worked on other parts while trying to figure this out because, development speed matters and I could actually figure the other stuff out)
forms.py
class VideoPostForm(forms.ModelForm):
class Meta:
model = VideoPost
fields = ['author','title', 'description', 'file']
views.py
def upload_video(request):
form = VideoPostForm(request.POST or None, request.FILES or None)
if form.is_valid():
form.save(commit=False)
VideoPost.author = request.user
form.save()
return redirect('home')
else:
form = VideoPostForm()
return render(request, 'upload_video.html', {'form': form})
models.py
class VideoPost(models.Model):
objects = models.Manager()
author = models.ForeignKey(User, related_name='video_post', on_delete=models.CASCADE, null=True)
title = models.CharField(max_length=50, null=True, blank=True)
published_date = models.DateTimeField(auto_now_add=True)
description = models.TextField()
validate_file = FileValidator(max_size=52428800)
file = models.FileField(upload_to='videos/', validators=[validate_file])
def __str__(self):
return 'Post by {}'.format(self.author)
template (excluding author field)
<h1>Create Post Page</h1>
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
<p> <!-- Normally the fields would be form.as_p -->
{{ form.title }}
{{ form.description }}
{{ form.file }}</p>
<button type="submit">Submit New Post</button>
</form>
The views.py is very close. The form.save() method returns an instance of VideoPost. You can then set the author to the current user directly to the new video post object that was created by the form. See code sample below.
views.py
def upload_video(request):
if request.method == "POST":
form = VideoPostForm(request.POST, request.FILES or None)
if form.is_valid():
new_videopost = form.save()
new_videopost.author = request.user
new_videopost.save()
return redirect('home')
else:
form = VideoPostForm()
return render(request, 'upload_video.html', {'form': form})

I have issue with saving form: add_product to be specific in django

I am trying to save simple form add_product, I don't have any error but the new product doesn't appear in admin or on a page. I really not sure what I am doing wrong. Any suggestion would be great! Thank you.
my views.py
def add_product(request):
author = request.user
product_form = ProductForm(request.POST, request.FILES, instance=author)
if product_form.is_valid():
form = product_form.save(commit=False)
form.save()
return HttpResponseRedirect('/products/')
else:
product_form = ProductForm()
return render(request, 'products/add_product.html', {'product_form': product_form})
my forms.py
class ProductForm(forms.ModelForm):
class Meta:
model = Product
fields = ('title', 'content', 'picture',)
urls.py
urlpatterns = patterns('',
url(r'^$', views.all, name='all'),
url(r'^add/$', views.add_product, name='add_product'),
url(r'^(?P<slug>[\w-]+)/$', views.single_product, name='single_product'),
)
template: products/add_product.html
<h1>Add Product</h1>
<form method="post" action="" enctype="multipart/form-data"> {% csrf_token %}
{{ product_form.as_p }}
<input type="submit" value="Add">
</form>
models.py
class Product(models.Model):
title = models.CharField(max_length=100)
author = models.ForeignKey(User)
content = models.CharField(max_length=300)
slug = models.SlugField(unique=True)
picture = models.ImageField(upload_to='products/picture/', blank=True)
def __unicode__(self):
return self.title
def get_absolute_url(self):
return reverse('single_product', kwargs={'slug': self.slug})
I fixed my view.py by adding following line :
form.author = request.user
and I removed the first line : author = request.user plus the instance as well.
So now works fine :)
Your code doesn't seem to be valid. And there should be errors.
The first thing that is notice is following:
author = request.user
product_form = ProductForm(request.POST, request.FILES, instance=author)
You are passing user instance as a instance to author form. That doesnt make any sense. For product form instance should a product, not a user. If you want to set a author field you can do following :
form = product_form.save(commit=False)
form.author = author
form.save()
Also its not good to call this variable form, because its not a form anymore, its a product object that is returned by save function.

Django - Saving a form form multiple model

I am new in Django, and trying to create a simple blog platform out of it. It's where user can create/edit a blog post on the front end.
Here is my models.py
class Blog(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
author = models.ForeignKey(User, null=True, blank=True)
......
class Categories(models.Model):
blog = models.ForeignKey(Blog)
name = models.CharField(max_length=200)
slug = models.CharField(max_length=200)
......
And I created a form in the front end by :
#forms.py
class AddBlogForm(forms.ModelForm):
class Meta:
model = Blog
class AddCategoryForm(forms.ModelForm):
class Meta:
model = Categories
#views.py
def AddBlogPost(request):
if request.POST:
lf= AddBlogForm(request.POST, request.FILES,prefix="Lform")
cf = AddCategoryForm(request.POST, prefix="Cform")
if lf.is_valid() and cf.is_valid():
addblog = lf.save(commit=False)
addblog.save()
obj_id = addblog.id
addcategory = cf.save(commit=False)
addcatgory.blog_id = obj_id
addcatgory.save()
return HttpResponseRedirect(reverse('edit', args=(obj_id,)))
else:
blog= AddBlogForm(prefix="Lform")
category = AddCategoryForm(prefix="Cform")
return render_to_response("forms.html", locals(),context_instance=RequestContext(request))
#template
<form action="" enctype="multipart/form-data" method="POST">{% csrf_token %}
{{blog.as_p}}
{{category.as_p}}
<input type="submit">
</form>
This working actually, but I feel it is too redundant create and saving a form with two classes.It's there anyway to simplified this?
You can use django forms to save data from a form to multiple models. For example:
forms.py
class AddBlogCategory(forms.Form):
title= form.CharField(max_length=100)
content= form.CharField(max_length=255)
...............
...............
views.py:
def AddBlogPost(request):
if request.POST:
form= AddBlogCategory(request.POST)
if form.is_valid():
addblog= Blog() #import model class
addblog.title= form.cleaned_data['title']
addblog.content= form.cleaned_data['content']
addblog.author= request.user
.....
addblog.save()
obj_id= addblog.id
addcat=Categories()
addcat.blog= addblog
....
addcat.save()
return HttpResponseRedirect(reverse('edit', args=(obj_id,)))
else:
return render_to_response("forms.html", {form:'form'})
Its an untested code, but you can have an idea how to implement it.

Django Form and Image Upload on same page

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.