Django: Querying Foreign Keys - django-models

I have two models Book and Review,
models.py
class Book(models.Model):
title = models.CharField()
class Review(models.Model):
rating = models.IntegerField()
content = models.TextField()
book = models.OneToOneField(Book, on_delete=models.CASCADE)
I'm using ListView to display the book title with it's rating and review. However, I'm having issues with querying the rating and content attributes of the Review model that match the book.
views.py
class BookList(ListView):
model = Book
context_object_name = 'books'
template_name = 'book_list.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
for book in context['books']:
try:
context['review'] = Review.objects.get(book=book)
except Review.DoesNotExist:
context['review'] = None
return context
book_list.html
<table style=width:100%>
<tr>
<th>Book</th>
<th>Rating</th>
<th>Review</th>
</tr>
{% for book in books %}
<tr>
<th>{{ book.title }}</th>
<th>{{ review.rating }}</th>
<th>{{ review.content }}</th>
</tr>
{% endfor %}
</table>
The book titles render fine, but there is nothing for the rating and an empty queryset for the review.
I know the issue has to do something with the get_context_data method and how it retrieves the review object. I tried using the _set.all() method, but that didn't work either.
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
for book in context['books']:
context['review'] = book.review_set.all()
return context
How can I query the review that is connected to the specific book and access all of that review's attributes?

I read in the comments that you recently changed the relationship from ForeignKey (OneToMany) to OneToOne relationship. So you have to make sure that you did your migrations properly and there are no Items left in your database with the "old" relationship. So much for the disclaimer.
You should be able to do this quite simple.
class BookList(ListView):
model = Book
context_object_name = 'books'
template_name = 'book_list.html'
# delete get_context_data entirely - the method of parent ListView does just fine
<table style=width:100%>
<tr>
<th>Book</th>
<th>Rating</th>
<th>Review</th>
</tr>
{% for book in books %}
<tr>
<th>{{ book.title }}</th>
<th>{{ book.review.rating }}</th>
<th>{{ book.review.content }}</th>
</tr>
{% endfor %}
</table>
Read more about reverse lookup of OneToOne relationships here.
Let me know how it goes!

Related

How i keep the rendered tamplete with large amount of data to orthers route in Flask

I'm having difficulties trying to create a modal with a new link on my webpage. I want the model to appear on top of the searched data.
I can't use session because the data is non json serializable.
#app.route('/search/<string:subject_in_box>', methods=['POST', 'GET'])
def show_data_subject(subject_in_box):
if request.method == 'POST':
subject_in_box = request.form['subject'].upper()
search_by_subject = Collegiate.query.filter_by(subject=subject_in_box).order_by(Collegiate.available.desc()).all()
return render_template(r'show_data.html', data=search_by_subject, subject_search=subject_in_box)
elif request.method == 'GET':
search_by_subject = Collegiate.query.filter_by(subject=subject_in_box).order_by(Collegiate.available.desc()).all()
return render_template(r'show_data.html', data=search_by_subject, subject_search=subject_in_box)
#app.route('/search/<string:subject_in_box>/<int:row_id>')
def modal_popup(row_id, subject_in_box):
return render_template('modal.html')
show_data.html
<table id="example" class="table table-striped table-bordered table-hover" cellspacing="0" width="100%">
<thead>
<tr>
<!--<th class="th-sm">xxxxxx</th>-->
<!--<th class="th-sm">xxxxx</th>-->
<th class="th-sm">xxxx</th>
<th class="th-sm">xxx xxxOfer</th>
<th class="th-sm">xxxx xxxvagas</th>
<th class="th-sm">xxxx</th>
</tr>
</thead>
<tbody>
{% for item in data %}
<tr class="clickable"
onclick="window.location='{{url_for('modal_popup', row_id=item.row_id, subject_in_box=subject_search)}}'">
<!--<td>{{ item.collegiate }}</td>-->
<!--<td>{{ item.subject }}</td>-->
<td>{{ item.classes }}</td>
<td>{{ item.offered }}</td>
<td>{{ item.demand }}</td>
<td>{{ item.available }}</td>
</tr>
{% endfor %}
</tbody>
</table>
If I understand correctly, your problem is that clicking an item renders the modal.html and the original page isn't visible behind that modal page?
It's kind of hard to determine what you need to do without seeing the html files. Or without any error message. However here's 3 things you could try depending on your situation:
One
If your modal.html file contains the same html content as show_data.html plus some kind of modal window then you'll need to add the same data in the return statement of your modal_popup route
So something along these lines:
#app.route('/search/<string:subject_in_box>/<int:row_id>')
def modal_popup(row_id, subject_in_box):
search_by_subject = Collegiate.query.filter_by(subject=subject_in_box).order_by(Collegiate.available.desc()).all()
return render_template('modal.html', data=search_by_subject, subject_search=subject_in_box)
Two
If not and your modal.html file contains just the html for the modal part you could take a look at this stackoverflow question Open a new page as modal window
Three
Restructure your show_data.htmlto include the modal and its data. For example using bootstrap's modal https://getbootstrap.com/docs/5.3/components/modal/
Then you won't need your modal.html file anymore.

How to iterate JsArray in Scala view page (value map is not a member of play.api.libs.json.JsArray)

I'm using JsArray on Scala view page, And I tried to iterate it using for loop, but throwing error on the Scala view page, Here I attached my code, how can I resolve it.
#(jsonArrValue: play.api.libs.json.JsArray)
<html>
<body>
<table>
<thead>
<tr>
<th>Details</th>
</tr>
</thead>
<tbody>
<tr>
#for(x <- jsonArrValue){
<td>#x</td>
}
</tr>
</tbody>
</table>
</body>
</html>
Error:
value map is not a member of play.api.libs.json.JsArray
jsonArrValue contains:
[{"empName":"xxx","age":"23","empNo":"123"},{"empName":"yyy","age":"24","empNo":"1234"}]
While the name JsArray may suggest it's a collection sort of thing, it's actually not. The definition:
case class JsArray(value: Seq[JsValue] = List()) extends JsValue with Product with Serializable
clearly shows it. That why for comprehension does not work.
And I think the best way to iterate it is call its value() method to convert to a Seq[JsValue], then use for comprehension.

how to open row at the same index in ng-repeat , nested ng-repeat

I am new to angularjs and facing an issue with ng-repeat. A list of invoices repeated with ng-repeat, each invoice has List of Payments. I'm trying to get the payments on click of one of the repeated row and then another and so on.
when I open the first one it opens with exact data, when we open other row payments it opens with new payments by replacing the old one. Both payments of the First row payments and second row payments are same.
List of payments has to open with ng-repeat of that particular index. it has to happen for every invoice which is not happening with following
here is my html
<tbody data-ng-repeat="invoice in relatedInvoices>
<tr>
<td class="td-bottom-border">
{{invoice.PayableCurrencyCode}} {{invoice.PayablePaidAmount | number: 2}}<br />
<small>
<a data-ng-click="isOpenPayablePayments[$index] = !isOpenPayablePayments[$index]; togglePayablePayments(invoice.PayableInvoiceId)">Paid</a>
</small>
</td>
</tr>
<tr data-ng-show="isOpenPayablePayments[$index]">
<td>
<table>
<thead>
<tr>
<th>Transaction Id</th>
</tr>
</thead>
<tbody>
<tr data-ng-repeat="payment in payablePayments">
<td>{{payment.TransactionId}}</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
Here is my javascript
var getPayments = function (invoiceId) {
paymentService.getPayments(invoiceId).then(function (paymentsResponse) {
return paymentsResponse.data;
});
};
$scope.togglePayablePayments = function(invoiceId) {
$scope.payablePayments = getPayments(invoiceId);
};
Every time on toggle click payments getting replaced with new payments. My problem is how to maintain the payments of particular index of every click and show at respective index. please help me out
Working Demo
<tbody>
<tr data-ng-repeat="city in name.cities">
<td>{{city.city}}</td>
</tr>
</tbody>
Actually you have to specifies main object name with the cities. name.cities
That's all !!!
Hope this will help you.
Feel free to ask any doubt on this.

What is the best practice to show the data fetched by Laravel 4.2 from Database using 'ng-repeat' of AJS

I'm fetching data from the database using Laravel 4.2, it returns an array of JSON objects, then I pass that data to a view. But I'm unable to show it using Angular JS' ng-repeat directive. How can I do taht?
Note for Blade I'm using [[ ]], and for Angular JS I'm using {{ }}.
Controller of Laravel is given as Following:
class CountryController extends BaseController {
public function index()
{
return View::make('admin.country.show')
->with('countries', Country::all());// returns array of JASON objects
}
}
View of Laravel is given as follows:
<table class="table table-bordered">
<tr>
<th class="col-lg-2">Sr.No</th><th>Country</th>
</tr>
<!-- foreach($countries as $country) -->
<tr ng-repeat="country in $countries">
<td class="col-lg-2">{{country.id}}</td><td>{{country.country}}</td>
</tr>
<tr><td>{{query}}</td></tr>
<!--endforeach -->
</table>
{{countries}}
[[ $countries]]
{{countries}} of ajs not works but [[$countries]] works! How can I access $countries in AJS?
I don'n know that whether it's a good practice or not but I've found the solution which is given as follows:
<table class="table table-bordered">
<tr>
<th class="col-lg-2">Sr.No</th><th>Country</th>
</tr>
<tr ng-repeat="country in $countries">
<td class="col-lg-2">{{country.id}}</td><td>{{country.country}}</td>
</tr>
</table>
Instead of using
<tr ng-repeat="country in $countries">
I've used the
<?php echo("<tr ng-repeat='country in ". $countries. "'>"); ?>
It, after rendering becomes
<tr class="ng-scope" ng-repeat="country in [{"id":1,"countries":"Pakistan"},{"id":2,"countries":"Saudi Arbia"}]">
You can clearly see that an array of JSON object is returned by php, which now can easly be printed.
Note again: I don't know that it's best practice or not! I still would like to know the best practice.

Is it possible to limit the number of displayed items in a loop in AngularJs

I have a list of categories and many questions which belongs to different categories.
{
"id": 5,
"description": "Does your site have Facebook?",
"question_category_id": 3
}
{
"id": 1,
"name": "Network",
"description": "Network"
}
<table ng-repeat="c in categories">
<thead>
<tr>
<th>{{ c.id }}. {{ c.description }}</th>
</tr>
</thead>
<tbody ng-repeat="q in questions | filter: { question_category_id: c.id } : true">
<tr>
<td>{{q.description}}</td>
</tr>
</tbody>
</table>
This is the code which displays all questions under a category.
But I want to loop through each of the categories and only display 1 question under one category by using AngularJs.
Is it possible ?
If yes, how?
Thank you.
You have a couple of possibilities here, check de documentation of ng-repeat (https://docs.angularjs.org/api/ng/directive/ngRepeat). For example if you only want to show the first question, you can check $first in ng-show on the tr-tag.
But be aware that this is only not showing the other questions of that category in the html, you still have retrieved all questions of that category from the server which is a waste of resources since you are only showing the first question.
If you really want to iterate over questions, then you could use $index.
<tbody
ng-repeat="q in questions | filter: { question_category_id: c.id } : true"
ng-show="$index == 0">
If not, but still you do not want to touch the JavaScript part, then'd I'd go around this using
<td>
{{ (questions | filter: { question_category_id: c.id } : true)[0].description }}
</td>

Resources