I'm a new Django programmer and I'm writing a learning app. This app have a foreign key relations and I use prefetch_related method. This system runs well ;-)
My problem is at the template, when I show the data from the table, the browser shows this menssages:
ID Bill number Warehouse Article Quantity Price (<<-- columns)
1 CabeceraDeFacturas object (1) Primer almacén Bolsa plástico .05 mm. KK. 10 1
...
The questions are:
¿Why does show the message "CabeceraDeFacturas object (1)" instead of a bill number?
¿Can I fix this? ¿How?
The information about is:
Part of models.py
class CabeceraDeFacturas(models.Model):
ID_cliente = models.ForeignKey('Clientes',on_delete=models.CASCADE)
fecha_factura = models.DateField('Fecha de factura: ')
ID_formaDePago = models.ForeignKey('FormasDePago',on_delete=models.CASCADE)
Porcentaje_IVA = models.PositiveSmallIntegerField(default=21)
Total_factura = models.IntegerField()
class Meta:
ordering = ('id',)
#def __str__(self):
# return self.id
class LineasDeFacturacion(models.Model):
ID_factura = models.ForeignKey('CabeceraDeFacturas',on_delete=models.CASCADE)
ID_almacen = models.ForeignKey('Almacen',on_delete=models.CASCADE)
ID_articulo = models.ForeignKey('Articulos',on_delete=models.CASCADE)
cantidad = models.IntegerField(default=1)
Precio = models.IntegerField()
class Meta:
default_related_name = 'lineas'
# def __str__(self):
# return str(self.ID_factura)
Part of views.py
class VerFacturaCompleta(ListView):
#model = CabeceraDeFacturas
model = LineasDeFacturacion
template_name = "ListarTodasLasFacturasConLineas.html"
# recuperar las facturas completas y líneas --> comprobar
# queryset = CabeceraDeFacturas.objects.all().select_related('lineas')
queryset = LineasDeFacturacion.objects.all().prefetch_related('ID_factura')
paginate_by = 10
And finally, the template:
<h1>Listar facturas</h1>
<table class="table">
<thead>
<tr>
<th scope="col">ID</th>
<th scope="col">Factura</th>
<th scope ="col">Almacén</th>
<th scope ="col">Artículo</th>
<th scope ="col">Cantidad</th>
<th scope="col">Precio</th>
<!--<th scope="col">Almacén</th>-->
</tr>
</thead>
<tbody>
{% for articulo in object_list %}
<tr>
<!--<th scope="row">{{ articulo.pk }}</th>-->
<th scope ="row"> {{ articulo.pk }} </th>
<td>{{ articulo.ID_factura }}</td>
<td>{{ articulo.ID_almacen }}</td>
<td>{{ articulo.ID_articulo }}</td>
<td>{{ articulo.cantidad }}</td>
<td>{{ articulo.Precio }}</td>
</tr>
{% endfor %}
</tbody>
</table>
<hr>
Thanks a lot!
Well, the template only uses "object_list". This object_list comes form a instruction like this "queryset = LineasDeFacturacion.objects.all().prefetch_related('ID_factura')"; which is in a view.
The view which I use for this template is the next:
class VerFacturaCompleta(ListView):
#model = CabeceraDeFacturas
model = LineasDeFacturacion
template_name = "ListarTodasLasFacturasConLineas.html"
# recuperar las facturas completas y líneas --> comprobar
# queryset = CabeceraDeFacturas.objects.all().select_related('lineas')
queryset = LineasDeFacturacion.objects.all().prefetch_related('ID_factura')
paginate_by = 10
I don't use a context inside the view, only, the view pass an object_list (queryset) to the template.
Thanks for your time!
I found the mistake. The problem was in the models.py declaration. The CabeceraDeFactura class didn't had a data return. When I fixed this mistake
def __str__(self):
return str(self.id)
the template shows the data correctly.
Thanks for your time!
Related
At my work everyone has to plan until they've reached their planning target. To make this easier I'm building a planning tool to plan the activities. All the activities have standard durations which are saved in the PlanningActivity model. Now I want to show a list of all the planned activities with the standard duration and also sum up the total planned time in a week. How can I use strd_duration in my added Planning's? I've tried so much, but nothing seems to work...
models.py
class PlanningActivity(models.Model):
name = models.CharField(max_length=255)
is_billable = models.BooleanField()
is_auto_realised = models.BooleanField()
strd_duration = models.PositiveIntegerField()
def __str__(self):
return self.name
class Planning(models.Model):
added_by = models.ForeignKey(
User, related_name='planning_activity', on_delete=models.DO_NOTHING
)
activity = models.ForeignKey(
PlanningActivity, on_delete=models.DO_NOTHING
)
date = models.DateField()
note = models.CharField(max_length=255)
def __str__(self):
return str(self.id)
views.py
def home(request):
planning_form = PlanningForm(request.POST)
if request.user.is_authenticated:
planning = Planning.objects.filter(added_by=request.user).order_by('-date')
contracts = UserContract.objects.filter(assigned_user=request.user)
else:
planning = ''
contract = ''
if planning_form.is_valid():
new_planning = planning_form.save(commit=False)
new_planning.added_by = request.user
new_planning.save()
return redirect('/')
else:
planning_form = PlanningForm()
return render(request, 'home.html', {'planning_form': planning_form, 'planning':planning, 'contracts':contracts})
home.html
<table class="table table-striped mt-2">
<thead class="thead-light">
<tr>
<td>Activity</td>
<td>Date</td>
<td>Note</td>
<td>Duration</td>
</tr>
</thead>
<tbody>
{% for plan in planning %}
<tr>
<td>{{ plan.activity }}</td>
<td>{{ plan.date }}</td>
<td>{{ plan.note }}</td>
<td>{{ plan.activity_id }}</td> <== HERE I WANT TO SHOW strd_duration
</tr>
{% endfor %}
</tbody>
</table>
You can access the attribute through the foreign key:
{% for plan in planning %}
<tr>
<td>{{ plan.activity }}</td>
<td>{{ plan.date }}</td>
<td>{{ plan.note }}</td>
<td>{{ plan.activity.strd_duration }}</td>
</tr>
{% endfor %}
Note that in the view, you can optimize the number of queries to the database with a .select_related(…) clause [Django-doc]:
planning = Planning.objects.filter(
added_by=request.user
).select_related('activity').order_by('-date')
I'm using Django 2.1
I've got these 2 models with a ManyToMany relationship:
class Ingrediente(models.Model):
produtor = models.ForeignKey('auth.User', on_delete=models.CASCADE, default=10)
nome = models.CharField(max_length=200)
descricao = models.TextField()
quantidade = models.DecimalField(max_digits=10, decimal_places=3)
custo = models.DecimalField(max_digits=10, decimal_places=2)
def __str__(self):
return self.nome
e
class Produto(models.Model):
nome = models.CharField(max_length=200)
descricao = models.TextField()
ingredientes = models.ManyToManyField(Ingrediente)
utilitarios = models.ManyToManyField(OutrosCustos)
def __str__(self):
return self.nome
I use the this view to return a list with all objects of Class Produto:
def produtos_list(request):
produtos = Produto.objects.filter()
return render(request, 'egg_app/produtos_list.html', {'produtos':produtos})
And in my template I write this:
<table class="table">
<thead>
<tr>
<th scope="col">Nº Produto</th>
<th scope="col">Nome</th>
<th scope="col">Ingredientes</th>
<th scope="col">Custo</th>
</tr>
</thead>
<tbody>
{% for p in produtos %}
<tr>
<th scope="row">{{ p.pk }}</th>
<td>{{ p.nome }}</td>
<td>{{ p.ingredientes }}</td>
<td>custo teste</td>
</tr>
{% endfor %}
</tbody>
</table>
But my result in the column Ingredientes has been egg_app.Ingrediente.None and not the name of the Ingrediente of the relationship (between Ingrediente and Produto). In my Django admin page, I associate this, so I'm sure about the relationship.
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
I have models called Statistics. From views, I made a ListView to display it on the template. Now my problem is I would like to see only today's == date_expiry. How can I do this using ListView?
models.py
class Statistics(models.Model):
site = models.CharField(max_length=264)
name = models.CharField(max_length=264, blank=True)
mac_add = models.CharField(max_length=264)
minutes_used = models.CharField(max_length=265)
date = models.DateTimeField(auto_now=True, blank=True)
date_expiry = models.DateTimeField()
def __str__(self):
return self.name
views.py
class DisplayStats(ListView):
model = Statistics
ordering = ['date']
html
<table class="table">
<tr>
<th>Site</th>
<th>Name</th>
<th>Mac ID</th>
<th>Hours</th>
<th>Date</th>
<th>Date Expired</th>
</tr>
{% for clients in object_list %}
<tr>
<td>{{ clients.site }}</td>
<td>{{ clients.name }}</td>
<td>{{ clients.mac_add }}</td>
<td>{{ clients.minutes_used|cut:".0" }}</td>
<td>{{ clients.date }}</td>
<td>{{ clients.date_expiry }}</td>
</tr>
{% endfor %}
</table>
you can just filter it.
import datetime
class DisplayStats(ListView):
model = Statistics
ordering = ['date']
def get_queryset(self):
# python3
queryset = super().get_queryset()
# if python2
# queryset = super(DisplayStats, self).get_queryset()
queryset.filter(date_expiry=datetime.date.today())
return queryset
You can just filter the query set. You can do it two ways:
Override the queryset
import datetime
class DisplayStats(ListView):
model = Statistics
queryset = Statistics.objects.filter(date_expiry=datetime.date.today())
ordering = ['date']
Use get_queryset()
import datetime
class DisplayStats(ListView):
model = Statistics
ordering = ['date']
def get_queryset(self):
return Statistics.objects.filter(date_expiry=datetime.date.today())
I have the following classes defined that essentially define a Node class. Each Node can have multiple NodeIntf's assigned to it. Each NodeIntf can have multiple NodeIntfIpaddr's assigned to it. One of those NodeIntfIpaddr's maybe assigned as the mgmt_ipaddr attribute on the Node object. And one of them maybe assigned to the mgmt_ipaddr_v6 attribute. Now in my template, I have essentially a nested table for the interfaces and I want to use a radio button selector to choose which of the ipaddrs is selected for the mgmt_ipaddr(_v6) attributes on the Node object, but I'm not quite sure how to do it. I think that, as I iterate over the ipaddr_formset, I have to check to see if that ipaddr represents the selected mgmt_ipaddr, but I'm not sure how to do that. Any help would be appreciated.
class Node(models.Model):
name = models.CharField(max_length=64, primary_key=True)
mgmt_ipaddr = models.ForeignKey('NodeIntfIpaddr', null=True, on_delete=models.SET_NULL)
mgmt_ipaddr_v6 = models.ForeignKey('NodeIntfIpaddr', null=True, on_delete=models.SET_NULL)
class NodeIntf(models.Model):
intf = models.CharField(max_length=32)
node = models.ForeignKey('Node', on_delete=models.CASCADE)
class Meta:
unique_together = ('node', 'intf')
class NodeIntfIpaddr(models.Model):
node_intf = models.ForeignKey('NodeIntf', on_delete=models.CASCADE)
ipaddr = InetAddressField()
class Meta:
unique_together = ('node_intf', 'ipaddr')
class NodeForm(ModelForm):
class Meta:
model = Node
class NodeIntfForm(ModelForm):
class Meta:
model = NodeIntf
class NodeIntfIpAddrForm(ModelForm):
class Meta:
model = NodeIntfIpaddr
NodeIntfIpaddrFormSet = modelformset_factory(NodeIntfIpaddr,
form=NodeIntfIpAddrForm, extra=0)
class BaseNodeIntfFormSet(BaseInlineFormSet):
def add_fields(self, form, index):
super(BaseNodeIntfFormSet, self).add_fields(form, index)
instance = self.get_queryset()[index]
pk_value = instance.pk
form.ipaddr_formset = NodeIntfIpaddrFormSet(
queryset=NodeIntfIpaddr.objects.filter(node_intf=pk_value),
prefix='INTF_%s' % pk_value)
NodeIntfFormSet = inlineformset_factory(Node, NodeIntf,
form=NodeIntfForm, formset=BaseNodeIntfFormSet, extra=0)
class NodeUpdateView(UpdateView):
form_class = NodeForm
model = Node
def get_context_data(self, **kwargs):
c = super(NodeUpdateView, self).get_context_data(**kwargs)
node = self.get_object()
c['action'] = reverse('node-update', kwargs={'pk': node.name})
if self.request.POST:
node_intfs = NodeIntfFormSet(self.request.POST, instance=node)
if node_intfs.is_valid():
addrs = node_intfs.save_all()
else:
node_intfs = NodeIntfFormSet(instance=node)
c['node_intfs_formset'] = node_intfs
return c
Template snippet:
<table class='node_intfs'>
<thead>
<tr class='node_intf'>
<th colspan='2'></th>
<th>Name</th>
<th></th>
</tr>
<tr class='node_intf_ipaddr'>
<th>IPv4 Mgmt<br><label><input type='radio' name='mgmt_ipaddr' value=''{{ node.mgmt_ipaddr|yesno:', checked' }}>None</label></th>
<th>IPv6 Mgmt<br><label><input type='radio' name='mgmt_ipaddr_v6' value=''{{ node.mgmt_ipaddr_v6|yesno:', checked' }}>None</label></th>
<th colspan='2'></th>
</tr>
</thead>
<tbody>
{% for node_intf_form in node_intfs_formset %}
<tr class='node_intf'>
<td colspan='2'></td>
<td>{{ node_intf_form.intf }}</td>
<td></td>
</tr>
{% if node_intf_form.ipaddr_formset %}
{% for ipaddr_form in node_intf_form.ipaddr_formset %}
<tr class='node_intf_ipaddr'>
<td>TODO</td> <---- These are what I can't figure out
<td>TODO</td> <---- These are what I can't figure out
<td></td>
<td>{{ ipaddr_form.ipaddr }}</td>
</tr>
{% endfor %}
{% endif %}
{% endfor %}
</tbody>
</table>
I was able to do what I needed by using the following in my template:
<td class='center'><input type='radio' name='mgmt_ipaddr' value='{{ ipaddr_form.instance.id }}'{% if node.mgmt_ipaddr_id == ipaddr_form.instance.id %} checked='checked'{% endif %}</td>
<td class='center'><input type='radio' name='mgmt_ipaddr_v6' value='{{ ipaddr_form.instance.id }}'{% if node.mgmt_ipaddr_v6_id == ipaddr_form.instance.id %} checked='checked'{% endif %}</td>
This compares the mgmt_ipaddr(_v6)_id from the Node object with the id of the instance tied to the individual ipaddr forms, accessible as ipaddr_form.instance.id.
Just for completeness, I was also previously missing the management_form for each of the node_intf_forms and ipaddr_forms.