I am trying to set up links to a view that allows to edit objects, in previous view.
Model:
class List(models.Model):
user = models.ForeignKey(User)
name = models.CharField(max_length=200)
type = models.PositiveIntegerField(choices=TYPE_DICT)
def __unicode__(self):
return self.name
#models.permalink
def get_absolute_url(self):
return ('EditList', None, {'list_id':self.id} )
View:
lists = List.objects.filter(user=request.user)
array = []
for list in lists:
ListDict = {'Name':list.name, 'type':types[str(list.type)], 'edit':list }
array.append(ListDict)
context = { 'array':array,}
Template:
{% for dict in array %}
<tr>
{% for key,value in dict.items %}
{% ifequal key 'edit' %}
<td>{{ key }}</td><td>{{ value.name }}</td>
{% else %}
<td>{{ key }}: </td><td>{{ value }}</td>
{% endifequal %}
{% endfor %}
</tr>
{% endfor %}
and urls conf:
urlpatterns = patterns('tst.list.views',
(r'^$', 'list'),
(r'^edit/(?P<list_id>\d+)/$', 'EditList')
,
What this line with link gives me is http://localhost/list/ as url, not http://localhost/list/edit/[objectid]/
Can anyone please tell me what am i doing wrong?
Alan
If you had wanted to do it for an unnamed urlconf, you just needed to pass the whole import string:
#models.permalink
def get_absolute_url(self):
return ('yourproject.yourapp.views.EditList', None, {'list_id':self.id} )
I also suggest you follow the PEP8 naming conventions for functions.
Ok. I got it working. What i needed to do ,was to give name to this view. When i changed my urlconf to this:
url(r'^edit/(?P<list_id>\d+)/$', 'EditList', name = 'EditList'),
Then everything started working.
Related
Is it possible to dinamically change a variable name in template?
In the view below I am sending to the template an url parameter called sl.
is it possible to pass that sl to the {{ devize.sl{{sl}} }} so that it changes dinamicaly ?
thank you
#login_required
def slList(request,centrudecost,SL):
queryset = Deviz.objects.filter(centrudecost_id=centrudecost)
sl = SL
print(centrudecost)
return render(request, "proiecte/sl_list.html", {"queryset": queryset,"sl":sl})
{% for devize in queryset %}
<td>{{ devize.sl{{sl}} }}</td>
{% endfor %}
You can not change the template variable dynamically but there is a workaround on the query side. You can create (annotate) a field (my_field) and fill it dynamically in the query:
field = "xyz_fieldname" # in your case field = "sl" + SL
queryset = Deviz.objects.annotate(my_field=F(field)).values('my_field',...).filter(centrudecost_id=centrudecost)
print(centrudecost)
return render(request, "proiecte/sl_list.html", {"queryset": queryset})
and in the template:
{% for devize in queryset %}
<td>{{ devize.my_field }} }}</td>
{% endfor %}
I am pretty new to django and try to call a django function in html to display how many objects of 'Akte' is in the respective 'Charge' object, but somehow I am missing the right way to do it.
models.py:
class Charge(models.Model):
STATI = (
('O','Offen'),
('G','Geschlossen'),
)
"Projektnr = models.CharField(max_length=30)"
Containernr = models.CharField(max_length=30)
Plombennr = models.CharField(max_length=30)
status = models.CharField(max_length=1, choices=STATI)
def __str__(self):
return self.Containernr
class Akte(models.Model):
Aktenbarcode = models.CharField(max_length=30)
"Eincheckdatum = models.datetime()"
user = models.CharField(max_length=30)
containerId = models.ForeignKey(Charge,on_delete=models.CASCADE)
kundennr = models.CharField(max_length=30)
Startdatum = models.DateField(auto_now_add=True)
def __str__(self):
return self.Aktenbarcode
and this is my views.py:
def tabelle(request):
assert isinstance(request, HttpRequest)
charge_list = Charge.objects.all()
return render(
request,
'app/tabelle.html',
{
'charge_list':charge_list,
}
)
def anzahl(containernr):
return {'anzahl': Akte.objects.filter(containerId__Containernr==containernr).count }
and here is the html code:
{% extends "app/ats.html" %}
{% block content %}
{% if not user.is_anonymous %}
<div style="margin-left:10%;color:white;"><a style="color:white"href="{% url 'home'%}">Home</a> ><a style="color:white"> Tabellenübersicht</a></div>
<div>
<table>
<tr>
<th>Containernummer</th>
<th>Status</th>
<th>Anzahl Akten</th>
<th>Plombennummer</th>
<th></th>
</tr>
{%for Charge in charge_list%}
<tr>
<td>{{Charge.Containernr}}</td>
<td>{{Charge.status}}</td>
<td>{% anzahl Charge.Containernr %}</td>
<td>{{Charge.Plombennr}}</td>
</tr>
{% endfor %}
</table>
</div>
{% endif %}
{% endblock %}
when I try it, I always get this error:
TemplateSyntaxError at /tabelle
Invalid block tag on line 19: 'anzahl(Charge.Containernr)', expected 'empty' or 'endfor'. Did you forget to register or load this tag?
what is the right way to solve this problem?
You can't call methods with arguments in the template. But you don't need to here; to get the count of Akte for that Charge you can do:
{{ Charge.akte_set.count }}
An even better - and much more efficient - approach is to get this data in the original query in your view, via annotation:
from django.db.models import Count
def tabelle(request):
charge_list = Charge.objects.all().annotate(akte_count=Count('akte'))
and now in your template you can do:
{{ Charge.akte_count }}
I have a problem comparing dates in Django. I followed the hint How to compare dates in Django but it does not work. Maybe you can help me.
My code:
modelys.py
class Customer(models.Model):
last_updated = models.DateTimeField(auto_now_add=True)
views.py
#property
def is_past_due(self):
return (date.today() - self.date)> timedelta(1)
home.html
{% if customer.last_updated.is_past_due %}
<td class="table-danger">{{ customer.last_updated }}</td>
{% else %}
<td class="align-middle">{{ customer.last_updated }}</td>
{% endif %}
I am using Bootstrap, so when the difference between two dates has a more than one day I want a tablefield to become 'danger'-ous ;-), but nothing changes.
Thanks in advance.
PS: edited the typo in def timdedelta to timedelta.
you can use days property of datetime to get the exact gap between days.
(datetime.today()- self.last_updated).days > 1
where self.last_updated is field name of "Customer" Model
Here the final code as sumup of the posts:
models.py
from datetime import datetime
class Customer(models.Model):
last_updated = models.DateTimeField(auto_now_add=True)
#...some more code...
#property
def is_past_due(self):
return (datetime.now(timezone.utc) - self.last_updated).days>1
home.html
{% if customer.is_past_due %}
<td class="align-middle table-danger">{{ customer.last_updated.date}}</td>
{% else %}
<td class="align-middle">{{ customer.last_updated}}</td>
{% endif %}
I have two models with one having a foreign key to the other as such:
Models:
class WhoAmI(models.Model):
name = models.CharField(max_length=200)
company = models.CharField(max_length=200)
def __str__(self):
return self.name
class SolarClient(models.Model):
name = models.CharField(max_length=200)
client_owner = models.ForeignKey(WhoAmI, on_delete=models.CASCADE, related_name='solarclients')
addr = models.CharField(max_length=200)
city = models.CharField(max_length=200)
state = models.CharField(max_length=200)
email = models.EmailField()
I am trying to simply display an html table showing each client a salesperson has, with the salesperson listed first with a table of clients below their name.
The only way I could figure out how to do this was to create a dictionary using the code shown below.
class Homeowners(DetailView):
def get(self, request, **kwargs):
salespersons = WhoAmI.objects.all()
homeowners = SolarClient.objects.all().order_by("client_owner") #the name 'objects' is the Manager
rangers = {}
for e in salespersons:
k = salespersons.get(id = e.id)
v = k.solarclients.all()
rangers[k] = v
return render(request, 'homeowners.html', {'homeowners': homeowners, 'salespersons': salespersons, 'rangers': rangers })
I then iterate over the dictionary using:
{% for key, values in rangers.items %}
... display salesperson
{% if values %}
{% for v in values %}
.... display clients
{% endfor %}
{% else %}
... display "No Clients"
{% endif %}
{% endfor %}
Is there a more efficient way to do this? It seems silly to put the data into a dictionary to display it, but after many, many hours of trying different methods, this is the only way I could display the data.
thanks for any suggestions.
views.py
class Homeowners(DetailView):
def get(self, request, **kwargs):
salespersons = WhoAmI.objects.all()
return render(request, 'homeowners.html', {'salespersons': salespersons })
html:
{% for sales in salespersons %}
{% for client in sales.solarclients.all %}
------ Print Client
{% empty %}
---- Client not exist
{% endfor %}
{% endfor %}
There is a nice handy template filter called regroup built in Django which does exactly what you're looking for.
# views.py
homeowners = SolarClient.objects.all().order_by("client_owner").select_related('client_owner')
return render(request, 'homeowners.html', {'homeowners': homeowners})
# homeowners.html
{% regroup homeowners by client_owner as home_owners_list %}
<ul>
{% for client_owner in home_owners_list %}
<b>{{ client_owner.grouper }}</b>
<ul>
{% for client in client_owner.list %}
<li>{{ client.name }}</li>
{% endfor %}
</ul>
{% endfor %}
</ul>
The select_related method is just for performance improvement and omitting it wouldn't affect functionality.
I have a model called Subtopic. One of my templates runs a forloop on an object, returning a different field for each cell of a table row.
Two of the table cells look up a field which is a ManytoMany foreign key, both to the same foreign model, Resource. I want each to display different results, based on the value of a boolean field within the Resource model.
What you see below is currently working fine, but doesn't attempt to filter by the boolean field.
models.py:
class ICTResourceManager(models.Manager):
def get_query_set(self):
return super(ICTResourceManager, self).get_query_set().filter('is_ict': True)
class NonICTResourceManager(models.Manager):
def get_query_set(self):
return super(NonICTResourceManager, self).get_query_set().filter('is_ict': False)
class Resource(models.Model):
subtopics = models.ManyToManyField(Subtopic)
external_site = models.ForeignKey(ExternalSite)
link_address = models.URLField(max_length=200, unique=True, verify_exists=False)
requires_login = models.BooleanField()
is_ict = models.BooleanField()
flags = models.ManyToManyField(Flag, blank=True)
comment = models.TextField()
def __unicode__(self):
return u'%s %s' % (self.external_site, self.link_address)
objects = models.Manager()
ict_objects = ICTResourceManager()
nonict_objects = NonICTResourceManager()
class Meta:
ordering = ['external_site', 'link_address']
views.py:
def view_ks5topic(request, modulecode, topicshortname):
listofsubtopics = Subtopic.objects.filter(topic__module__code__iexact = modulecode, topic__shortname__iexact = topicshortname)
themodule = Module.objects.get(code__iexact = modulecode)
thetopic = Topic.objects.get(module__code__iexact = modulecode, shortname__iexact = topicshortname)
return render_to_response('topic_page.html', locals())
My template:
{% for whatever in listofsubtopics %}
<tr>
<td>
{{ whatever.objective_html|safe }}
<p>
{% if request.user.is_authenticated %}
{% with 'objective' as column %}
{% include "edit_text.html" %}
{% endwith %}
{% else %}
{% endif %}
</td>
<td>
{% regroup whatever.resource_set.all by external_site.name as resource_list %}
{% for external_site in resource_list %}
<h4>{{ external_site.grouper }}</h4>
<ul>
{% for item in external_site.list %}
<li>{{ item.comment }}</li>
{% endfor %}
</ul>
{% endfor %}
</td>
</tr>
{% endfor %}
As you can see, I've added extra managers to the model to do the filtering for me, but when I replace the appropriate lines in the template, I just get blanks. I have tried: for external_site.ict_objects in resource_list and for item.ict_objects in resource_list and <a href="{{ item.ict_objects.link_address }}">. If this were in the view I could probably do the filter just by .filter('is_ict': True), but with this being inside a forloop I don't know where to do the filtering.
I also tried writing regroup whatever.resource_set.filter('is_ict': True) in the template, but the syntax for regrouping seems to use resource_set.all rather than resource_set.all() (and I don't know why) so the filter text doesn't work here.
Turns out it was possible to do it using a custom template filter. The original efforts to filter within the template weren't working, given that as is well documented the template language is not a fully-fledged python environment. My original question remains open for anyone who knows an alternative method that more directly addresses the question I was originally asking, but here's how I did it:
myapp_extras.py:
from django import template
register = template.Library()
def ict(value, arg):
"filters on whether the is_ict Boolean is true"
return value.filter(is_ict=arg)
register.filter('ict', ict)
My template, note the use of the custom filter in line 2:
<td>
{% regroup whatever.resource_set.all|ict:1 by external_site.name as resource_list %}
{% for external_site in resource_list %}
<h4>{{ external_site.grouper }}</h4>
<ul>
{% for item in external_site.list %}
<li>{{ item.comment }}</li>
{% endfor %}
</ul>
{% endfor %}
</td>
After this I was able to remove the additional custom managers from the model.
One further question, when filtering for the boolean is_ict field, I found that I had to use filter(is_ict=1) and filter(is_ict=0). Is that the only way to refer to a True or False value?