Django - submit multiple forms in a view - python

I have two forms in my views, when I hit on save it's not working properly, when I want to display on my templates what I saved not showing as expected.
Here's what I have:
views.py
def index(request):
queryset = Personinfo.objects.all()
queryset2 = Person.objects.all()
qs = chain(queryset,queryset2)
form = personform(request.POST or None)
form2 = personinfoform(request.POST or None)
context = {
"queryset": queryset,
"queryset2": queryset2,
"qs": qs,
"form2":form2,
"form":form,
}
form2_valid = form2.is_valid()
form_valid = form.is_valid()
if form2_valid and form_valid:
a = form2.save()
b= form.save(commit=False)
b.ForeignkeytoA = a
b.save()
return render(request, "index.html", context)
index.html
<form method="POST" action="">{% csrf_token %}
{{form2.as_p}}
{{form.as_p}}
<input type="submit" value="Save!" />
</form>
<table >
<tr>
<th>Name</th>
<th>Address</th>
<th>Number</th>
<th>Hobbies</th>
</tr>
{% for item in qs %}
<tr>
<td>{{ item.name }}</td> #form2
<td>{{ item.address }}</td> #form1
<td>{{ item.phone_number }}</td> #form1
<td>{{ item.address }}</td> #form1
</tr>
{% endfor %}
</table>
models.py
class Personinfo(models.Model):
name = models.CharField(max_length=128)
def __str__(self):
return self.name
class Person(models.Model):
person = models.ForeignKey(Personinfo)
address = models.TextField()
phone_number = models.CharField(max_length=128)
hobbies =models.CharField(max_length=128)
def __str__(self):
return self.person
my output:
As you can see my table isn't showing my items as expected.
Is there a possible way to show every item in the same row?

Two errors are present. If I understand right, you're expecting the data from a Person instance and the data from its accompanying PersonInfo instance to print on the same line. However, you're trying to achieve this by using chain, which is not joining the querysets based on their relationship, but rather concatenating them blindly.
So if Person.objects.all() returns a queryset which contains the following data
id person address phone_number hobbies
1 1 a a a
2 2 5 5 5
and PersonInfo.objects.all() returns a queryset which contains
id Name
1 aaa
2 aa
chain combines them as
id person name address phone_number hobbies
1 aaa
2 aa
1 1 a a a
2 2 5 5 5
Instead, you should utilize the relationship between the models. If you pass only the Person queryset as context to your template, you could write
{% for p in persons %}
<tr>
<td>{{ p.person.name }}</td>
<td>{{ p.address }}</td>
<td>{{ p.phone_number }}</td>
<td>{{ p.hobbies }}</td>
</tr>
{% endfor %}
--
Additionally you are setting the Personinfo related instance incorrectly when you save your forms. By using b.ForeignkeytoA you are creating a new variable as a member of the object b called ForeignkeytoA, which has nothing to do with the Personinfo relationship. To set the related Personinfo, you should reference the name of the foreign key field, person. To correct this, that segment should be
# ...
b = form.save(commit = False)
b.person = a
b.save()
# ...

Related

Django: Show data from current user

I'm having trouble displaying data from current user. It shows all the shifts that was given to other users also. I don't have any idea how to do this. Below is my code.
models.py
class User(models.Model):
user_name = models.CharField(max_length=32, unique=True)
pass_word = models.CharField(max_length=150)
is_active = models.BooleanField(default=True)
class Rostering(models.Model):
name = models.CharField(max_length=64)
begin_time = models.TimeField(default="")
end_time = models.TimeField(default="")
is_active = models.BooleanField(default=True)
class RosteringUser(models.Model):
rostering_user = models.ForeignKey(Rostering, on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE)
views.py
def my_shift(request):
if request.method == 'GET':
queryset = RosteringUser.objects.all()
if queryset:
for obj in queryset:
id = Rostering.objects.get(rosteringuser=obj.id)
obj.id = id
return render(request, 'my_shift.html', {'queryset': queryset})
my_shift.html
{% for obj in queryset %}
<tr>
<td>{{ obj.user.user_name }}</td>
<td>{{ obj.id.name }}-{{ obj.id.begin_time }}</td>
<td>{{ obj.id.name }}-{{ obj.id.end_time }}</td>
</tr>
{% endfor %}
Thank you in advance!
Simply you can try like this:
if queryset:
for obj in queryset:
id = Rostering.objects.get(rosteringuser=obj.id)
obj.id = id
querysets = obj
return render(request, 'my_shift.html', {'querysets': querysets})
And in templates:
{% for object in querysets %}
<tr>
<td>{{ object.user.user_name }}</td>
<td>{{ object.id.name }}-{{ object.id.begin_time }}</td>
<td>{{ object.id.name }}-{{ object.id.end_time }}</td>
</tr>
{% endfor %}
def my_shift(request):
if request.method == 'GET':
rost_id = RosteringUser.objects.filter(user_id=request.user.id).values("rostering_user_id").first()
if rost_id :
data = Rostering.objects.get(id=rost_id['rostering_user_id'])
return render(request, 'my_shift.html', {'queryset': data })
in template you can directly display logged in username {{ request.user.first_name }}

How to add Django Object Models to A Separate List

I am creating an app for a school schedule using Django. Admin users can currently add classes to a list. Student users can view that list but I want to create a button/link that will add that class object to a separate list that will act as their applied classes.
Models.py
class Class(models.Model):
def __str__(self):
return self.name
name = models.CharField(max_length=50)
crn = models.CharField(max_length=5, validators=[RegexValidator(r'^\d{1,10}$')])
grade_mode = models.CharField(max_length=50)
subject = models.CharField(max_length=3)
course_num = models.CharField(max_length=4, validators=[RegexValidator(r'^\d{1,10}$')])
section_num = models.CharField(max_length=3, validators=[RegexValidator(r'^\d{1,10}$')])
credit_hours = models.FloatField(validators=[MinValueValidator(0.0), MaxValueValidator(5.000)])
teacher = models.CharField(max_length=50)
Views.py
#login_required
#dec.student_required
def index(request):
class_list = Class.objects.all().order_by("-name")
# Allow for Posting of New Classes to Schedule.
if request.method == "POST":
form = ClassesForm(request.POST)
if form.is_valid():
form.save()
form = ClassesForm()
messages.success(request, "Class Added to Registry!")
else:
form = ClassesForm()
context_dict = {'classes': class_list,
'form': form}
return render(request, 'index.html', context=context_dict)
Index.HTML Add Button
<table>
<tbody>
{% if classes %}
{% for class in classes %}
<tr>
<td>Class Name: </td>
<td>Subject: </td>
<td>CRN: </td>
<td>Course Number: </td>
<td>Section Number: </td>
<td>Credit Hours: </td>
<td>Teacher: </td>
<td>Grade Mode: </td>
<td>Add Class</td>
</tr>
<tr>
<td>{{ class.name }}</td>
<td>{{ class.subject }}</td>
<td>{{ class.crn }}</td>
<td>{{ class.course_num }}</td>
<td>{{ class.section_num }}</td>
<td>{{ class.credit_hours }}</td>
<td>{{ class.teacher }}</td>
<td>{{ class.grade_mode }}</td>
<td>
<form method="GET">
{% csrf_token %}
<button class="addToSchedule" type="submit" value="add" name="Add Class">
Add Class
</button>
</form>
</td>
</tr>
{% endfor %}
</tbody>
{% else %}
<strong>There are no classes added.</strong>
{% endif %}
</table>
Image on Website.
So far I can print out the models on their own separate list as shown above but I don't know where to go in regards to the button or if a button is even the correct way of doing it. I want to click on a button and that model will be added and saved to the Added Classes section above.

Django.db.models.field.CharField

I have a Django project that I'm trying to cobble together for a very basic survey that needs to be entered for demographic information. I've dummied up some data through the admin site in order to get my ListView working for the time being.
Unfortunately, I'm getting a strange response. I built the models.py to be a drop-down of a full spelled out and then to keep it small, I've made the actual storage in the db 1-3 characters. When I get my list view, one that uses 1 character to store for gender presents as (<django.db.models.fields.CharField>,), I would like for it to present as as the larger name of "Male", "Female", "Non-binary".
However, for my race and ethnicity fields which are 2 & 3 characters, those are returning as the actual storage for the DB (i.e, 'AA', 'NHP'). I'm more comfortable with SQL, so I'm not opposed to adding a table for a key as there would only be 11 entries for now, but it is possible that more things could be added down the line.
models.py:
from django.db import models
from django.contrib import admin
from django.contrib.auth.models import User
# Create your models here.
class StuData(models.Model):
id_num = models.IntegerField(primary_key=True)
entry_date = models.DateTimeField('Date of Entry')
MALE = 'm'
FEMALE = 'f'
OTHER = 'x'
GENUNK = 'u'
GENDER_SELECTIONS = [
(MALE,'Male'),
(FEMALE,'Female'),
(OTHER,'Non-Binary'),
(GENUNK,'Unknown'),
]
gender = models.CharField(max_length=1, choices=GENDER_SELECTIONS),
## Build the selections for the race field
AFR_RACE = 'AA'
ASI_RACE = 'AS'
WHI_RACE = 'WH'
UNK_RACE = 'UN'
RACE_SELECTIONS = [
(AFR_RACE, 'African-American'),
(ASI_RACE, 'Asian/Pacific Islander'),
(WHI_RACE, 'White'),
(UNK_RACE, 'Unknown Race'),
]
race = models.CharField(max_length=2, choices=RACE_SELECTIONS)
## Build the selections for the ethnicity field
HSP = 'HIS'
NHP = 'NHP'
UNK = 'UNE'
ETHNICITY_SELECTIONS = [
(HSP, 'Hispanic Origin'),
(NHP, 'Not of Hispanic Origin'),
(UNK, 'Unknown Ethnicity'),
]
ethnicity = models.CharField(max_length=10, choices=ETHNICITY_SELECTIONS)
stu_count = models.IntegerField(default=1)
user = models.ForeignKey(User, on_delete=models.CASCADE)
class Meta:
ordering = ["cad_num"]
def __str__(self):
return self.name
views.py:
from django.shortcuts import render
from django.http import HttpResponse
from mvstop.models import StuData
from django.views.generic.list import ListView
from django.views.generic.edit import UpdateView, CreateView
# Create your views here.
class StuDataList(ListView):
model = StuData
template = "myapp/studata_list.html"
fields = ""
paginate_by = 25
def Meta():
ordering = ['id_num']
def __str__(self):
return self.name
studata_list.html:
<!DOCTYPE html>
{% extends "./base.html" %}
{% block content %}
<h3>Most recent entries</h3>
<table id="studata">
<tr>
<th>ID Number</th>
<th>Entry Date</th>
<th>Gender</th>
<th>Race</th>
<th>Ethnicity</th>
<th>Count</th>
</tr>
{% for stu in studata_list %}
<tr>
<tr>
<td>{{ stu.id_num }}</td>
<td>{{ stu.entry_date }}</td>
<td>{{ stu.gender }}</td>
<td>{{ stu.race }}</td>
<td>{{ stu.ethnicity }}</td>
<td>{{ stu.occupants }}</td>
</tr>
{% endfor %}
</tr>
</table>
{% endblock %}
Django have build in method for that:
get_FIELD_display()
so in your template:
{% for stu in studata_list %}
<tr>
<tr>
<td>{{ stu.id_num }}</td>
<td>{{ stu.entry_date }}</td>
<td>{{ stu.get_gender_display }}</td>
<td>{{ stu.get_race_dispaly }}</td>
<td>{{ stu.get_ethnicity_display }}</td>
<td>{{ stu.occupants }}</td>
</tr>
{% endfor %}

Display part of django model in html table

How to display only some columns of Django model in a HTML template?
And also: how do I perform a function on one of the records? (amount)?
Right now I'm displaying a whole table of model like that:
my models.py
class Tabela(models.Model):
block_id = models.CharField(max_length=64)
timestamp = models.DateTimeField()
type = models.CharField(max_length=32)
link = models.CharField(max_length=64)
link_as_account = models.CharField(max_length=100)
account = models.CharField(max_length=100)
amount = models.CharField(max_length=64)
def __str__(self):
return self.block_id
My views.py
def search_results(request):
model = Tabela
query_addresse = request.GET.get('addressee', None)
query_hash = request.GET.get('hash', None)
if not query_hash and not query_addresse and request.method == 'GET':
return render(request, 'nanosite/index.html', {})
if query_hash and request.method == 'GET':
if query_addresse:
result = Tabela.objects.filter(account=query_addresse, block_id=query_hash)
else:
result = Tabela.objects.filter(block_id=query_hash)
field_names = [f.name for f in model._meta.get_fields()]
data = [[getattr(ins, name) for name in field_names]
for ins in result]
elif query_addresse and request.method == 'GET':
result = Tabela.objects.filter(account=query_addresse)
field_names = [f.name for f in model._meta.get_fields()]
data = [[getattr(ins, name) for name in field_names]
for ins in result]
return render(request, 'nanosite/index.html', {'field_names': field_names, 'data': data})
My index.html
<div id="bottomhalf" class="table-responsive">
<table class="table table-sm table-dark table-hover">
<thead class="thead-light">
{% for head in field_names %}
<th scope="col">{{ head }}</th>
{% endfor %}
</thead>
<tbody>
{% for row in data %}
<tr scope="row">
{% for cell in row %}
<td>{{ cell }}</td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
</div>
What I'd like to do is display only block_id, timestamp, account and amount in html. I've tried different approaches like using only the result part of views without field_names and data, but of course it didn't work.
My other question is, how can I modify the field amount and perform an operation on it to be displayed in template like amound divided by certain digit with a $ sign before it (for example if amount=1488 to be divided by 124 and displayed as '$12')?
Pass the queryset qs selecting the objects to display to the template and iterate over it to generate your table:
{% for obj in qs %}
<tr>
<td> {{obj.block_id}} </td>
<!-- etc ... -->
</tr>
{% endfor %}
Now, if you also want to pass a variable specifying the names of the fields of the object to tabulate, and in what order, you find out that the Django template engine is by design (!) incapable of doing that. You can either do what you are doing, and generate a list-of-rows in Python which you pass to the Template, or you need a Django custom template tag such as
#register.filter
def attr( obj, name):
return getattr( obj, name, '')
and then you can run an inner loop in your template
<tr>
{% for name in selected_field_names %}
<td> {{obj|attr:name}} </td>
{% endfor %}
</tr>
The answer to the second question, is to define a property on your model to return the field suitably transmogrified:
class Tabela(models.Model):
...
#property
def funny_amount(self):
val = self.amount/12.0
return f'$ {val:.2f}'
and refer to {{obj.funny_amount}} in your template

Looping in django template with variable parameter

I want to get all the details of class Material where user=user_id
Here is the models.py:
class Material(models.Model):
subject = models.CharField(max_length=10)
topic = models.CharField(max_length=50)
user = models.IntegerField()
and my views.py:
def add_material(request):
c = {}
c.update(csrf(request))
if 'user_session' in request.session:
user_id = request.session['user_session']
material_array = Material.objects.filter(user=user_id).values()
materials_len = len(material_array)
c['m_len'] = materials_len
for i in range(0, materials_len):
c['material_id_'+str(i)] = material_array[i]
return render_to_response('add_material.html',c)
else:
return HttpResponseRedirect('/user')
and my add_material.html is:
{% for i in range(m_len) %}
<tr>
{% for j in material_id_+str(i) %}
{{j.subject}}
{{j.topic}}
{% endfor %}
</tr>
{%endfor%}
So I am getting error in template, how to insert variable in for loop?
This how I would do it.
views.py
def add_material(request):
c = {}
c.update(csrf(request))
if 'user_session' in request.session:
user_id = request.session['user_session']
material_array = Material.objects.filter(user=user_id)
c.update({'materials': material_array})
return render_to_response('add_material.html', c)
else:
return HttpResponseRedirect('/user')
template
{% for material in materials %}
<tr>
<td>{{ material.subject }}</td>
<td>{{ material.topic }}</td>
<td>{{ material.user.username }}</td>
</tr>
{% endfor %}
You can include any user field you like.

Categories