No such column: AGC.id Django - django

I've been working with an existing datatable, so I create the models using inspectdb. My class doesn't have a primary key, so Django adds an automatic primary key named id when I makemigrations and migrate. Later, when I define the template, views, and URLs to see the class table at my website, there is an error like this one:
no such column: AGC.id
I don´t know how to fix it, I'm new to using Django.
Model:
class Agc(models.Model):
index = models.BigIntegerField(blank=True, null=True)
area = models.TextField(db_column='AREA', blank=True, null=True) # Field name made lowercase.
periodo = models.BigIntegerField(db_column='PERIODO', blank=True, null=True) # Field name made lowercase.
demanda = models.TextField(db_column='DEMANDA', blank=True, null=True) # Field name made lowercase. This field type is a guess.
class Meta:
db_table = 'AGC'
Template:
{% extends "despachowebapp/Base.html" %}
{% load static %}
{% block content %}
<table class="table table-bordered">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">Index</th>
<th scope="col">Area</th>
<th scope="col">Periodo</th>
<th scope="col">Demanda</th>
</tr>
</thead>
<tbody>
{% if AGCs %}
{% for AGC in AGCs %}
<tr>
<th scope='row'>{{ Agc.id }}</th>
<td>{{ Agc.index }}</td>
<td>{{ Agc.index }}</td>
<td>{{ Agc.area }}</td>
<td>{{ Agc.periodo }}</td>
<td>{{ Agc.demanda }}</td>
</tr>
{% endfor %}
{% else %}
<h1>No hay datos </h1>
</tbody>
</table>
{% endblock %}
Views:
def index(request):
AGCs=Agc.objects.all()
contexto={'AGCs': AGCs }
return render(request,'OfertasAGC.html', contexto)
URLs:
urlpatterns =[
path('admin/', admin.site.urls),
path('', include('webapp.urls')),
path('prueba/',views.index),
]

Django models must always have a primary key, you can use AutoField or BigAutoField or use another model field, but you will need to add the primary_key = True attribute.
For example:
class Agc(models.Model):
index = models.BigIntegerField(primary_key=True)
area = models.TextField(db_column='AREA', blank=True, null=True) # Field name made lowercase.
periodo = models.BigIntegerField(db_column='PERIODO', blank=True, null=True) # Field name made lowercase.
demanda = models.TextField(db_column='DEMANDA', blank=True, null=True) # Field name made lowercase. This field type is a guess.
class Meta:
db_table = 'AGC'

Related

Django render many to many attributes after query, display None

I am using slug to query the model, and render result in HTML.
The code is unable to render actual name of region, it just return None
Model
class Region(models.Model):
name = models.CharField(blank=False, unique=True)
def __str__(self):
return self.name
class Theme(models.Model):
name = models.CharField(blank=False, unique=True)
slug = models.SlugField(default="", null=False)
def __str__(self):
return self.name
class ETF(models.Model):
ticker = models.CharField(max_length=6, blank=False, db_index=True, unique=True)
full_name = models.CharField(max_length=200, blank=False)
# many to many
region = models.ManyToManyField(Region)
theme = models.ManyToManyField(Theme)
views.py
def theme_etf(request, slug): # render ETFs with theme filter
filtered_results = ETF.objects.filter(theme__slug=slug)
return render(request, "etf/list_etf.html", {
"ETFs": filtered_results
})
Part of list_etf.html
{% for ETF in ETFs %}
<tr>
<td>{{ ETF.ticker }}</td>
<td>{{ ETF.full_name }}</td>
<td>{{ ETF.region.name }}</td> # What should I use in this line
</tr>
{% endfor %}
The code is unable to render actual name of region, it just return None
Result
Ticker, Name, Region
ARKF, ARK Fintech Innovation ETF, None
ARKK, ARK Innovation ETF, None
KEJI, Global X China Innovation, None
I would like to have this:
Ticker, Name, Region
ARKF, ARK Fintech Innovation ETF, Global
ARKK, ARK Innovation ETF, Global
KEJI, Global X China Innovation, China
I have the information in the database. I have checked it in admin.
Can an ETF have multiple regions as implied by your database design? If it does not I would suggest you use ForeignKey instead.
You are accessing the region field as if it were a ForeignKey.
In your database design you need to iterate over the objects saved in the ManyToManyField using .all.
{% for ETF in ETFs %}
<tr>
<td>{{ ETF.ticker }}</td>
<td>{{ ETF.full_name }}</td>
<td>{% for region in ETF.region.all %}{{ region.name }}{%endfor%}</td>
</tr>
{% endfor %}
Because you have many-to-many relationship, you cannot simply have single values. So, you have to list values.
{% for ETF in ETFs %}
<tr>
<td>{{ ETF.ticker }}</td>
<td>{{ ETF.full_name }}</td>
<td>
<ol>
{% for region in ETF.region %}
<li>{{region.name}}</li>
{% endfor %}
</ol>
</td>
</tr>
{% endfor %}

Django initial loading of page taking too long

Hi I am a beginner at Django and I am working on a project that lists 100 companies in each page along with there contacts and also the amount of items sold. Here is an example:
As you can see the initial loading time of the page is very high. But when I refresh the page it refreshes very fast because I am using caching.
Here are some of my other files:
models.py
from __future__ import unicode_literals
from django.db import models
class Company(models.Model):
name = models.CharField(max_length=150)
bic = models.CharField(max_length=150, blank=True)
def get_order_count(self):
orders = self.orders.count()
return orders
def get_order_sum(self):
orders = Order.objects.filter(company=self)
total_sum = sum([x.total for x in orders])
return total_sum
class Meta:
ordering = ['-id']
class Contact(models.Model):
company = models.ForeignKey(
Company, related_name="contacts", on_delete=models.PROTECT)
first_name = models.CharField(max_length=150)
last_name = models.CharField(max_length=150, blank=True)
email = models.EmailField()
def get_order_count(self):
orders = self.orders.count()
return orders
class Order(models.Model):
order_number = models.CharField(max_length=150)
company = models.ForeignKey(Company, related_name="orders", on_delete=models.CASCADE)
contact = models.ForeignKey(Contact, related_name="orders", on_delete=models.SET_NULL, blank=True, null=True)
total = models.DecimalField(max_digits=18, decimal_places=9)
order_date = models.DateTimeField(null=True, blank=True)
added_date = models.DateTimeField(auto_now_add=True)
modified_date = models.DateTimeField(auto_now=True)
def __str__(self):
return "%s" % self.order_number
views.py
from django.shortcuts import render
# Create your views here.
from django.views.generic import ListView
from mailer.models import Company, Contact, Order
class IndexView(ListView):
template_name = "mailer/index.html"
model = Company
paginate_by = 100
The html
<div class="container">
<table class="table table-borderless">
{% if is_paginated %}
<tr><td>
{% if page_obj.has_previous %}
«
{% endif %}
</td>
<td></td>
<td></td>
<td>
{% if page_obj.has_next %}
»
{% endif %}
</td>
</tr>
{% endif %}
<tr>
<th>Name</th>
<th>Order Count</th>
<th>Order Sum</th>
<th>Select</th>
</tr>
{% for company in company_list %}
<tr>
<td>{{ company.name }}</td>
<td>{{ company.get_order_count }}</td>
<td>{{ company.get_order_sum|floatformat:2 }}</td>
<td><input type="checkbox" name="select{{company.pk}}" id=""></td>
</tr>
{% for contact in company.contacts.all %}
<tr>
<td> </td>
<td>{{ contact.first_name }} {{ contact.last_name }}</td>
<td>Orders: {{ contact.get_order_count }}</td>
<td></td>
</tr>
{% endfor %}
{% endfor %}
</table>
</div>
Is there any way in which I can reduce the initial load time. Please show me an efficient way to solve this problem.
Each {{company.get_order_count}} will hit the DB. Admittedly with a very simple query, but even so, it will slow things down.
You want to annotate the objects with this count. Use
from django.db.models import Count
class IndexView(ListView):
template_name = "mailer/index.html"
model = Company
paginate_by = 100
def get_queryset(self):
return super().get_queryset().annotate( num_orders=Count('orders') )
and replace {{ company.get_order_count }} with {{ company.num_orders }}. This will turn N+1 DB queries into one DB query.
That's the easy one. There's a similar problem with get_order_sum which can almost certainly be solved with another annotation involving the django.db.Sum. Sorry but its late and my stomach is growling and I don't have any confidence that I would get that one right straight off the top of my head.
The cheat sheet on annotation is here. You might also need to look at aggregation.
Oh, and install Django_debug-toolbar in your developer environment. Every time in future it gets slow, you can just click there to see what SQL was executed and how long it took.

Print a project name in jinja template

I have the following models
AcsObject class
class AcsObjects(models.Model):
object_id = models.IntegerField(primary_key=True)
object_type = models.ForeignKey('AcsObjectTypes', db_column='object_type')
context = models.ForeignKey('self', blank=True, null=True)
security_inherit_p = models.BooleanField()
creation_user = models.IntegerField(blank=True, null=True)
Projects class
class ImProjects(models.Model):
project = models.ForeignKey('AcsObjects',related_name='project', on_delete=False, primary_key=True)
project_name = models.CharField(max_length=1000)
project_nr = models.CharField(max_length=100)
project_path = models.CharField(max_length=100)
TimesheetTasks class
class TimesheetTasks(models.Model):
task = models.ForeignKey('Projects', related_name='t_task', on_delete=False, primary_key=True)
uom = models.ForeignKey('Categories', related_name='u_uom', on_delete=False)
planned_units = models.FloatField(blank=True, null=True)
billable_units = models.FloatField(blank=True, null=True)
I wrote the following code into views.py file.
class TimesheetData(TemplateView):
template_name = 'timesheet.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["da"] = TimesheetTasks.objects.all()
return context
I want to print a project_name but it is giving me a task_id ( task_id and project_id are same) using jinja template.
timesheet.html
<body>
<p> {{da}} </p>
<table class="table table-light">
<thead class="thead-light">
<tr>
<th>Task </th>
</tr>
</thead>
<tbody>
{% for timesheet in da %}
<tr>
<td> {{timesheet.task}} </td>
</tr>
{% endfor %}
</tbody>
</table>
</body>
It is giving me a blank output
Output
That's simply just because you're not access to product_name field yet.
<tbody>
{% for timesheet in da %}
<tr>
<td> {{timesheet.task}} </td>
</tr>
{% endfor %}
</tbody>
With this, Jinja just render the task id (project id), because Jinja think that you're not need any other information but just the foreign key value. So to be able to see the project_name, you should use this instead: timesheet.task.project_name, it does the job.
<tbody>
{% for timesheet in da %}
<tr>
<td> {{timesheet.task.project_name}} </td>
</tr>
{% endfor %}
</tbody>
Just want to mention that this could lead to another issue (performance issue) when Jinja have to query the data when render the template. To get rid of that, consider to use select_related which is an API of Django Queryset, check it out and gain some experiment that API, it really useful when using Django.

How to set field value based on what user click in Django ListView

I have two models Parent and Child. I would like to display both values in a ListView, whereby there is an Add Child button for each family.
Supposed that the parents are already populated, when I click Add Child, I would love that in the form of Child, the parent field are already set to the corresponding family name (please see code below).
Simple model would be:
class Family(models.Model):
family_name = models.CharField(max_length=100, default='', blank=False)
father_name = models.CharField(max_length=100, blank=False, default='')
mother_name = models.CharField(max_length=100, blank=False, default='')
def get_absolute_url(self):
return reverse('family-list')
def __str__(self):
return str(self.family_name)
class Children(models.Model):
parent = models.ForeignKey(Family, blank=False, default=None, null=True, on_delete=models.PROTECT, related_name='their_child')
child_name = models.CharField('4Jet ID', max_length=100, default='', blank=False)
birth_date = models.DateField(default=timezone.now, blank=False)
def get_absolute_url(self):
return reverse('family-list') # both return to family list view
The View using simple generic view:
class FamilyList(ListView):
model = Family
template_name = '/family_list.html'
context_object_name = 'fam_list'
# class NewParent omitted
class NewChild(CreateView):
model = Children
template_name = '/child_new.html'
context_object_name = 'child'
fields = [
'parent', 'child_name', 'birth_date'
]
and the simplified template:
<!--file: family_list.html-->
{% for fam in fam_list %}
<table>
<tr>
<th class="header"></th>
<th class="header">Family Name</th>
<th class="header">Father's First Name</th>
<th class="header">Mother's First Name</th>
<th class="header">Add Child</th>
</tr>
<tr>
<td>+</td>
<td>{{ fam.family_name }}</td>
<td>{{ fam.father_name }}</td>
<td>{{ fam.versand_datum | date:"d M, Y" }}</td>
<td>Add Child
</td>
</tr>
<tr >
<td colspan="5">
<div>
<table>
<tr>
<th class="header">Child's First Name</th>
<th class="header">Date of Birth</th>
</tr>
{% for child in fam.their_child.all %}
<tr>
<td>{{ child.child_name }}</td>
<td>{{ child.birth_date | date:"d M, Y" }}</td>
</tr>
{% endfor %}
</table>
</div>
</td>
</tr>
</table>
{% endfor %}
I've tried playing with the get_initial method in the NewChild view but by setting pdb trace within the method, the self.request.GET.getlist() gives me empty list.
Again, I just want that when I click the Add Child button in the template, the parent field in the child form will be set corresponding to the parent that I clicked.
Any idea how to do that?
All help are much appreciated
Your template is only a template to wiew a result, not to record an other one.
You must write a form and the most simple to you is to follow the initial Django tutorial.
Url : https://docs.djangoproject.com/en/2.1/intro/tutorial04/
You need :
- write a form template
- write a service to record you form result.
- and write a new template to view your record.
Take the time to do the initial tutorial, it is simple to follow

Passing raw SQL to Django template

I need to display a large amount of data that I don't want paginated because I'm using a jQuery tablesorter, and using Person.objects.all() in a view is very expensive for the database. Takes too long to load, so I'm trying to perform raw SQL in my view.
I tried using Django's generic views, but they were just as slow as the objects.all() method.
Here are my models. Essentially, I want to display all persons while counting how many times they have appeared in, say, var1 or var2.
class Person(models.Model):
name = models.CharField(max_length=64, blank=True, null=True)
last_name = models.CharField(max_length=64,)
slug = models.SlugField()
class Object(models.Model):
title = models.ForeignKey(Title)
number = models.CharField(max_length=20)
var1 = models.ManyToManyField(Person, related_name="var1_apps", blank=True, null=True)
var2 = models.ManyToManyField(Person, related_name="var2_apps", blank=True, null=True)
var3 = models.ManyToManyField(Person, related_name="var3_apps", blank=True, null=True)
# ...
slug = models.SlugField()
from django.db import connection
def test (request):
cursor = connection.cursor()
cursor.execute('SELECT * FROM objects_person')
persons = cursor.fetchall() # fetchall() may not be the right call here?
return render_to_response('test.html', {'persons':persons}, context_instance=RequestContext(request))
Template:
<table class="table tablesorter">
<thead>
<tr>
<th>Name</th>
<th>Var1</th>
<th>Var2</th>
<th>Var3</th>
</tr>
</thead>
<tbody>
{% for person in persons %}
<tr>
<td>{{ person.last_name }}{% if person.name %}, {{ person.name }}{% endif %}</td>
<td>{{ person.var1_apps.count }}</td>
<td>{{ person.var2_apps.count }}</td>
<td>{{ person.var3_apps.count }}</td>
</tr>
{% endfor %}
</tbody>
</table>
What it does it iterate blank lines, but if I just call {{ creator }} it will show the entire SQL table -- which I do not want. I must be doing something wrong with the query, so any help appreciated.
The problem isn't the Person.objects.all(). When you loop through that queryset, you are doing three queries for every item in the queryset to calculate the counts.
The answer is to annotate your queryset with the counts for each field.
# in the view
persons = Person.objects.annotate(num_var1_apps=Count('var1_apps'),
num_var2_apps=Count('var2_apps'),
num_var3_apps=Count('var3_apps'),
)
# in the template
{% for person in persons %}
<tr>
<td>{{ person.last_name }}{% if person.name %}, {{ person.name }}{% endif %}</td>
<td>{{ person.num_var1_apps }}</td>
<td>{{ person.num_var2_apps }}</td>
<td>{{ person.num_var3_apps }}</td>
</tr>
{% end for %}