Django error in forms.FileField() - django

I have a problem with my app.
A pet store app.
I created 2 forms . The First form allow users to create their own store and save the data into the models which I did successfully and the second form allows users to add their own pets to the pet store.
The first form was successful because it got validated correctly but my second form didn't succeed the validation because in PetForm , I have a field called image = forms.FileField() where users can upload a picture of their pet and the validation fail because the picture does not save anywhere.
I tried to put in an argument into image = forms.FileField(upload_to="images/")
but I received an error
__init__() got an unexpected keyword argument 'upload_to'
I'm reading the documentation at the moment and it state ' When you I use FileField in a form, you must also remember to bind the file data to the form.'.
I'm having trouble understanding binding the file data .
Can someone please help me !
My forms.py
from django import forms
from pet.models import Store
from pet.models import Pet
class StoreForm(forms.ModelForm):
name = forms.CharField(max_length =20,widget =forms.Textarea)
number = forms.CharField(max_length =20,widget =forms.Textarea)
address = forms.CharField(max_length = 20,widget = forms.Textarea)
class Meta:
model = Store
fields = ('name','number','address')
class PetForm(forms.ModelForm):
animal =forms.CharField(max_length = 20,widget = forms.Textarea)
description =forms.CharField(max_length =20, widget = forms.Textarea)
owner = forms.ModelChoiceField(queryset=Store.objects.all())
image = forms.FileField()
class Meta:
model = Pet
fields = ('animal','description','owner','image')
My models.py
from django.db import models
class Store(models.Model):
name = models.CharField(max_length = 20)
number = models.BigIntegerField()
address =models.CharField(max_length = 20)
def __unicode__(self):
return self.name
class Pet(models.Model):
animal = models.CharField(max_length =20)
description = models.TextField()
owner = models.ForeignKey(Store)
image = models.FileField(upload_to="images/",blank=True,null=True)
def __unicode__(self):
return self.animal
This is parts of my views.py
import from django.core.files.uploadedfile import SimpleUploadedFile
def fan(request): # this is the function that saves my form into my models.
form = PetForm(request.POST or None)
if form.is_valid():
dad = form.save(commit=False)
dad.save()
if 'cat' in request.POST:
cat = request.POST['next']
else:
cat = reverse('world:index')
return HttpResponseRedirect(cat)
return render_to_response(
'fan.html',
{'form':PetForm()},
context_instance = RequestContext(request)
)
and My fan.html
<form method="POST" "action">{% csrf_token %}
<ul>
{{ form.as_ul }}
</ul>
<input type = "submit" value= "Add Pets to Store" />
</form>

Because your override your Pet model image. Delete the image in your form.
class PetForm(forms.ModelForm):
animal =forms.CharField(max_length = 20,widget = forms.Textarea)
description =forms.CharField(max_length =20, widget = forms.Textarea)
owner = forms.ModelChoiceField(queryset=Store.objects.all())
class Meta:
model = Pet
fields = ('animal','description','owner','image')
//It's not necessary to defined again model field in the form. Once you call the model
//in the form it's understood what you want to show. You can only defined the model
//field again if you want something to add or embed in that field. Like for example you
//want to change the charfield in to textarea or you defined a queryset like you did
//above. Erase your max_length because you are already defined that in the model.
When you upload images don't forget to add "multipart/form-data" in the form
<form method="POST" enctype="multipart/form-data" "action" >
{% csrf_token %}
<ul>
{{ form.as_ul }}
</ul>
<input type = "submit" value= "Add Pets to Store" />
</form>

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>

Django Form based on Form

I am writing my code based on the principle don't repeat yourself. I keep violating that rule because I am new to Django but this one should be straight forward.
The code below is no problem for ModelAForm:
model.py
class ModelA(models.Model):
id = model.AutoField(primary_key=True)
name1 = models.CharField(max_length=100)
name2 = models.CharField(max_length=100)
...
right = models.BooleanField(default=True)
class ModelB(models.Model):
id = model.AutoField(primary_key=True)
mod = model.ForeignKey(ModelA, on_delete=models.CASCADE)
above30 = models.BooleanField(default=True)
forms.py
class ModelAForm(forms.ModelForm):
class Meta:
model = ModelA
exclude = ['id']
class ModelBForm(forms.ModelForm):
class Meta:
model = ModelB
exclude = ['id']
But this way I don't see the other fields of modelA in the ModelBForm. How can I do this?
Thanks!
Well, it should not. Because its FK relation between ModelB and ModelA. So in ModelB form, the ModelA entries should appear as a choice field. If you want to show fields of ModelA then try like this:
First, remove the FK reference field from ModelBForm:
class ModelBForm(forms.ModelForm):
class Meta:
model = ModelB
exclude = ['id', 'mod']
Now Use both those forms in your view:
def some_view(request):
if request.method == 'GET':
return render(request, 'template.html', {'form_a': ModelAForm(), 'form_b': ModelBForm()})
if request.method == 'POST':
form_a = ModelAForm(request.POST)
form_a = ModelBForm(request.POST)
if form_a.is_valid() and form_a.is_valid():
instance_a = form_a.save() # get model a instance
instance_b = form_b.save(commit=False)
instance_b.mod = instance_a # set model a instance as FK
instance_b.save()
Render the Form Like this:
<form action="." method="post">
{% csrf_token %}
{{ form_a.as_p }}
{{ form_b.as_p }}
<input type="submit" value="Submit">
</form>

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 passing object ID in hiddeninput by populating

I have an form which allows a user to edit an object description.
How can I populate an object ID in a form's hidden input value.
What I done so far is I added an field called hidden_field in forms.py but it only show the hidden_field . How can I link the hidden_field with the object ID
models.py
class School(models.Model):
user = models.ForeignKey(User)
name = models.CharField(max_length=55)
description = models.CharField(max_length=300,blank=True)
forms.py
class SchoolDescriptionForm(forms.ModelForm):
description = forms.CharField(widget=forms.Textarea,max_length=300)
hidden_field = forms.CharField(widget=forms.HiddenInput())
class Meta:
model = School
fields = ()
views.py
def SchoolEditor(request,school_id):
school = School.objects.get(pk=school_id,user=request.user)
form = SchoolDescriptionForm(instance=school) # I want to populate the object ID
return render(request,'schooleditor.html',{'school':school,'form':form})
template
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<input type = "submit" value= "save" />
{{ form.field.as_hidden }}
</form>
Change hidden_field to id and tell Django to include the School's id.
class SchoolDescriptionForm(forms.ModelForm):
description = forms.CharField(widget=forms.Textarea,max_length=300)
id = forms.CharField(widget=forms.HiddenInput())
class Meta:
model = School
fields = ('id', 'name', 'description')
EDIT:
If you want to conserve hidden_field as name you should then add a custom init method:
def __init__(self, *args, **kwargs):
super(SchoolDescriptionForm, self).__init__(*args, **kwargs)
if self.instance:
self.fields['hidden_field'].initial = instance.id
Just pass the object id in the form initial:
def SchoolEditor(request,school_id):
initial = {}
school = School.objects.get(pk=school_id,user=request.user)
if school:
initial.update({'hidden_field': school.id})
form = SchoolDescriptionForm(instance=school, initial=initial) # I want to populate the object ID
return render(request,'schooleditor.html',{'school':school,'form':form})

Set a non-null, but non-displayed django form field before form.save()

Am using django forms on my app. I have a model Client like this:
class Client(models.Model):
client_name = models.CharField(max_length=50)
email = models.EmailField(max_length=75)
password = models.CharField(max_length=128)
is_active = models.BooleanField()
last_login = models.DateTimeField(null=True)
class Meta:
db_table = u'client'
Then I have some other models 'Asset,AssetType` and then also specify a form for allowing a client to define their own assets - the asset types are created by the admin.
class AssetType(models.Model):
name = models.CharField(max_length=50)
class Meta:
db_table = u'assettype'
def __unicode__(self):
return self.name
class Asset(models.Model):
name = models.CharField(max_length=50)
type = models.ForeignKey(AssetType)
number = models.CharField(max_length=20)
client = models.ForeignKey(Client)
class Meta:
db_table = u'asset'
def __unicode__(self):
return self.name
class AssetForm(ModelForm):
class Meta:
model = Asset
Now, my problem is that when the Client is logged in, and the want to create a new Asset, the AssetForm, which I render like this, in the asset.html:
<FORM id="newasset_form" method="POST" action="/assets/">
{% csrf_token %}
<TABLE cellpadding="3" border="0" cellspacing="5">
<tr><th colspan="2">define a new asset</th></tr>
{{ form }}
<td align="center" colspan="2"><input type="submit" name="btn" id="btn" value="create asset" /></td>
</TABLE>
</FORM>
On the resultant form displayed to the Client, this setup displays the client field of the new Asset as a select with a drop-down of all existing clients, something I want to avoid. I want that client field to be auto-linked to the client whose session created the form - the currently logged in client, and not allow them to set the client to any other client. so how do i do this?
I had tried doing this, after the AssetForm is posted, to assign this client to the form's client field, then save, but it doesnt work!
if request.method == 'POST':
asset_form = AssetForm(request.POST)
if asset_form.is_valid():
asset_form.client = client
asset_form.save()
I want to define my form as :
class AssetForm(ModelForm):
class Meta:
model = Asset
exclude = ('client')
so that a client, can't tamper with the client field at all, when creating the new Asset.
class AssetForm(ModelForm):
class Meta:
model = Asset
exclude = ('client',) # don't forget that comma
Use the commit argument of the save method (docs):
if asset_form.is_valid():
instance = asset_form.save(commit=False)
instance.client = client
instance.save()
or create an instance of Asset where client is set and use that for the instance argument of creating your form:
def someview(request):
client = Client.objects.get(pk=<some_pk>)
asset = Asset(client=client)
if request.method == 'POST':
form = AssetForm(request.POST, instance=asset)
if form.is_valid():
form.save()
return HttpResponse('success')
else:
form = AssetForm(instance=asset)
context = {'form':form}
return render_to_response('some_template.html', context,
context_instance=RequestContext(request))