Flask SQLAlchemy Query - python

I have created a Flask project using Miguel Grinbergs' excellent tutorials. I am adapting the example code to make my own site.
I have two tables in my db. Drivers and Teams. I have created a One-to-Many relationship in models.py and I want to output a list of drivers and the team they belong to. I have included routes.py and the html file that will display the results.
The query in routes.py works fine if I specify one driver within the query, but when I try Drivers.query.all(), it does not return any data on the web page.
NOTE = I have ran the Drivers.query.all() within a Python Shell and I get the correct response, it is only when I try to implement the solution on the web page that I experience the problem.
output from Python Shell
>>> details = Driver.query.all()
>>> details
[<Driver Lewis Hamilton>, <Driver Kimi Raikkonen>, <Driver Max Verstappen>]
>>> for d in details:
... print(d.driverName, d.driverTeam)
...
Lewis Hamilton Mercedes
Kimi Raikkonen Ferrari
Max Verstappen Red Bull
>>>
models.py
class Team(db.Model):
id = db.Column(db.Integer, primary_key=True)
teamName = db.Column(db.String(64))
teamDriver = db.relationship('Driver', backref='driverTeam', lazy='dynamic')
def __repr__(self):
return '{}'.format(self.teamName)
class Driver(db.Model):
id = db.Column(db.Integer, primary_key=True)
driverName = db.Column(db.String(64))
team_id = db.Column(db.Integer, db.ForeignKey('team.id'))
def __repr__(self):
return '<Driver {}>'.format(self.driverName)
routes.py
#app.route('/driverDetails', methods=['GET', 'POST'])
def driverDetails():
## Output works fine with one driver specified in query
# details = Driver.query.filter_by(driverName='Kimi Raikkonen').first()
## No data is output when using query below
details = Driver.query.all()
return render_template('driverDetails.html', title='Driver Details', details=details)
driverDetails.html
{% extends "base.html" %}
{% block content %}
<h1>Driver Details</h1>
<!-- Output works correctly for one driver as specified in query on routes.py
<div><p>{{ details.driverName }} is in: <b>{{ details.driverTeam }}</b></p></div>
-->
<!-- However, when trying to iterate over whole list of drivers, output shows
the text "drives for:". But there is no data being populated from the db
-->
{% for d in details %}
<div><p>{{ details.driverName }} drives for: {{ details.driverTeam }}</p></div>
{% endfor %}
{% endblock %}
I would appreciate any advice on where I am going wrong.

your code is basically correct, you just need to actually use the object you are binding to d:
{% for d in details %}
<div><p>{{ d.driverName }} drives for: {{ d.driverTeam }}</p></div>
{% endfor %}

Related

How to minimise number of routes in my Flask webapp

I am attempting to minimize the number of routes and database tables in my simple clothing ecommerce site. My site has four product categories: Coat, Shirt, Trouser, Shoe.
Each category currently has its own table in the database:
class Coat(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.Text, nullable=False)
description = db.Column(db.Text, nullable=True)
price = db.Column(db.Float)
image1 = db.Column(db.String(100), nullable=True, default='default.jpg')
image2 = db.Column(db.String(100), nullable=True)
I would like to combine all products into a single database with 'Category' being a column inside this Product database.
Each category also currently has its own route and template:
#app.route('/coats')
def coats():
products = Coat.query.all()
return render_template('coats.html', products=products, title='Coats')
{% extends "base.html" %}
{% block content %}
{% for product in products %}
<div class="product">
<a href="{{ url_for('product_coat', id=product.id) }}">
<img src="static/images/coats/{{ product.image1 }}" class="image"></a>
<p class="name">{{ product.name }}</p>
<p class="price">{{ product.price }}</p>
</div>
{% endfor %}
{% endblock %}
When a products link is followed, a product page is displayed, again using individual routes for each category:
#app.route('/product_coat/<id>', methods=['GET', 'POST'])
def product_coat(id):
product = Coat.query.get(id)
return render_template('product_coat.html', title='Product',
product=product)
Currently my navbar in "base.html" looks like this:
<nav>
<h3>Coats</h3>
<h3>Shirts</h3>
<h3>Trousers</h3>
<h3>Shoes</h3>
</nav>
I realise this is a rather large post so to summarise,
If I were to combine all four database tables into one product table with a new 'category' column, how would I:
Create navbar links for these categories?
Create a route that handles displaying only products from the selected category?
Thanks for reading.
You can pass query parameters to a new route,
#app.route('/product/', methods=['GET'])
def product_list(id):
item = request.args.get('item')
product = products.all.filter(type=item)
return render_template(f"{item}.html", title=item,product=product)
then when you load the page, you can call url/?item=coat and it will filter the data.
*that product filter line might be incorrect.
What you can do is attempt to follow a more RESTful design pattern.
The main idea is to add a parameter to your routes to represent the category. This would be similar to what you've done for the product ID. Importantly, you would have only one HTML template for the products page (the page that lists all the products of a particular category) and one HTML template for the product page (the page for listing the details of one product of a particular category).
So your two existing routes could become something like this:
(Note your logic should ensure an invalid product category and/or ID is correctly handled)
#app.route('/products/<product_category>/<product_id>', methods=['GET', 'POST'])
def product(product_category, product_id):
product = <your database logic utilizing the product_category and product_id + error handling>
return render_template('product.html', product=product, title=product.name)
#app.route('/products/<product_category>', methods=['GET'])
def products(product_category):
products = <your database logic utilizing the product_category + error handling>
return render_template('products.html', products=products, title=product_category.title())
Your navbar HTML could end up looking like this:
(Here we specify the 2nd route and supply just the category)
<nav>
<h3>Coats</h3>
<h3>Shirts</h3>
<h3>Trousers</h3>
<h3>Shoes</h3>
</nav>
Finally, your product display HTML could end up like this:
(Here we specify the 1st route and supply the category and product ID -- since we're linking to a specific product in this case)
<div class="product">
<a href="{{ url_for('product', product_category=product.category, product_id=product.id) }}">
<img src="{{ url_for('static', filename='images/coats/' + product.image1) }} class="image"></a>
<p class="name">{{ product.name }}</p>
<p class="price">{{ product.price }}</p>
</div>
Also, I suggest investigating the MVC design pattern which is highly prevalent in Flask applications.

How does "template.Library()" and "get_related_name" work in django?

I'm working on a basic social media django project with the help of an udemy course. The following are the models i created:
group : models.py
register = template.Library()
class Group(models.Model):
name = models.CharField(max_length=255,unique=True)
slug = models.SlugField(allow_unicode=True,unique=True)
description = models.TextField(blank=True,default='')
description_html = models.TextField(editable=False,default='',blank=True)
members = models.ManyToManyField(User,through="GroupMember")
class GroupMember(models.Model):
group = models.ForeignKey(Group,related_name='memberships',on_delete=models.CASCADE)
user = models.ForeignKey(User,related_name='user_groups',on_delete=models.CASCADE)
post : models.py
class Post(models.Model):
user = models.ForeignKey(User,related_name='posts',on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now=True)
message = models.TextField()
message_html = models.TextField(editable=False)
group = models.ForeignKey(Group,related_name='posts',null=True,blank=True)
And the part that does not make any sense to me is the following:
post_list.html
{% for member_group in get_user_groups %}
<a href="{% url 'groups:single' slug=member_group.group.slug %}">{{ member_group.group.name
}}</a></li>
{% endfor %}
{% for other_group in get_other_groups %}
{{ other_group.name }}</li>
{% endfor %}
What does "get_user_groups","get_other_groups" and "register = template.Library()" mean here and how are they related? Also what are they trying to achieve here? I'm clueless guys, help me out.
That's an example of custom template tags. There is probably a custom_tags.py file where you created the custom template tags within a folder called template_tags that shows the work being done to create the content of those tags.
get_user_groups isn't pulling from views.py or directly referencing your models.py. Instead, it's referencing queries stored in custom_tags.py
Find a detailed breakdown here:
https://medium.com/#hiteshgarg14/creating-custom-template-tags-in-django-application-7bd1dcfeb144
This can be useful if you want to display content from a query on a variety of different views without having to redundantly insert that query into multiple functions within views.py. In this case, it looks like it will be used to insert group membership information within a variety of views by using custom tags.

How to dynamically generate URL with flask and my database?

I try to dynamically generate my url_for like this and it is not working...:
search.html
<a href="{{ url_for('{{ country }}') }}"
This is where I query my data for my link from my database.
routes.py
from app import app, db
from app.models import
#app.route('/search')
def search():
country = Country.query.get(3)
return render_template('search.html', country=country.country)
#this is one of the final page where the link in the search results lead
#I will have /portugal, /france, etc...
#app.route('/germany')
def germany():
return render_template('germany.html')
and this is a clip of the information in my database:
models.py
from app import db
class Country(db.Model):
id = db.Column(db.Integer, primary_key=True)
country = db.Column(db.String(120), index=True, unique=True)
html_page = db.Column(db.String(255), index=True, unique=True)
def __repr__(self):
return '<Country {}>'.format(self.country)
Do I even need to store the URL since it is the same as the country name aka #germany
If you already have a base template file setup for your countries then typically you want to generate that template with the specific information.
Then typically you want to have your function definition setup something like this
# renders the given country page from the base template
# EX: if given "Germany" the resulting url will be:
# mywebsite.com/country/Germany
#app.route("country/<str:country>", methods=["GET"])
def render_country(country):
# your specific code here
return render_template("countrybase.html", country=country)
While your html link would look something like this:
Link to Germany page
If you don't already have a base html template setup I would recommend researching Jinja templates and how Flask uses them. The example project from the official documentation has a great guide on how to get started.
But as a quick example your countrybase.html might look like this:
{% extends base.html %}
{% block header %}
<h1>{% block title %}{{ country["name"] }}{% endblock %}</h1>
{% endblock %}
{% block content %}
<div class="my-custom-css-class">
{{ country["other_country_data"] }}
<!-- etc.. -->
</div>
{% endblock %}

Getting spesific data from three models in django

I am starting working with django and i want get specific data from three related models.
my models are
class Institution(models.Model):
name = models.CharField(max_length=100, unique=True)
...
class Certification(models.Model):
name = models.CharField(max_length=100)
...
class Course(models.Model):
name = models.CharField(max_length=100)
institution = models.ForeignKey(Institution)
certification = models.ForeignKey(Certification)
in my html page i want display the courses offered by a particular institution ordered by certification. like this
name of a particular institution I
certification 1
list courses that offer certification 1
certification 2
list courses that offer certification 2
...
my current template is
{{institution.name}}
{% for certification in preselected_certifications %}
<h1> {{ certification.name }} </h1>
<ul>
{% for course in courses %}
<li>{{ course.name }}</li>
{% endfor %}
</ul>
{% endfor %}
my view
def detail(request, slug):
context = RequestContext(request)
context_dict = {'slug_requested': slug}
try:
institution = Institution.objects.get(slug=slug)
courses = Course.objects.filter(etablissement=etablissement)
context_dict['courses'] = courses
context_dict['institution'] = institution
except Institution.DoesNotExist:
pass
return render_to_response('institutition/details.html', context_dict, context)
my question is how define "preselected_certifications" so it contains only certifications offered by all courses in the selected institution, but without repeating any certification
Question:
how define "preselected_certifications" so it contains only certifications offered by all courses in the selected institution, but without repeating any certification
I don't know exactly how you want to represent this information (meaning, which attributes you want available), but think you want something like the following:
def detail(request, slug):
...
institution = Institution.objects.get(slug=slug)
# `select_related` not strictly necessary
courses = institution.course_set.all().select_related('certification')
context_dict['courses'] = courses
context_dict['institution'] = institution
Now, each course object will have access to its certification relation and you could iterate through them to display the unique ones.
However, if you want to ensure from the outset these certifications are unique, one way to do that is with another query:
institution = Institution.objects.get(slug=slug)
courses = institution.course_set.select_related('certification')
certification_ids = courses.values_list('certification_id', flat=True).distinct()
preselect_certifications = Certification.objects.filter(id__in=certification_ids)
That last query will get you the unique certifications for a particular institution.
It seems like Certification should potentially have a relationship to Institution, though, no?
yeah thanks a lot, now i use in my template the following code
{% for certification in preselect_certifications %}
{{certification.name}}
{% for course in courses %}
<ul>
{% if certification = course.certification %}
<li>{{ course.name }}</li>
{% endif %}
</ul>
{% endfor %}
{% endfor %}
it works perfectly, but is there another way to avoid using
{% if certification = course.certification %}
?
thanks again

Python Django models execute a join query

I am developing an application with Django framework and I'm new to it
I need to create a query that simply joins 2 tables( type and subType ) and then later on use the result in the views the models file looks like this:
class Type(models.Model):
name = models.CharField(max_length=60)
description = models.CharField(max_length=200)
class SubType(models.Model):
name = models.CharField(max_length=60)
description = models.CharField(max_length = 200)
Type = models.ForeignKey(Type)
And in home.html file I have : (I dropped out the bootstrap code to make it more readable )
<ul>
<li ><a href="/home" >Home Page</a></li>
{% for type in all_types %}
<li >
{{ type.name }}
<ul >
--The Inner Loop--
</ul>
</li>
{% endfor %}
</ul>
I need to create an list of types and then inside each type I need to create another list which contains the subTypes of each type
I have no idea how do I have to create the query inside the views.py
def index(request):
list_all_types = #Here I have to create a join query via django models
t = loader.get_template('home.html');
c = Context({
'all_types' : list_all_types,
});
return HttpResponse(t.render(c));
So please let me know how do I have to make the query and replace the correct code with the comment part in views.py and what changes do I have to add to make to the home.html to make it enabled show all the subTypes instead of --inner loop in home.html
Thanks in advance
You don't need to do anything in the view other than get the types:
types = Type.objects.all()
In the template, you just iterate over type.subtype_set.all:
<ul>
{% for subtype in type.subtype_set.all %}
<li>{{ subtype.name }}</li>
{% endfor %}
</ul>
Note that this is well covered by the tutorial. (As is the use of the render shortcut rather than loading and rendering the template separately.)
(Actually, what I said at first was not quite true: for the sake of efficiency, you can add prefetch_related() to the Type query.)

Categories