How to initialize value of foreign key in Django form - django

Im trying to initialize a model form where both fields are foreign key.
Model:
class Subcohort(models.Model):
cohort_id=models.ForeignKey(Cohort,on_delete=models.PROTECT,default=0,db_constraint=False,related_name='subcohortid')
parent_id=models.ForeignKey(Cohort,on_delete=models.PROTECT,default=0,db_constraint=False,related_name='subparentid')
Form:
class SubcohortForm(forms.ModelForm):
class Meta:
model = Subcohort
fields = [
"cohort_id","parent_id",
]
Views:
initialvalue2={
'cohort_id':int(cohortidnew),
'parent_id':id,
}
form2 = SubcohortForm(initialvalue2)
if form2.is_valid():
return redirect('/dashboard')
It is saying my form is not valid. Can someone explain what is the reason behind this and how to fix this?
Thanks.

Because, you have not saved that form after validation.
let's save it:
if form2.is_valid():
form2.save()
return redirect('/dashboard')
And now your problem will be solved..

If you need the form intialize with these values, then please pass the values using initial parameter when initiaiting form object:
initialvalue2={
'cohort_id':int(cohortidnew),
'parent_id':id,
}
form2 = SubcohortForm(initial = initialvalue2)
You can send this form2 instance to the template directly without validating it. But you should check if the form is valid on post request. For example:
if request.method == 'GET':
form2 = SubcohortForm(initial = initialvalue2)
return render(request, template_name, context={'form2':form2})
else:
form = SubcohortForm(request.POST)
if form.is_valid():
form.save()
return redirect('dashboard')
else:
return render(request, template_name, context={'form2':form})

Related

Delete record without accessing it directly

I am creating a data visualisation site in django and using the rest api for my data. Is there any way of deleting a record without accessing its url directly, as in this case it is impossible.
Something like
def employee_delete(request):
instance = Employee.objects.get(social_security=request.POST)
instance.delete()
return render(request, "dashboard.html")
This only works if you have access to the console as I learned, so I tried to access the data from a form like so
def employee_delete(request):
if request.method == "POST":
form = delete_EmployeeForm(request.POST, request.FILES)
if form.is_valid():
instance = Employee.objects.get(social_security=request.POST)
instance.delete()
return render(request, "dashboard.html")
else:
form = delete_EmployeeForm()
return render(request, "deleteemployee.html",{'form': form})
Would this work if I was able to be more specific about which piece of data I was accessing from the form? I got a typeError trying to use request.Post in that manner. That form contained a single field in 'social_security' from the Employee model.
Thanks
def employee_delete(request):
if request.method == "POST":
form = delete_EmployeeForm(request.POST, request.FILES)
if form.is_valid():
instance = Employee.objects.get(social_security=request.POST['social_security'])
instance.delete()
return render(request, "dashboard.html")
else:
form = delete_EmployeeForm()
return render(request, "deleteemployee.html",{'form': form})
use this in your view

Create, get and edit user information in same form and template

I'm trying to retrieve data from user. The form where i want to show the user information is also the same that i use to update this information.
Update3
After some updates I make this work and this is my code. If somenone have a better way to do this can share it :)
models.py
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class informacionFacturacion(models.Model):
usuario = models.ForeignKey(User, on_delete=models.CASCADE)
apellidos = models.CharField(max_length=100)
nombres = models.CharField(max_length=100)
[More fields...]
def __str__(self):
self.apellidos
forms.py
from .models import informacionFacturacion
#Create your forms here.
class informacionFacturacionForm(ModelForm):
class Meta:
model = informacionFacturacion
fields = [
"usuario",
"apellidos",
"nombres",
[More fields...]
]
views.py
#login_required
def datosPersonales(request):
#Filter query by user ID
query = informacionFacturacion.objects.filter(usuario=request.user)
form = informacionFacturacionForm()
#If query has content, edit record, else, create a new record
if query:
if request.method == "POST":
form = informacionFacturacionForm(request.POST or None, instance=query[0])
if form.is_valid():
edit_content = form.save()
edit_content.save()
else:
if request.method == "POST":
form = informacionFacturacionForm(request.POST)
if form.is_valid():
create_content = form.save(commit=False)
create_content.save()
return HttpResponseRedirect(reverse('datosPersonales'))
context = {
"titulo": "Datos personales | Co.",
"body_class": "class= sidebar_main_open sidebar_main_swipe",
"form": form,
"infoFacturacion": query,
}
template = "micuenta/datosPersonales.html"
return render(request, template, context)
Thanks for the support.
At first glance, it seems that the informacionFacturacion table is not being populated. Have you checked that the instance.save() is reached? (in other words, that the form is valid)
Second, in the template you want to use the informacionFacturacion object as the form elements, and you are handling them separately. Do:
if request.POST:
form = informacionFacturacionForm(request.POST)
if form.is_valid():
instance = form.save(commit=False)
instance.save()
else:
# handle here the form error's, maybe report it in the template
else:
query = informacionFacturacion.objects.filter(usuario=request.user)
form = informacionFacturacionForm(instance=query[0])
and render the form parameter insead of infoFacturacion:
{{ form.as_p }}
finally, make sure that your template form id's matches the form element names, otherwise the form won't be filled.
UPDATE
Based on your edit, now the error is in this line:
form = informacionFacturacionForm(request.POST, instance=query_id)
query_id is an int, and it is expecting a model. Change the following line:
query_id = informacionFacturacion.objects.get(usuario=request.user).id
to
query = informacionFacturacion.objects.get(usuario=request.user)
and the faulty line to:
form = informacionFacturacionForm(request.POST, instance=query)
that should work for now, although code can be simplified a lot.
EDIT 2
Here is what I assume you want:
#login_required
def datosPersonales(request):
query = informacionFacturacion.objects.filter(usuario=request.user)
if request.method == "POST": # This will handle the template form's POST
form = informacionFacturacionForm(request.POST)
if form.is_valid():
asd = form.save(commit=False)
asd.save()
# Here you may want to redirect to somewhere else
# Im not sure here, I guess that you want to handle the GET method if
# there is no form in the request. Post your template form to see what
# is happening.
else:
form = informacionFacturacionForm(instance=query)
# you dont need to save it, it is already in DB
context = {
"titulo": "Datos personales | Co.",
"body_class": "class= sidebar_main_open sidebar_main_swipe",
# I think here is your main issue, you are handling a form object
# AND a infoFacturacion object. You need to use just the
# form object in the template and render it accordingly.
"form": form,
"infoFacturacion": query,
}
template = "micuenta/datosPersonales.html"
return render(request, template, context)
Well, I was with the same problem on my sytem, so I made this solution, maybe it works to you! =D
I'm changing the value of the submit button and using the same form:
<button type="submit" id="submitButton" name="button" value="">Save</button>
If is a new task, I change the value of the button with JQuery:
$('#submitButton').val('new');
And if is an edition, I change the value again:
$('#submitButton').val('edit');
On my views.py, I check if is an edit or a new save by the value of the button:
def index(request):
tasks = Task.object.filter()
context = {
'tasks': tasks
}
if request.method == 'POST':
form = NewTask(request.POST or None)
if request.POST['button'] == 'new':
if form.is_valid():
context['is_valid'] = True
form.save()
form = NewTask()
else:
context['is_valid'] = False
if request.POST['button'] == 'edit':
instance = Task.object.filter(pk=request.POST['id']).first()
form = NewTask(request.POST, instance=instance)
if form.is_valid():
context['is_valid'] = True
form.save()
else:
context['is_valid'] = False
else:
form = NewTask()
context['form'] = form
return render(request, 'index.html', context)

Django handle new ManyToManyField items with get_or_create()

I have a model with a ManyToManyField and in my view I want to be able to add new options to the generated selectbox
How can I handle those new items with get_or_create function?
I want to check for form validity before saving it, but it will never be valid because I have to create all the new ManyToMany items.
In the meantime, I don't want to add new items if the form is not valid...
So I'm stuck with this not-working-code:
def add_entry(request):
if request.method == 'POST':
form = EntryForm(data=request.POST)
model_instance = form.save(commit=False)
for tag in model_instance.tags.all():
t, created = Tag.objects.get_or_create(author=request.user, title=tag.title)
model_instance.tags.add(t)
if form.is_valid():
model_instance.save()
return HttpResponseRedirect("/")
else:
form = EntryForm()
return render_to_response(
'add_entry.html',
{'form' : form },
context_instance=RequestContext(request))
EDIT:
my code is now
def add_entry(request):
if request.method == 'POST':
form = EntryForm(data=request.POST)
if form.is_valid():
model_instance = form.save(commit=False)
model_instance.save()
form.save_m2m()
return HttpResponseRedirect("/")
else:
print form.errors
else:
form = EntryForm()
return render_to_response(
'add_entry.html',
{'form' : form },
context_instance=RequestContext(request)
)
and i can save existing tags, but i can't dinamically add new ones...
I guess you are using some sort of JS to add the tags dynamically. I suggest you to go further and create an API endpoint where you can actually save the created tags so they can became a valid options of the selectbox.

Auto Fill ModelForm with data already stored in database

I got a form as shown below and I want it to be filled with information from the database when its HTML is rendered. I am passing the id of the Coworker as a parameter for the view.
See code below:
view.py
def EditCoworker(request, id):
form = FormEditCoworker(Coworkers.objects.get(id=id))
if request.method == "POST":
form = FormEditCoworker(request.POST)
if form.is_valid():
form.save()
confirmation_message = "Coworker information updated successfully!"
return render(request, "coworkers/coworkers.html", locals())
else:
return render(request, "coworkers/edit_coworker.html", locals())
return render(request, 'coworkers/edit_coworker.html', locals())
forms.py
class FormEditCoworker(ModelForm):
class Meta:
model = Coworkers
urls.py
url(r'^edit_coworker/(?P<id>[\d]+)$', views.EditCoworker),
Of course the code in my views.py is not right.
Can someone help me on this?
Thanks in advance!
This line
form = FormEditCoworker(Coworkers.objects.get(id=id))
Should be
form = FormEditCoworker(instance=Coworkers.objects.get(id=id))
Although you should really handle the case where the Coworker doesn't exist
form = FormEditCoworker(instance=get_object_or_404(Coworkers, id=id))
EDIT: As Alisdair said, you should also pass the instance keyword arg to the bound form also
instance = get_object_or_404(Coworkers, id=id)
form = FormEditCoworker(instance=instance)
if request.method == "POST":
form = FormEditCoworker(request.POST, instance=instance)

Insert or update data with Django formsets

it's not clear to me how to manage formsets in Django. This is my views.py:
def newAd(request):
newAdFormSet = modelformset_factory(Ad)
if request.method == 'POST':
formset = newAdFormSet(request.POST, request.FILES)
if formset.is_valid():
formset.save()
return render_to_response('conf.html',
{'state':'Your ad has been successfull created.'},
context_instance = RequestContext(request),)
else:
formset = newAdFormSet()
return render_to_response('ad_form.html',
{'form':formset},
context_instance=RequestContext(request),)
It works but it always returns one prefilled form for each existing tuple plus, at the end, a blank form.
Now, i can't get how to say where it must return a blank form (to perform a new insert), and where it must instead return a single prefilled form (possibly passing the Ad's id) to perform an update.
modelformset_factory and formset helps to solve a lot, take your code for example
def newAd(request):
newAdFormSet = modelformset_factory(Ad, extra=1)
if request.method == 'POST':
formset = newAdFormSet(request.POST, request.FILES)
if formset.is_valid():
formset.save()
return render_to_response('conf.html',
{'state':'Your ad has been successfull created.'},
context_instance = RequestContext(request),)
else:
formset = newAdFormSet(queryset=Ad.objects.all())
return render_to_response('ad_form.html',
{'form':formset},
context_instance=RequestContext(request),)
Note the extra=1 in modelformset_factory line, it ensures there is only one extra blank form. And queryset=Ad.objects.all() in the second newAdFormSet inside else statement, it pre-fills forms for Ad objects from DB and correctly set PK in, mostly hidden, field for backend code to recognize submitted objects.
update
if you want to set Ad().codU to point to an User() instance, request.user for example, you could simply just set it by
instances = formset.save(commit=False)
for obj in instances:
obj.codU = request.user
obj.save()
I'm still not 100% clear what your question is, but it sounds like you don't want a formset at all. If you're only interested in adding or updating a single record at a time, you want a simple ModelForm, not a formset. So:
class AdForm(forms.ModelForm):
class Meta:
model = Ad
def add_update_ad(request, pk=None):
if pk is not None:
instance = Ad.objects.get(pk=pk)
else:
instance = Ad()
if request.POST:
form = AdForm(request.POST, instance=instance)
if form.is_valid():
new_instance = form.save()
return HttpResponseRedirect('my_confirmation_view')
else:
form = AdForm(instance=instance)
return render(request, 'ad_form.html', {'form': form})