django show object from parent table - python

If i have a one-to-many relationship. How do i show a field from the related parent table in my child template.
models.py
class Parent(models.Model):
name = models.CharField()
class Child(models.Model):
parent = models.ForeignKey(parent)
child_name = models.CharField()
views.py
def childs(request):
return render_to_response('dashboard/childs.html', {'childs': Child.objects.all(), 'parents': Parent.objects.all() })
childs.html
<table class="table table-striped">
<thead>
<tr>
<th>id</th>
<th>child name</th>
<th>parent name</th>
</tr>
</thead>
<tbody>
{% for child in childs %}
<tr>
<td>{{ child.id }}</td>
<td>{{ child.child_name }}</td>
<td>{{ parent.name }}</td>

To achieve this, you dont need to send the parent objects in the context.
You can just do {{ child.parent.name }} in the loop, where child.parent refers to the foreign key parent associated with the child model instance.
So you would just do
{{ child.parent.name }}
Also, you can consider optimizing the database calls using select_related or prefetch_related

Related

How to display querysets in Django?

I write a functiın and the final, function creates several model objects (same model different values). I listed these objects but I want to list just one time with the same dashboard_id value.
I found something about that but I have an issue with displaying in the table.
It is working but does not display the values. How can I solve it?
views.py
def reports_list(request):
report_list = Reports.objects.values_list('dashboard_id', flat=True).distinct()
context = {
'report_list': report_list,
}
return render(request, "report_list.html", context)
report_list.html
<table id="table_id" class="display">
<thead>
<tr>
<th>Kullanıcı</th>
<th>Yüklenme Tarihi</th>
<th>Görüntüle</th>
</tr>
</thead>
<tbody>
{% for report in report_list %}
<tr>
<td>{{ report.user.first_name }} {{ report.user.last_name }}</td>
<td>{{ report.created_at }}</td>
<td>view</td>
</tr>
{% endfor %}
</tbody>
</table>
to be clear:
I do not think what you have in your function corresponds with what I see as your intention in the template. Therefore you can try this instead:
def reports_list(request, dashboard_id):
report_list = Reports.objects.filter(dashboard_id=dashboard_id).all()
context = {
'report_list': report_list,
}
return render(request, "report_list.html", context=context)
If you think your original function is correct, then you have forgotten to add the context (context=context).

How to modify the view to only show the data to one assigned user?

Problem:
I would like to assign a bank statement for each user. Each user will log in using their username and password, and access their document. At the moment, one user can see the statement of all users.
Option 1:
I`ve added a manytomany relationship for the user to the model. When logged in on the Admin interface, I can assign the Bank Statement to the user.
Question:
What is the right way to define the views.py or the html file to only show the bank statement to the user logged-in.
models.py
class BankStatement(models.Model):
user = models.ManyToManyField(settings.AUTH_USER_MODEL,related_name='bs')
name = models.CharField(max_length=20)
date_created = models.DateTimeField(auto_now_add=True)
last_updated = models.DateTimeField(auto_now=True)
views.py
#login_required(login_url="/login/")
def bankstatement_detail(request, bankstatement_id):
bankstatement = BankStatement.objects.get(pk=bankstatement_id)
context = {
'bankstatement': bankstatement,
}
return render(request, 'administration/bankstatement_detail.html', context)
#login_required(login_url="/login/")
def index_bankstatement(request):
user = request.user
bankstatement = BankStatement.objects..filter(user=request.user)
context = {
'bankstatement': bankstatement,
}
return render(request, 'administration/bankstatement_detail.html', context)
bankstatement_detail.html
<div class="card-block table-border-style">
<div class="table-responsive">
<table class="table table-hover">
<thead>
<tr>
<th>#</th>
<th>Name</th>
<th>Date Created</th>
<th>Last Updated</th>
</tr>
</thead>
<tbody>
{% for bankstatement in bankstatements %}
<tr>
<td>{{ bankstatement.id }}</td>
<td>{{ bankstatement.name }}</td>
<td>{{ bankstatement.date_created }}</td>
<td>{{ bankstatement.last_updated }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
Many Thanks
I do not know if you are still working on this one, but
I do not agree with linking of the BankStatement to the User as ManyToMany. In my opinion, one user can have many statements, but one statement has only one user. So it is a one to many relationship defined by Foreign Key.
Let's fix the view:
#login_required(login_url="/login/")
def bankstatement_detail(request, bankstatement_id):
# this line forces to show the statement of the logged in user
user = request.user
bankstatement = BankStatement.objects.get(pk=bankstatement_id, user=user)
context = {'bankstatement': bankstatement,}
return render(request, 'administration/bankstatement_detail.html', context)

Flask+SQLAlchemy: How to show the latest entry in 1-to-many database

Sorry I couldn't come up with a clear title, I'm not exactly sure what it is called that I want to accomplish. Also english is not my first language so please bear with me.
I've set up a database with two tables "Sensors" and "SensorValues".
There should be a one-to-many relationship so that one sensor can have many readings but the readings can belong to only one sensor.
I'm using Flask and flask-sqlalchemy.
Database models:
class Sensor(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(64), unique=True, nullable=False,)
gpiopin = db.Column(db.INT, unique=False, nullable=False,)
stype = db.Column(db.String(20), unique=False, nullable=False,)
values = db.relationship('SensorValues', backref='author', lazy=True) #not a column in table, just backreference
def __repr__(self):
return f"Sensor('{self.name}', '{self.gpiopin}', '{self.stype}')"
class SensorValues(db.Model):
id = db.Column(db.Integer, primary_key=True)
reading = db.Column(db.String(64), unique=False)
timestamp = db.Column(db.DateTime, unique=False, nullable=False, default=datetime.utcnow)
sensor_id = db.Column(db.Integer, db.ForeignKey('sensor.id'), nullable=False)
def __repr__(self):
return f"Value('{self.reading}', '{self.timestamp}')"
Here's the flask route for home.html:
#app.route("/", methods=['POST', 'GET'])
def home():
sensors = Sensor.query.all()
posts = SensorValues.query.all()
return render_template('home.html', posts=posts, sensors=sensors, db=db)
How I generate the table in home.html
<tbody>
{% for sensor in sensors %}
<tr>
<td>{{ sensor.name }}</td>
<td>{{ sensor.gpiopin }}</td>
<td>{{ sensor.stype }}</td>
<td>{{ sensor.values.reading }}</td> <- Where I want the latest reading of the specific sensor in the SensorValues to appear
</tr>
{% endfor %}
</tbody>
Now, I have another table which lists all the readings and the names of the sensors they belong to.
It's basically a history and this way it works because I'm looping the SensorValues table directly.
{% for post in posts %}
<tr>
<td>{{ post.author.name }}</td>
<td>{{ post.author.stype }}</td>
<td>{{ post.reading }}</td>
<td>{{ post.timestamp }}</td>
</tr>
{% endfor %}
I tried to change the first loop to this:
{% for sensor in sensors %}
<tr>
<td>{{ sensor.name }}</td>
<td>{{ sensor.gpiopin }}</td>
<td>{{ sensor.stype }}</td>
{{ lastvalue = SensorValues.filter_by(sensor_id=sensor.id).last()}}
<td>{{ lastvalue.reading }}</td>
</tr>
{% endfor %}
Where I tried to make a filter query to the SensorValues table with the current sensor.id (the id of the Sensor the for loop is currently in) and logically I think that could work but the syntax is not correct. I got the Jinja error:
expected token 'end of print statement', got '='
Can I even do the query in the home.html or do I have to do it in the routes before the page is rendered?
The query in the view function needs to be updated to include information about the latest reading for the sensors before passing it in the template context.
Start out with writing the query in SQL and then convert it to its SQLAlchemy variant.
The SQL query to find the last sensor reading values is the following:
https://www.db-fiddle.com/f/5fXZyPiPYawc22ffMi2tYk/0
SELECT DISTINCT
s.*,
FIRST_VALUE(sv.reading) OVER (
PARTITION BY sv.sensor_id ORDER BY sv.timestamp DESC
) AS last_reading
FROM sensors AS s
JOIN sensor_values AS sv ON s.id = sv.sensor_id
Now, let's build the SQLAlchemy variant
import sqlalchemy as sa
sensors = Sensor.query.join(
SensorValues).with_entities(
Sensor,
sa.func.first_value(
SensorValues.reading).over(
partition_by=SensorValues.sensor_id,
order_by=SensorValues.timestamp.desc
).label('latest_reading'))
The Result rows returned from the above query are instances of KeyTuple and the latest_reading label should be available as a direct attribute of the sensor in the Jinja2 template.
{% for sensor in sensors %}
<tr>
<td>{{ sensor.Sensor.name }}</td>
<td>{{ sensor.Sensor.gpiopin }}</td>
<td>{{ sensor.Sensor.stype }}</td>
<td>{{ sensor.latest_reading }}</td>
</tr>
{% endfor %}
I'm not sure if I should edit this to the original post rather than posting it as an answer?
But anyways I got it working with:
{% for sensor in sensors %}
<tr>
<td>{{ sensor.name }}</td>
<td>{{ sensor.gpiopin }}</td>
<td>{{ sensor.stype }}</td>
{% set lastvalue = SensorValues.query.filter_by(sensor_id=sensor.id).order_by(SensorValues.timestamp.desc()).first() %}
<td>{{ lastvalue.reading }}</td>
</tr>
{% endfor %}
And of course I had to add SensorValues to the route:
#app.route("/", methods=['POST', 'GET'])
def home():
sensors = Sensor.query.all()
posts = SensorValues.query.all()
#lastvalue = SensorValues.query.filter_by(sensor_id=sensor.id).last()
return render_template('home.html', posts=posts, sensors=sensors, db=db, SensorValues=SensorValues
If there is a better way by all means show it, but for now it works.

Not able to access data using 'categories.products .all ' in template view. Django Models with foreign key

I have models that have relation using a foreign key.
class Cat1(models.Model):
name = models.CharField(max_length=30)
description = models.CharField(max_length = 100)
def __str__(self):
return self.name
class Product(models.Model):
name = models.CharField(max_length=50)
productId = models.AutoField(max_length=50,primary_key=True)
productType = models.CharField(max_length=50)
matType = models.CharField(max_length=100,default='Use comma , to seperate multiple materials')
seller = models.ForeignKey(User, related_name='sellers',on_delete=models.CASCADE,default='NA')
cat_1 = models.ForeignKey(Cat1,related_name='catlevel1',on_delete=models.CASCADE,default='NA')
Then i have my views of the page.
where i need to display all the product from the category i have clicked on.
My View is :
def cat_products(request,pk):
categories = get_object_or_404(Cat1, pk=pk) #here the categories get the category i clicked on homepage.
products = Product.objects.all()
return render(request, 'products.html', {'categories':categories,'products':products})
Then products.html is:
<!--Full Code not shown for easy understanding-->
{% for prod in categories.products.all %}
{{categories.name}}
<tr>
<td>{{ prod.name }}</td>
<td>{{ prod.matType }}</td>
<td>0</td>
<td>0</td>
<td>0</td>
</tr>
{% endfor %}
So basically categories is the the name that can be used to access current category.Products is the list of all products.
I have tried this code above which yield no result.
Now the code below shows all the products objects.
<!--Full Code not shown for easy understanding-->
{% for prod in products %}
{{categories.name}}
<tr>
<td>{{ prod.name }}</td>
<td>{{ prod.matType }}</td>
<td>0</td>
<td>0</td>
<td>0</td>
</tr>
{% endfor %}
But this way it shows all products irrespective of categories.
So this party shirt in Men category is shown in Women too.
i have tried only printing all the products
{% for prod in products %}
The line in code above {{categories.name}} shows the name of the class.
This works fine with no problem.
The backend is able to access the database no problem but i am not able to figure out the template section
Here is the product and the categories stored as Men in product object.
I should be able to see Men category products in men and Women products in women category.
You need to use catlevel1 instead of products:
{% for prod in categories.catlevel1.all %}
{{categories.name}}
<tr>
<td>{{ prod.name }}</td>
<td>{{ prod.matType }}</td>
<td>0</td>
<td>0</td>
<td>0</td>
</tr>
{% endfor %}
Because you have defined related_name as catlevel1 when you created the ForeignKey relation between Product and Cat1.

django how to get field from child relationship into parent template

If I have a one-to-many relationship model. How do i display items from the related child table in my parent template.
models.py
class Parent(models.Model):
name = models.CharField()
class Child(models.Model):
parent = models.ForeignKey(Parent)
child_name = models.CharField()
parent.html
{% for parent in parents %}
<tr>
<td>{{ parent.id }}</td>
<td>{{ parent.name }}</td>
<td>{{ child.child_name }}</td>
</tr>
{% endfor %}
Read the Django docs on following relationships backwards: https://docs.djangoproject.com/en/dev/topics/db/queries/#backwards-related-objects
But basically, it's parent.child_set.all
You can change the name child_set by adding a related_name='children' to the ForeignKey: parent = ForeignKey(Parent, related_name='children')
Then you can use: parent.children.all

Categories

Resources