I'm trying to display some data on a webpage using a foreach loop and django.
I do not seem to understand how to use a lookup table that I have created in my Database.
These are the columns from the DB:
budget_audit_table:
-BudgetID
-BudgetTypeID <- Foreign Key
-ObjectAuditID
-CustomerID
-DateOfTransaction
-BudgetObject
-Amount
budget_type:
-BudgetTypeID
-BudgetType
As you can probably assume in the model.py, the BudgetTypeID is a foreign key.
In the budget_type table I currently have 2 rows:
- Expense: ID 1
- Income: ID 2
Now the problem I'm having is I have searched for a few days now trying to understand Django's API more and I'm struggling to understand how do I for each row that is displayed from the budget_audit_table, how do I instead of displaying the BudgetTypeID (eg 1), it displays the BudgetType (eg Expense)?
Here is my view & template
view.py
from django.contrib.auth.decorators import login_required
from django.http import HttpResponse
from django.template import RequestContext, loader
from models import BudgetAuditTable
from models import BudgetType
#login_required
def index(request):
budgetauditlist = BudgetAuditTable.objects.order_by('-budgetid')
template = loader.get_template('budget/budget.html')
context = RequestContext(request, {
'budgetauditlist': budgetauditlist,
})
return HttpResponse(template.render(context))
Template
{% for budgetauditobject in budgetauditlist %}
<tr>
<td>{{ budgetauditobject.budgetid }}</td>
<td>{{ budgetauditobject.budgettypeid }}</td>
<td>{{ budgetauditobject.objectauditid }}{{ budgetauditobject.customerid }}</td>
<td>{{ budgetauditobject.amount }}</td>
</tr>
{% endfor %}
Now perhaps you're wondering why I don't use the "Choices" django offers. Because I'm a very database driven person who believes the DB should handle as much as possible and leaving the python as the ask and receive part.
EDIT
models.py
class BudgetAuditTable(models.Model):
budgetid = models.IntegerField(db_column='BudgetID', primary_key=True)
budgettypeid = models.ForeignKey('BudgetType', db_column='BudgetTypeID', blank=True, null=True)
objectauditid = models.IntegerField(db_column='ObjectAuditID', blank=True, null=True)
customerid = models.IntegerField(db_column='CustomerID', blank=True, null=True)
dateoftransaction = models.DateField(db_column='DateOfTransaction', blank=True, null=True)
budgetobject = models.CharField(db_column='BudgetObject', max_length=255, blank=True)
amount = models.DecimalField(db_column='Amount', max_digits=10, decimal_places=2, blank=True, null=True)
class Meta:
managed = False
db_table = 'budget_audit_table'
class BudgetType(models.Model):
budgettypeid = models.IntegerField(db_column='BudgetTypeID', primary_key=True)
budgettype = models.CharField(db_column='BudgetType', max_length=25, blank=True)
class Meta:
managed = False
db_table = 'budget_type'
You should really have shown your models. If budgettypeid is the Django ForeignKey field, then budgetauditobject.budgettypeid would give you the actual BudgetType object, and then you can access its fields with the normal dot notation.
Instead of:
<td>{{ budgetauditobject.budgettypeid }}</td>
have you tried:
<td>{{ budgetauditobject.budgettypeid.budgettype }}</td>
?
Related
I have two models interrelated items and broken :
class Items(models.Model):
id = models.AutoField(primary_key=True)
item_name = models.CharField(max_length=50, blank=False)
item_price = models.IntegerField(blank=True)
item_quantity_received = models.IntegerField(blank=False)
item_quantity_available = models.IntegerField(blank=True)
item_purchased_date = models.DateField(auto_now_add=True, blank=False)
item_units = models.CharField(max_length=50, blank=False)
def __str__(self):
return self.item_name
class Broken(models.Model):
item = models.ForeignKey(Items, default=1, on_delete=models.CASCADE)
item_quantity_broken = models.IntegerField(blank=True)
item_broken_date = models.DateField(auto_now_add=True, blank=False)
item_is_broken = models.BooleanField(default=True)
date_repaired = models.DateField(auto_now=True, blank=True)
def __str__(self):
return self.item.item_name
I wrote this view function to retrieve data to a table into a template:
def broken_items(request):
br = Broken.objects.select_related('item').all()
print(br.values_list())
context = {
'title': 'broken',
'items': br,
}
return render(request, 'store/broken.html', context)
this is the executing query:
SELECT "store_broken"."id",
"store_broken"."item_id",
"store_broken"."item_quantity_broken",
"store_broken"."item_broken_date",
"store_broken"."item_is_broken",
"store_broken"."date_repaired",
"store_items"."id",
"store_items"."item_name",
"store_items"."item_price",
"store_items"."item_quantity_received",
"store_items"."item_quantity_available",
"store_items"."item_purchased_date",
"store_items"."item_units"
FROM "store_broken"
INNER JOIN "store_items"
ON ("store_broken"."item_id" = "store_items"."id")
looks like it gives me all the fields I want. In debugger it shows data from both tables,
so I wrote for loop in template,
{% for item in items %}
<tr>
<td>{{item.id}}</td>
<td>{{item.item_id}}</td>
<td>{{item.item_quantity_broken}}</td>
<td>{{item.item_broken_date}}</td>
<td>{{item.item_is_broken}}</td>
<td>{{item.date_repaired}}</td>
<td>{{item.item_name }}</td>
<td>{{item.item_item_quantity_received}}</td>
<td>{{item.item_quantity_available}}</td>
<td>{{item.item_purchased_date}}</td>
<td>{{item.items_item_units}}</td>
</tr>
{% endfor %}
The thing is this loop only gives me data from broken table only. I can't see data from Items table.
can someone help me to find the reason why other details are not showing?
Your items query is of Broken objects. So in order to access the Items values you need to change your table. For better understanding change your view like this:
brokens = Broken.objects.select_related('item').all()
context = {
'title': 'broken',
'brokens ': brokens,
}
and then your table:
{% for broken in brokens %}
<tr>
<td>{{broken.id}}</td>
<td>{{broken.item.pk}}</td> # This is the item id
<td>{{broken.item_quantity_broken}}</td>
<td>{{broken.item_broken_date}}</td>
<td>{{broken.item_is_broken}}</td>
<td>{{broken.date_repaired}}</td>
<td>{{broken.item.item_name}}</td>
<td>{{broken.item.item_quantity_received }}</td>
<td>{{broken.item.item_quantity_available}}</td>
<td>{{broken.item.item_purchased_date}}</td>
<td>{{broken.item.items_item_units}}</td>
</tr>
{% endfor %}
you loop over a List of Broken objects
to access the related item objects
item.item.item_name
Brand new to Django/Python and have almost completed my first big project. I've built a small ecommerce store with a staff backend to update/delete and create products. I would like to display the address entered in by the User at checkout with in the Staff template.
My code so far looks like this:
models.py:
class Address(models.Model):
ADDRESS_CHOICES = (
('B', 'Billing'),
('S', 'Shipping'),
)
user = models.ForeignKey(
User, blank=True, null=True, on_delete=models.CASCADE)
street_address = models.CharField(max_length=150)
town_or_city = models.CharField(max_length=100)
county = models.CharField(max_length=100, default=True)
postcode = models.CharField(max_length=20)
address_type = models.CharField(max_length=1, choices=ADDRESS_CHOICES)
default = models.BooleanField(default=False)
def __str__(self):
return f"{self.street_address}, {self.town_or_city}, {self.county}, {self.postcode}"
class Meta:
verbose_name_plural = 'Addresses'
I would like to captcha the data from the 'street_address', 'town_or_city', 'county' and 'postcode' fields and have that info displayed with in my staff template.
The idea I had was to import my Address model and grab all objects using Address.objects.all() and have this display with in the template using something like {{ user_address}}
views.py / StaffView:
class StaffView(LoginRequiredMixin, generic.ListView):
template_name = 'staff/staff.html'
queryset = Order.objects.filter(ordered=True).order_by('-ordered_date')
paginate_by = 10
context_object_name = 'orders'
def get_address(self):
user_address = Address.objects.all()
return user_address
staff.html:
<tr>
<td><a class="order-ref-number-link" href="{% url 'cart:order-detail' order.pk %}">#{{ order.reference_number }}</a>
</td>
<td>{{ order.ordered_date }}</td>
<td>{{ order.user.email }}</td>
<td>£{{ order.get_total }}</td>
<td>{% if order.ordered %}Paid{% else %}Not Paid!{% endif %}</td>
<td>{{ user_address }}</td> <--HERE IS WHERE I'M TRYING TO DISPLAY ADDRESSES
</tr>
{% empty %}
So far this method i've tried alone returns nothing, im still finding my way around Django so would really appreciate if someone could help me find a simple solution for this. If any additional info is needed I'll be happy to provide. Thanks in advance.
I built a table with a MySQL backend in Django that lets me store generator charts that would be useful in worldbuilding and character building, like you might find on reddit.com/r/d100. My table can account for 110 potential roll entries, but I anticipate that for some tables (such as d20 tables), a large number of the entries will not be used. Is there a way to display all of the used entries but skip the null entries? If not, I am prepared to hardcore each of the rolls to display on the webpage.
I was anticipating having to plug in something like
<tr>
<th>Roll</th>
<th>Result</th>
</tr>
{% if table.roll_1 is not None %}
<tr>
<td>1</td>
<td>{{ table.roll_1 }}
</tr>
{% endif %}
</table>
This is my generator table model:
class D100Generator(models.Model):
d_100_id = models.AutoField(primary_key=True)
field_of_interest = models.ForeignKey(FieldOfInterest, on_delete=models.CASCADE)
subreddit_post_id = models.ForeignKey(Subreddit, on_delete=models.CASCADE, blank=True, null=True)
module_id = models.ForeignKey(Module, on_delete=models.CASCADE, blank=True, null=True)
generic_website_id = models.ForeignKey(GenericWebsite, on_delete=models.CASCADE, blank=True, null=True)
table_name = models.CharField('table name', max_length=100)
system = models.CharField(max_length=150)
genre = models.CharField(max_length=250)
chart_type = models.CharField('Die used', max_length=15)
chart_instructions = models.TextField('Chart instructions & explanation')
roll_1 = models.TextField('1', blank=True, null=True)
roll_2 = models.TextField('2', blank=True, null=True)
...
roll_109 = models.TextField('109', blank=True, null=True)
roll_110 = models.TextField('110', blank=True, null=True)
table_slug = models.SlugField(unique=True)
def save(self, *args, **kwargs):
if not self.id:
#Newly created object, so set slug
self.table_slug = slugify(self.table_name)
super(D100Generator, self).save(*args, **kwargs)
def __str__(self):
return self.table_name
This is the view that calls the page:
from django.shortcuts import get_object_or_404, render
from .models import D100Generator
def index(request):
latest_table_list = D100Generator.objects.order_by('-d_100_id')[:5]
context = {
'latest_table_list': latest_table_list
}
return render(request, 'generators/index.html', context)
def table(request, table_slug):
table = get_object_or_404(D100Generator, pk=table_slug)
return render(request, 'generators/table.html', {'table': table})
I think you can do as following to filter table data to exclude null or empty roll containing entries
from django.db.models import Q
def index(request):
latest_table_list = D100Generator.objects.filter(
roll_1__isnull=False
).exclude(
roll_1__exact=''
).order_by('-d_100_id')[:5]
context = {
'latest_table_list': latest_table_list
}
return render(request, 'generators/index.html', context)
This will exclude table rows in which roll_1 is None or empty. Then you might not need check None in template.
There are ways to filter out the null entries for a column if multiple rows in a table are being used, but in this case I need to hardcode each successive column name, and there's no way to skip that.
I am trying to display a doctors first name from another table that is linked by foreign key. I can get the doctor_id to display but cannot get his name to display.
I looked at this solution
reading from joined query in flask-sqlalchemy
but it is slightly different as I am querying from the other side and cannot use the backref value as a reference. I have removed the irrelevant code.
class Appointment(db.Model):
id = db.Column(db.Integer, primary_key=True)
patient_id = db.Column(db.Integer, db.ForeignKey('patient.id'),
nullable=False)
doctor_id = db.Column(db.Integer, db.ForeignKey('doctor.id'),
nullable=False)
class Doctor(db.Model):
id = db.Column(db.Integer, primary_key=True)
first_name = db.Column(db.String(30), unique=False, nullable=False)
appointments = db.relationship('Appointment', backref =
db.backref('doctor',lazy=True))
and the query
all_appmts = db.session.query(Appointment)
.filter_by(patient_id=id)
.join(Doctor)
result =appointments_schema.dump(all_appmts)
return render_template('patient.html', all_appointments=result.data)
and this is what i tried
{% for a in all_appointments %}
<td>{{ a.doctor_id.first_name }}</td>
{% endfor %}
The doctor name displayed should be based on the the doctor id for that appointment.
Here is the marshmallow part.
class AppointmentSchema(ma.Schema):
class Meta:
# Fields to expose
fields = ('id','start_datetime', 'end_datetime', 'title',
'patient_id', 'doctor_id')
appointments_schema = AppointmentSchema(many=True)
You are trying to access doctor_id.first_name. But the name of the relationship is doctor. If you are converting the result of the query to a list of dicts, then you should serialize the appointment.doctor relationship also, so that the dict looks like
{
id: 12,
doctor: {
id: 34
}
}
Then you can access it like this
<td>{{ a.doctor.first_name }}</td>
But if you are just planning to use it in jinja template, then what is the need to serialize the objects? Instead you can just pass the result of the query.all() to the template. Jinja can directly access the python objects and show the data. So instead of result =appointments_schema.dump(all_appmts), try doing this
all_appmts = db.session.query(Appointment)
.filter_by(patient_id=id)
.join(Doctor)
return render_template('patient.html', all_appointments=all_aptmts.all())
And then keep the jinja template as the same
{% for a in all_appointments %}
<td>{{ a.doctor.first_name }}</td>
{% endfor %}
It will work
I have started creating a personal expenses django app to learn python...
So far, I have written some models for categories, transactions, scheduled transactions (for example re-occuring bills), type of accounts etc. And I am stuck :)
What I am trying to do is to display all transactions in an html page. Those that re-occur, should be listed also, as my app displays all transactions you have until 365 days from now. I can't manage to display all instances of repeating transactions.
model
class Transaction(models.Model):
category = models.ForeignKey(Category)
kind = models.ForeignKey(Kind)
account = models.ForeignKey(Account)
userA = models.ForeignKey(User, related_name='userA')
userA_contribution = models.DecimalField(max_digits=9, decimal_places=2)
userB = models.ForeignKey(User, related_name='userB', blank=True, null=True)
userB_contribution = models.DecimalField(max_digits=9, decimal_places=2, blank=True, null=True)
transaction_text = models.CharField(max_length=200)
transaction_date = models.DateTimeField('transaction date')
transaction_price = models.DecimalField(max_digits=9, decimal_places=2)
def __str__(self):
return self.transaction_text
# calculate days since transaction has been made
def days_ago(self):
days_ago = timezone.now() - self.transaction_date
return days_ago.days
class ScheduledTransaction(Transaction):
REPEATING_CHOICES = (
('0', 'Once'),
('1', 'Daily'),
('2', 'Every other day',),
('7', 'Every week'),
('14', 'Every two weeks'),
('30', 'Monthly'),
('90', 'Quarterly'),
('180', 'Six months'),
('365', 'Annually'),
)
repeated = models.CharField(max_length=30, choices=REPEATING_CHOICES)
def days_to_payment(self):
days_to_payment = self.transaction_date - timezone.now()
return days_to_payment.days
def cost_per_month(self):
cost_per_month = self.userA_contribution / int(self.repeated) * 30
return cost_per_month
controller
def index(request):
latest_transactions_list = Transaction.objects.all().order_by('-transaction_date')[:20]
scheduled_transactions = ScheduledTransaction.objects.all()
# create a list to save scheduleTransaction.object instances
s_instances = []
for sche in scheduled_transactions:
s_instances.append(sche)
next_payment_days = int(sche.repeated) # next payment day is the repeated value, e.g. = 30 days
base_trans_date = sche.transaction_date
while next_payment_days < 365:
sche.transaction_date = base_trans_date + datetime.timedelta(days=next_payment_days)
s_instances.append(sche)
next_payment_days = next_payment_days + int(sche.repeated)
accounts_dash = Account.objects.all().order_by('-name')
date_today = datetime.datetime.now()
context = { 'latest_transactions_list': latest_transactions_list,
'scheduled_transactions' : s_instances,
'accounts_dash' : accounts_dash,
'date_today' : date_today,
}
return render(request, 'transactions/index.html', context)
view
{% for strans in scheduled_transactions %}
{% if strans.repeated|add:0 <= 365 %}
<tr>
<td class="">{{ strans.transaction_date }}</td>
<td class="text-center"><span class="label label-default">{{ strans.kind }}</span></td>
<td class="text-center"><span class="label label-info">{{ strans.category }}</span></td>
<td class="text-center">{{ strans.transaction_text }}</td>
<td class="text-right">{{ strans.userA_contribution|floatformat:2 }}€</td>
<td class="text-center">{{ strans.repeated }}</td>
<td class="text-center">{{ strans.days_to_payment }}</td>
<td class="text-right">{{ strans.cost_per_month|floatformat:2 }}€</td>
</tr>
{% endif %}
{% endfor %}
The transaction is printed in the terminal webserver shell, but not displayed even once on the html.
Any help would be appreciated !
EDIT: Updated the controller. Now the iteration works, but I always get the latest date and the total of days_to_payment in all instances. Any ideas ?
Firstly, it's a view, not a controller.
Secondly, what you're doing with s_instances doesn't seem to make sense. First you declare it as global for no reason - it's local to the view function, so there's no need to make it global. Then you iterate through the transactions and for each one you redefine s_instances to be the value of the latest one. You should be appending to a list, not redefining it each time. And then you append two methods: days_to_payment and cost_per_month - without ever actually calling them. And finally, having converted your instances to a list of simple values, you attempt to call them from the template by their original property names, which they no longer have.
However, I must question why you think you need to do that at all. All the things you put into that list are simple model attributes or methods. Why not simply pass the transaction objects straight to the template? Then your template would actually work.
Just remove this useless and insane for loop from your view and you should be better:
def index(request):
latest_transactions_list = Transaction.objects.order_by('-transaction_date')[:20]
scheduled_transactions = ScheduledTransaction.objects.all()
accounts_dash = Account.objects.order_by('-name')
date_today = datetime.now()
context = {'latest_transactions_list': latest_transactions_list,
'scheduled_transactions': scheduled_transactions,
'accounts_dash': accounts_dash,
'date_today': date_today,
}
return render(request, 'transactions/index.html', context)