I am using Flask SQLAlchemy for my project and I realized my customers page is very slow because I am trying to get destination for each customers. My structure looks like this.
class Users(db.Model):
__tablename__ = "users"
id = db.Column(db.Integer, primary_key=True)
first_name = db.Column(db.String(200), nullable=False)
last_name = db.Column(db.String(30), nullable=False)
created_date = db.Column(db.DateTime,nullable=False,default=datetime.datetime.now())
email = db.Column(db.Unicode(50), nullable=False)
account = db.Column(db.Unicode(10), nullable=False)
number = db.Column(db.String(30), nullable=False)
user_type = db.Column(db.String(10), nullable=False, default='ADMIN')
created_by = db.Column(db.Unicode(10), nullable=False, default='SYSTEM')
destinations = db.relationship('Destinations', backref="customer",lazy="dynamic")
class Destinations(db.Model):
__tablename__ = 'destinations'
import datetime
id = db.Column(db.Integer, primary_key = True)
did = db.Column(db.Text, nullable=False)
gateway = db.Column(db.Text, nullable=False)
channel = db.Column(db.Text, nullable=False)
own = db.Column(db.Text, nullable=False)
number = db.Column(db.Unicode(50), nullable=True)
user_id = db.Column(db.Integer, db.ForeignKey('users.id'))
created_by = db.Column(db.Integer,nullable=False)
created_date = db.Column(db.DateTime, default=datetime.datetime.now())
expire_date = db.Column(db.DateTime, nullable=False)
record = db.Column(db.Integer, nullable=False)
auth_did = db.Column(db.Integer, nullable=False)
auth_gw = db.Column(db.Integer, nullable=False)
In my all customers page, I list all customers which the request if fast but when I try to load all destinations for each customer, the request takes a lot of time for it to load.
{% for customer in customers %}
<tr>
<td>{{customer.first_name}}</td>
<td>{{customer.number}}</td>
<td>
{% for destination in customer.destinations %}
{{destination.number}}<br />
{% endfor %}
</td>
<td>
{% for destination in customer.destinations %}
{{destination.did}}<br />
{% endfor %}
</td>
<td>
{% for destination in customer.destinations %}
{{destination.own}}<br />
{% endfor %}
</td>
<td>
{% for destination in customer.destinations %}
{{destination.created_date|humandatetime|safe}}<br />
{% endfor %}
</td>
<td>
{% for destination in customer.destinations %}
{% if destination.expire_date %}{{destination.expire_date|humandatetime|safe}}{% endif %}<br />
{% endfor %}
</td>
<td>
{% for destination in customer.destinations %}
{{destination.gateway or ''}}<br />
{% endfor %}
</td>
<td>
{% for destination in customer.destinations %}
{{destination.channel or ''}}<br />
{% endfor %}
</td>
<td>
{% for destination in customer.destinations %}
del<br />
{% endfor %}
</td>
<td><input type="hidden" value="{{customer.first_name}} {{customer.last_name}}"></td>
<td><a id="{{customer.id}}" class="user-delete-icon">delete</a></td>
</tr>
{% endfor %}
Also the function that get all my customers is this
customers = db.session.query(Users).filter_by(user_type='CUST').all()
I think the problem is the relationship type lazy but I can't get to fix it
Related
I tried to look up the order class and get the last 5 orders with their customer and items. But got the following exception:
*Exception Type: ValueError
Exception Value:
Negative indexing is not supported.*
Here are the models:
class Customer(models.Model):
first_name = models.CharField(max_length=255)
last_name = models.CharField(max_length=255)
class Order(models.Model):
placed_at = models.DateTimeField(auto_now_add=True)
customer = models.ForeignKey(Customer, on_delete=models.PROTECT)
class OrderItem(models.Model):
order = models.ForeignKey(Order, on_delete=models.PROTECT)
product = models.ForeignKey(Product, on_delete=models.PROTECT)
And here is the view class:
def last_5_orders(request):
orders = Order.objects.select_related('customer').prefetch_related('orderitem_set__product').order_by('placed_at')[-5:]
return render(request, 'last_5_orders.html', {'orders': orders})
And finally in last_5_orders.html file I have:
{% for order in orders %}
<h1>
{{ order.id }} : {{ order.custumer.first_name }} {{ order.custumer.last_name }} PURCHASED {{order.orderitem_set.product}}
</h1>
{% endfor %}
Any ideas about resolving this issue?
I'm calculating the min and max values so I can display the spread of RRPs for a car model. Here I just have the min value, which is being calculated correctly but it will not display to the index file using the guidance I got from various examples/sites.
Greatly appreciatte any help.
Models.py
class MotorMakes(models.Model):
MotorMakeName = models.CharField(max_length=50, unique=True, default=False)
def __str__(self):
return self.MotorMakeName or ''
def __unicode__(self):
return u'%s' % (self.MotorMakeName) or ''
class MotorModelsV2(models.Model):
MotorMakeName = models.CharField(max_length=50, default=False,)
MotorModelName = models.CharField(max_length=50, default=False,)
Mkid = models.ForeignKey(MotorMakes,on_delete=models.CASCADE, default=False)
Mlid = models.IntegerField(default=False, unique=True)
MotorImage = models.ImageField(upload_to='Car_Pics', default=False,blank=True)
def __str__(self):
return self.MotorModelName or ''
def __unicode__(self):
return u'%s' % (self.MotorModelName) or ''
class Meta:
ordering = ('MotorMakeName',)
class MotorDetail(models.Model):
MotorMakeName = models.CharField(max_length=50, default=False,)
MotorModelName = models.CharField(max_length=50, default=False,)
title = models.CharField(max_length=100, default=False,)
fuel = models.CharField(max_length=25, default=False,)
body = models.CharField(max_length=25, default=False,)
engine = models.CharField(max_length=5, default=False,)
#Mkid = models.CharField(max_length=5, default=False,)
#Mlid = models.CharField(max_length=5, default=False,)
Mkid = models.ForeignKey(MotorMakes,on_delete=models.CASCADE, default=False, null=True)
Mlid = models.ForeignKey(MotorModelsV2,on_delete=models.CASCADE, default=False, null=True)
RRP = models.DecimalField(max_digits=10, decimal_places=2, default ='0' )
MotorImage = models.ImageField(upload_to='Car_Pics', default=False,blank=True)
def __str__(self):
#return self.title or ''
return '%s %s %s' % (self.MotorMakeName,self.MotorModelName, self.title,) or ''
def __unicode__(self):
return u'%s' % (self.title) or ''
class Meta:
ordering = ('MotorMakeName',)
View.py
def SearchInventory(request):
if request.method=='GET':
inputvalue = request.GET['modelselection']
print(inputvalue)
DisplayInventory = GarageInventory.objects.all().filter(ListModel=inputvalue) #join to MotorDetails with Title and Body to get the image, as well as the RRP, then just output this to html
DisplayImage = MotorModelsV2.objects.all().filter(MotorModelName=inputvalue)
DisplayRRP=MotorDetail.objects.all().filter(MotorModelName=inputvalue).aggregate(Min('RRP'))
else:
DisplayInventory = GarageInventory.objects.all()
return render(request, 'search_results.html', {'GarageInventoryView':DisplayInventory,'ImageView':DisplayImage, 'RRPView': DisplayRRP })
Index.html
{% for inv in GarageInventoryView %}
<tbody class = "table table-hover">
<tr align="center">
<td align="center">{{inv.GarageID}}</td>
<td align="center">{{inv.ListModel}}</td>
<td align="center">{{inv.ListMake}}</td>
<td align="center">{{inv.Title}}</td>
<td align="center">{{inv.Year}}</td>
<td align="center">{{inv.BodyType}}</td>
<td align="center">{{inv.GaragePrice}}</td>
<td align="center">Base RRP is {{ RRP__min}}</td>
{% for imgs in ImageView %}
<td> <img src="{{ imgs.MotorImage.url }}" alt="{{inv.ListModel}} image",height="75", width="120" /></td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
In your views.py, you defined the key for the aggregate result, inside your context dictionary, as RRPView:
return render(request, 'search_results.html', {'GarageInventoryView':DisplayInventory,'ImageView':DisplayImage, 'RRPView': DisplayRRP })
But when you are attempting to access the aggregate value in your template, you are trying to access the default name for the aggregate value (RRP__min), instead of the key stored in your context:
<td align="center">Base RRP is {{ RRP__min}}</td>
Change that line to:
<td align="center">Base RRP is {{ RRPView.RRP__min }}</td>
Your context dictionary contains a key called RRPView; the value of RRPView is the dictionary returned by the Aggregate function. Inside that dictionary is the key RRP__min, which holds as a value the result of your aggregate.
I want to calculate total sums while processing a table, so as rendering goes row by row but I need totals over the columns, I need a counter per column.
{% assign cols = "col1,col2" | split: "," %}
{% assign rows = "row1,row2" | split: "," %}
{% assign total = ????? %}
...
{% for row in rows %}
<tr>
{% for col in cols %}
<td>
{% for post in site.posts %}
{% if post.colThing == col and post.rowThing == row %}
{% assign total[row] = total[row] | plus: post.thatNumber %}
.... {{ post.thatNumber }} ...
{% endif %}
{% endfor %}
</td>
{% endfor %}
</tr>
{% endfor %}
<tr>
{% for col in cols %}
<td>
.... {{ total[row] }} ...
</td>
{% endfor %}
</tr>
The best I could come up with is to parse the site.posts again for the total:
...
<tr>
{% for col in cols %}
{% assign total = 0 %}
{% for post in site.posts %}
{% if post.colThing == col %}
{% assign total = total | plus: post.thatNumber %}
{% endif %}
{% endfor %}
<td>
.... {{ total }} ...
</td>
{% endfor %}
</tr>
Is that the most efficient way of getting that total?
Your idea of using a hash to store totals is evident except that Jekyll cannot manipulate ruby hashes. total[row] is a hash entry that cannot be populated from liquid.
The way you're printing your totals is one of the solutions.
On the Efficiency side,it might be interesting to explore an other way if you want to avoid to loop over all posts each time you want to populate a cell, by using where and where_exp filters. Depending of the number of posts you're manipulating, this can be more efficient :
{% assign cols = "col1,col2" | split: "," %}
{% assign rows = "row1,row2" | split: "," %}
<thead><tr>{% for col in cols %}<th>{{ col }}</th>{% endfor %}</tr></thead>
{% for row in rows %}
<tr>
{% for col in cols %}
<td>
{% comment %}
where_exp: "post", "post.colThing == col and post.rowThing == row"
returns null if no post fulfill conditions
or
returns an array of posts fulfilling conditions
first
returns the first post of the returned array
{% endcomment %}
{% assign post = site.posts | where_exp: "post", "post.colThing == col and post.rowThing == row" | first %}
{% if post != null %}
{{ post.title }} : {{ post.thatNumber }}
{% else %}
NO DATAS AT THIS POSITION
{% endif %}
</td>
{% endfor %}
</tr>
{% endfor %}
<tfoot><tr>
{% for col in cols %}
{% assign total = 0 %}
{% comment %}
Select posts that are in each column
{% endcomment %}
{% assign posts = site.posts | where: "colThing", col %}
{% for post in posts %}
{% assign total = total | plus: post.thatNumber %}
{% endfor %}
<td>{{ total }}</td>
{% endfor %}
</tr></tfoot>
I have the following two models:
class Company(db.Model):
__tablename__ = "company"
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(128), index=True, unique=True, nullable=False)
comments = db.relationship("Comment", backref="comment", lazy=True)
class Comment(db.Model):
__tablename__ = "comment"
id = db.Column(db.Integer, primary_key=True)
company_id = db.Column(db.Integer, db.ForeignKey("company.id"), nullable=False)
body = db.Column(db.Text)
created_datetime = db.Column(
db.TIMESTAMP(timezone=True), default=datetime.datetime.now
)
And the following Jinja2 template:
{% for comment in company.comments %}
<div><span>{{ comment.created_datetime }}:</span> {{comment.body}}</div>
{% endfor %}
I'd like to order the comments by created_datetime desc.
Can I do that in the Jinja2 template?
In Jinja2:
Ascending
{% for comment in company.comments|sort(attribute='created_datetime') %}
<div><span>{{ comment.created_datetime }}:</span> {{comment.body}}</div>
{% endfor %}
Descending
{% for comment in company.comments|sort(attribute='created_datetime', reverse = True) %}
<div><span>{{ comment.created_datetime }}:</span> {{comment.body}}</div>
{% endfor %}
Or do the sort in Python prior to passing company to the template:
#app.route('/')
def index():
# e.g company 10
company = Company.query.join(Company.comments).filter(Company.id == 10).order_by(Comment.created_datetime.desc()).first_or_404()
render_template('index.html', company=company)
I'm using Django 1.11 and I would like to get the correct syntax in order to translate my MySQL Join request to Django QuerySet Syntax.
I have 3 different models (1 Model in my Identity application and 2 Models in my Fiscal application) as following :
#Identity.Individu
class Individu(models.Model):
NumeroIdentification = models.CharField(max_length=30, null=True, verbose_name='Numero Identification physique', unique=True)
Civilite = models.CharField(max_length=12,choices=CHOIX_TITRE, verbose_name='Civilité')
NomJeuneFille = models.CharField(max_length=30, verbose_name='Nom de jeune fille', blank=True)
Nom = models.CharField(max_length=30, verbose_name='Nom de famille')
Prenom = models.CharField(max_length=30, verbose_name='Prénom(s)')
#Fiscal.Profession
class Profession (models.Model) :
Employe = models.ForeignKey(Individu, related_name='Individu', verbose_name='Individu', null=False, to_field='NumeroIdentification')
Entreprise = models.ForeignKey(Societe, related_name='Société', verbose_name='Société', null=False, to_field='NumeroIdentification')
NumeroImpot = models.CharField(max_length=30, null=True, verbose_name='Numéro Imposition', unique=True)
Profession = models.CharField(max_length=30, verbose_name='Profession')
#Fiscal.Salaire
class Salaire (models.Model) :
Employe = models.ForeignKey(Individu, related_name='Salaire_Individu', verbose_name='Salaire_Individu', null=False, to_field='NumeroIdentification')
Salaire_B_mensuel = models.IntegerField(verbose_name='Salaire Brut Mensuel')
Salaire_N_mensuel = models.IntegerField(verbose_name='Salaire Net Mensuel')
With Mysql, I have this request which works fine :
SELECT * FROM Identity_individu i
INNER JOIN Fiscal_profession p ON i.NumeroIdentification = p.Employe_id
INNER JOIN Fiscal_salaire s on i.NumeroIdentification = s.Employe_id;
I thing I have to use prefetch_related and I wrote this (first step, join between two tables) :
#login_required
def FiscalReporting(request) :
Contribuable = Individu.objects.prefetch_related("Profession").all().filter(NumeroIdentification=Profession.Employe)
context = {
"Contribuable" : Contribuable,
}
return render(request, 'Fiscal_Reporting.html', context)
And in my template :
<table style="width:120%">
<tbody>
<tr>
<th>ID</th>
<th>État</th>
<th>N° Identification</th>
<th>Civilité</th>
<th>Nom</th>
<th>Prénom</th>
<th>Date de Naissance</th>
<th>N° Fiscal</th>
<th>Salaire Annuel Net</th>
</tr>
{% for item in Contribuable %}
<tr>
<td>{{ item.id}}</td>
<td>{{ item.Etat}}</td>
<td>{{ item.NumeroIdentification}}</td>
<td>{{ item.Civilite }}</td>
<td>{{ item.Nom }}</td>
<td>{{ item.Prenom }}</td>
<td>{{ item.DateNaissance }}</td>
<td>{{ item.NumeroImpot }}</td>
<td>{{ item.Employe.Salaire_N_annuel }}</td>
</tr>
{% endfor %}
</tbody>
</table>
Any idea about my issue ? I don't find any result up to now because my array is empty :/
Then, How I can add a supplementary join in my Django QuerySet ?
You can use prefetch_related to prefetch more than one related table like this:
Contribuable = Individu.objects.prefetch_related("Individu", "Salaire_Individu")
Note that I use "Individu" related_name of Profession model as prefetch_related argument.
Now in template you can iterate over each profession and Salaire_Individu like this:
{% for item in Contribuable %}
...
<td>{{ item.Nom }}</td>
{% for profession in item.Individu.all %}
<td>{{ profession.NumeroImpot }}</td>
{% endfor %}
{% for salary in item.Salaire_Individu.all %}
<td>{{ salary.Salaire_B_mensuel }}</td>
{% endfor %}
{% endfor %}