Display the descriptive status of options - django

I define a article_table model data in modles.py, especially set a options attribute for status
class Article(models.Model):
STATUS = (
(0, 'normal'),
(-1, 'deleted'),
)
block = models.ForeignKey(Block, on_delete=models.CASCADE)
title = models.CharField(max_length=100)
author = models.CharField(max_length=100)
content = models.CharField(max_length=1000) # set the widget
status = models.IntegerField(choices=STATUS)
date_created = models.DateTimeField(default=datetime.now)
date_updated = models.DateTimeField(auto_now=True)
def __str__(self):
return self.title
When I check the responded html, it display status with 0 from database rather than its description 'normal'
The status did not show normal as I intended.
The template of article_list.html
<table class="table table-bordered">
<tr>
<th>Status</th>
<th>Title</th>
<th>Author</th>
<th>Latest Updated</th>
</tr>
{% for article in articles %}
<tr>
<td>{{ article.status }}</td>
<td>{{ article.title }}</td>
<td>{{ article.author }}</td>
<td>{{ article.date_updated }}</td>
</tr>
{% endfor %}
</table>
How to solve such a problem?

If you use choices, then you can use get_<fieldname>_display() in the template, like this:
{{ article.get_status_display }}

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 %}

Get Display CHOICE in a ForeignKey Django Model

My models:
class Sell(models.Model):
item = models.OneToOneField(Buy, related_name='sell', on_delete=models.CASCADE)
date = models.DateField(default=timezone.now)
code = models.ForeignKey(Order, related_name='order', on_delete=models.CASCADE, null=True, blank=True)
class Order(models.Model):
status_choice = (
("W", "Aguardando aprovação do pagamento"),
("A", "Pagamento aprovado - produto em separação"),
)
code = models.CharField(max_length=100)
status = models.CharField(max_length=1, choices=status_choice, default='W')
My views:
def order(request):
orders = Sell.objects.values('code__code', 'date', 'code__status') \
.annotate(total_paid=Sum('total_paid')). \
filter(buyer__username=request.user.username).order_by('-date')
return render(request, 'orders/orders.html',
{'orders': orders})
My template:
{% for order in orders %}
<tr>
<td>{{ order.code__code }}</td>
<td>{{ order.date }}</td>
<td>{{ order.get_code__status_display }}</td>
</tr>
{% endfor %}
The output I was expecting: "Aguardando aprovação do pagamento" but it's not printing this.
Any help to display the full text instead the only word "W"?
Thank you!
You should use a period/full-stop/. to access objects related by a ForeignKey
{% for order in orders %}
<tr>
<td>{{ order.code.code }}</td>
<td>{{ order.date }}</td>
<td>{{ order.code.get_status_display }}</td>
</tr>
{% endfor %}

Using attribute from a related model django

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')

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 %}