I'm new to Django and I'm trying to learn as I go. And I've ended up in a situation where I can't figure out what is the best way forward.
snippet from models.py:
class ProjectMeta(models.Model):
project = models.ForeignKey(Project)
architect = models.CharField(max_length=200)
landscape = models.CharField(max_length=100, blank=True)
engineer = models.CharField(max_length=200, blank=True)
client = models.CharField(max_length=100)
consultant = models.CharField(max_length=100, blank=True)
size = models.DecimalField(max_digits=5, decimal_places=2, blank=True)
location = models.CharField(max_length=200)
date = models.DateField()
STATUS = (
('CP', 'Competition'),
('UC', 'Under construction'),
('CO', 'Completed'),
)
status = models.CharField(max_length=2, choices=STATUS, default=1)
And this is the view:
class ProjectDetailView(DetailView):
model = Project
def get_context_data(self, **kwargs):
context = super(ProjectDetailView, self).get_context_data(**kwargs)
context['projectmeta_list'] = ProjectMeta.objects.all()
return context
But if I want to output ProjectMeta in the template I could iterate over projectmeta_list.
{% for metadata in projectmeta_list %}
<p>Architect: {{ metadata.architect }}</p>
{% endfor %}
But this require alot of repeating myself, and I wont work. Because lets say the architect field is empty, I would get Archiect: printed to the page. Is there a built-in way of converting a model into a dict or list, so I can iterate over it and only print out fields that aren't empty to the page?
I've been looking at get_fields(), would that work? https://docs.djangoproject.com/en/1.10/ref/models/meta/#retrieving-all-field-instances-of-a-model
I tried this in the shell, threw me and AttributeError:
>>> from projects.models import *
>>> Project._projectmeta.get_fields()
You should try wrapping the <p>Architect: {{ metadata.architect }}</p> piece in a conditional {% if metadata.architect != '' %} or some condition to that effect.
Try with another ProjectMeta model. Take a look at this one.
class ProjectMeta(models.Model):
project = models.ForeignKey(Project)
name = models.CharField(max_length=50)
value = models.TextField()
And this query should work. myproject.projectmeta_set.filter(name="status")
You can use built-in default or default_if_none template filters to show a default value if it is None or empty string.
{% for metadata in projectmeta_list %}
<p>Architect: {{ metadata.architect|default:"-" }}</p>
{% endfor %}
Check this for more details.
Related
I'm working on a questionnaire and I made a page where user have a list of which questionnaires to fill and which did he filled before but I have stucked.
I like to check if the user filled a form/questionnaire before and if he didn't show him the questionnaire link.
My solutions doesn't work because it checks the db just if the user filled the questionnaire but if he did not (no row for him in the db) it shows a blank cell in my table.
(I don't know if exists query could be a solution but I can't made it work)
main.html
{% for i in oke_vezetoi %}
{% if i.vezetoi_ok == True %}
<td><button class="btn btn-sm btn-outline-info"> Kitöltöm</button>
<td><i class="fas fa-running fa-2x text-dark"></i></td>
{% else %}
<td class="text-success text-uppercase">Kitöltötted</button>
<td><i class="fas fa-check fa-2x text-success"></i></td>
{% endif %}
{% endfor %}
views.py
def main(request):
oke_vezetoi = Vezetoi.objects.filter(user_name=request.user)
oke_stressz = Stressz_teszt.objects.filter(user_name=request.user)
context = {
'oke_vezetoi': oke_vezetoi,
'oke_stressz': oke_stressz,
}
return render(request, 'stressz/main.html', context)
models.py
class Vezetoi(models.Model):
def __str__(self):
return str(self.user_name)
user_name = models.ForeignKey(User, on_delete=models.CASCADE, default=1)
vezetoi_v01 = models.IntegerField( null=True)
vezetoi_v02 = models.IntegerField( null=True)
vezetoi_v03 = models.IntegerField( null=True)
vezetoi_v04 = models.IntegerField( null=True)
vezetoi_v05 = models.IntegerField( null=True)
vezetoi_v06 = models.IntegerField( null=True)
vezetoi_v07 = models.IntegerField( null=True)
vezetoi_v08 = models.IntegerField( null=True)
vezetoi_v09 = models.IntegerField( null=True)
vezetoi_v10 = models.IntegerField( null=True)
vezetoi_v11 = models.IntegerField( null=True)
vezetoi_v12 = models.IntegerField( null=True)
vezetoi_ok = models.BooleanField()
forms.py
class VezetoiForm(forms.ModelForm):
class Meta:
model = Vezetoi
fields = ['vezetoi_v01', 'vezetoi_v02', 'vezetoi_v03', 'vezetoi_v04', 'vezetoi_v05', 'vezetoi_v06', 'vezetoi_v07', 'vezetoi_v08', 'vezetoi_v09', 'vezetoi_v10', 'vezetoi_v11', 'vezetoi_v12', 'vezetoi_ok' ]
I'm not sure if I'm interpreting your question correctly, but it seems like there are a few things that you could optimise.
It sounds like there should only be one entry per user in the Vezetoi model.
If this is true, you should enforce ForeignKey(unique=True), and you don't need a for loop and you can use Vezetoi.objects.get() in your views.py
If this is not true, and there are multiple Vezetoi integers per user, you might want to have one Vezetoi object for each integer.
If the user hasn't submitted a questionnaire, then the Vezetoi model object will not exist.
Since the object doesn't exist, it won't appear in the oke_vezetoi queryset, so the object attribute i.vezetoi_ok will not be found in your loop (this is why your table row is blank).
Assuming the field vezetoi_ok is only intended to check for the existence of the questionnaire, it can only ever be True, so you can remove it from the model definition.
If these are not true, I'll need to amend the answer and I'll ask you to provide more information about what these models are tracking, the content of the Stressz_teszt model and urls.py as well as how the VezetoiForm is implemented.
So in the case that I've described, I'd do it like this with a class based view and the get_context_data method.
models.py
class Vezetoi(models.Model):
def __str__(self):
return str(self.user_name)
user_name = models.ForeignKey(User, on_delete=models.CASCADE, unique=True)
vezetoi_v01 = models.IntegerField(null=True)
...
# vezetoi_ok = models.BooleanField()
forms.py
class VezetoiForm(forms.ModelForm):
class Meta:
model = Vezetoi
fields = '__all__'
views.py
class MainView(TemplateView):
template_name = 'main.html'
def get_context_data(self, **kwargs):
context = super().get_context_data()
context['oke_vezetoi'] = Vezetoi.objects.get(user_name=request.user)
context['oke_stressz'] = Stressz_teszt.objects.get(user_name=request.user)
return context
main.html
{% extends 'base.html' %}
{% if oke_vezetoi %}
{# do not display link #}
{% else %}
{# display link #}
{% endif %}
I have a following models.py for my Django blog, I made a following views.py to pass the value of the slug for my URL parameter.
However I am struggling to create a model in views to get other data(person & description) from Category class.
I have tried some patterns by myself but can not pass them to HTML. (always Error or not showing)
Can you please give me some idea of how to solve this.
models.py
class Category(models.Model):
person = models.CharField(max_length=20)
description = models.TextField()
slug = models.SlugField()
def __str__(self):
return self.person
views.py
def blog_category(request, category):
posts = Post.objects.filter(categories__slug__contains=category).order_by("-created_on").distinct()
context = {"category": category, "posts": posts}
return render(request, "blog_category.html", context)
HTML(Localhost:8000/slug)
{{ person }}
{{ description }}
this is full code of my models.py
class Category(models.Model):
person = models.CharField(max_length=20)
description = models.TextField()
slug = models.SlugField()
def __str__(self):
return self.person
class Recommender(models.Model):
recommender_name = models.CharField(max_length=20)
slug = models.SlugField()
def __str__(self):
return self.recommender_name
class Post(models.Model):
book_title = models.CharField(max_length=255)
author = models.CharField(max_length=255)
book_link = models.CharField(max_length=255)
recommenders = models.ForeignKey("Recommender", on_delete=models.CASCADE,)
source = models.TextField()
source_link = models.CharField(max_length=255)
created_on = models.DateTimeField(auto_now_add=True)
last_modified = models.DateTimeField(auto_now=True)
categories = models.ManyToManyField("Category", related_name="posts")
slug = models.SlugField()
def __str__(self):
return self.book_title
posts = Post.objects.filter(categories__slug__contains=category).order_by("-created_on").distinct()
Is going to return a queryset. It can have more than one instance of the model class (since you are using filter). In your context you are sending this queryset as posts to your templates.
So in your HTML you can use something like this. You need to use a for loop since there can be more than one item in posts.
{% for post in posts %}
{% for category in post.categories.all %}
{{ category.person }}
{{ category.description }}
{% endfor %}
{% endfor %}
I would look at this example.
Namely, if you render the template like it is shown in the example, you should be able to do
{{ category.person }} {{ category.description }}
My models:
class customer(models.Model):
cstid = models.AutoField(primary_key=True, unique=True)
insurance_number = models.CharField(max_length=100, blank=True, null=True)
name = models.CharField(max_length=35)
ageyrs = models.IntegerField(blank=True)
class Admission(models.Model):
id = models.AutoField(primary_key=True, unique=True)
clinic = models.ForeignKey(Clinic, on_delete=models.CASCADE)
customer = models.ForeignKey(customer, on_delete=models.CASCADE)
diagnosis = models.CharField(max_length=2000, default='', blank=True)
date_admission = models.DateTimeField(default=timezone.now)
ward = models.ForeignKey(Ward, on_delete=models.CASCADE)
bed = models.ForeignKey(Bed, on_delete=models.CASCADE)
discharged = models.BooleanField(default=False)
ip_number = models.IntegerField(blank=True)
ip_prefix = models.CharField(max_length=20, default='', blank=True)
My objective: Set a variable to a query filter, adding a property, 'is_admitted' to the queryset, so that I can pass this query set to the template and use the property while displaying data.
Code:
def is_admitted(cust):
admission = Admission.objects.filter(customer=cust, discharged=False)
admission_results = len(admission)
if admission_results > 0:
return True
return False
my_q = or_q_if_truthfull(
cstid=HospitalID,
name__lower__contains=name.lower() if name else None,
ageyrs=ageyrs if ageyrs.isdigit() else None,
agemnths=agemnths if agemnths.isdigit() else None,
mobile__contains=mobile if mobile else None,
alternate__contains=alternate if alternate else None,
email__lower__contains=email.lower() if email else None,
address__lower__contains=address.lower() if address else None,
city__lower__contains=city.lower() if city else None
)
ORSearchResult = customer.objects.filter(my_q, linkedclinic=clinicobj)
cust_set = []
cust_admission_status = []
for cust in ORSearchResult:
cust_set.append(cust)
cust_admission_status.append(is_admitted(cust))
print(f"Customer name: {cust.name} Admission status: {is_admitted(cust)}")
cust_templ_set = zip(cust_set, cust_admission_status)
And in template, I will do:
{% for cust, status in cust_templ_set %}
{{ cust.name }} {{ status }}
{% endfor %}
I want to understand how I can convert my above code by generating an aggregate over the queryset, so that I can use a property of the query, and change the template code to the following, and avoid the loop in the view, and the zip. So that the template code becomes:
{% for cust in customers %}
{{ cust.name }} {{ cust.is_admitted }}
{% endfor %}
I am not sure whether I am making complete sense, and can explain further.
I'm not sure I understood you right, perhaps you might want this:
cust = customer.objects.filter(my_q, linkedclinic=clinicobj)
is_admitted_sub_q = Admission.objects.filter(customer=OuterRef('pk'), discharged=False)
cust_templ_set = cust.annotate(is_admitted=Exists(is_admitted_sub_q), )
this will return a list of customers with additional field is_admitted which will be True if there exists at least one linked (to this customer) record in Admission.
OuterRef, Exists
One option could be to use conditional-expressions together with annotate(). It could look like this:
from django.db import models
qs = Customer.objects.filter(...) # your filter conditions go here
# now add a field to the resulting queryset
qs = qs.annotate(
active_admissions=models.Count(
models.Case(
models.When(admission__discharged=False, then=1),
output_field=models.IntegerField())))
Now each object in the queryset will have an additional attribute called active_admissions which will contain the number of active admissions.
This could be used in the template like this:
{% for cust in qs %}
{{ cust.name }} {{ cust.active_admissions }}
{% endfor %}
Maybe you need to modify the subquery to fit your specific needs. Does that help?
I'm using nested prefetching to link all my objects with each other and then pushing them to a template to show them.
My general setup: I have frameworks, categories and controls. A control is linked to a category, a category is linked to a framework. A category can also have a supercategory, in which case the category has a call to another category object. Every control also has an initial score, current score and a target score.
What I want to do is for every framework, for every supercategory, for every subcategory show every control with their scores.
Example:
Framework A
Super Category 1
Subcategory 1
Control 1
Initial
Current
Target
Control 2
...
Subcategory 2
Control 3
...
Super Category 2
Subcategory 3
Control 4
...
Framework B
...
I've already managed to do this by using a lot of nested prefetches.
My models:
# models.py
#==============[FRAMEWORKS]==============#
class Framework(models.Model):
name = models.CharField(max_length=100)
description = models.TextField(null=True)
def __str__(self):
return self.name.replace(' ', '_')
class FrameworkCat(models.Model):
name = models.CharField(max_length=100)
identifier = models.CharField(max_length=10,
null=True,
blank=True,
verbose_name="optional identifier")
framework = models.ForeignKey(Framework,
on_delete=models.CASCADE,
verbose_name="related framework")
superCat = models.ForeignKey('self',
on_delete=models.CASCADE,
verbose_name="super category",
blank=True,
null=True)
hexColor = models.CharField(max_length=10,
null=True,
blank=True,
verbose_name="hex color")
def __str__(self):
return self.name
#==============[CONTROLS]==============#
class Control(models.Model):
title = models.CharField(max_length=250)
description = models.TextField()
framework = models.ForeignKey(Framework,
on_delete=models.CASCADE,
verbose_name="related framework")
category = models.ForeignKey(FrameworkCat,
on_delete=models.CASCADE,
verbose_name="related category",
null=True)
def __str__(self):
return self.title
class ProjectScore(models.Model):
project = models.ForeignKey(Project,
on_delete=models.CASCADE,
verbose_name="related project")
control = models.OneToOneField(Control,
on_delete=models.CASCADE,
verbose_name="related control")
framework = models.ForeignKey(Framework,
on_delete=models.CASCADE,
verbose_name="related framework")
score = models.IntegerField(default=-1)
current_score = models.IntegerField(default=-1)
target = models.IntegerField(default=-1)
def __str__(self):
return "Project Score"
My (testing) view:
# views.py
def testing_models(request):
def_data = default_data(request)
frameworks = Framework.objects.prefetch_related(Prefetch('frameworkcat_set',
queryset=FrameworkCat.objects.prefetch_related(Prefetch('frameworkcat_set',
queryset=FrameworkCat.objects.prefetch_related(Prefetch('control_set',
queryset=Control.objects.select_related('projectscore').order_by('id'),
to_attr='controls')).exclude(superCat=None),
to_attr='categories')).filter(superCat=None),
to_attr='supercategories')).all()
def_data['frameworks'] = frameworks
return render(request, 'testing_models.html', def_data)
And my template to show everything:
# templates/testing_models.html
{% for framework in frameworks %}
{% for supercategory in framework.supercategories %}
<p><strong>{{ supercategory.name }}</strong></p>
{% for subcategory in supercategory.categories %}
<p>{{ subcategory.name }}</p>
{% for control in subcategory.controls %}
<p>{{ control.title }}</p>
<p>{{ control.projectscore.score }}</p>
<p>{{ control.projectscore.current_score }}</p>
<p>{{ control.projectscore.target }}</p>
{% endfor %}
{% endfor %}
{% endfor %}
{% endfor %}
This all works correctly by executing 6 queries. Now, my main question is: is there a better way to fetch these objects and link them than using all these nested prefetches? Is there some other kind of syntax that I could be using that makes it easier to read and easier to modify? I have many more things I would like to link but I'm afraid the python statement would become too big and my overview would be lost.
Much appreciated!
Hi My project works on Django and some AngularJS. I want map my Django model field values into some custom string values. The following is my Model,
class History(models.Model):
TYPE_CHOICES = (
(1, 'CREATE'),
(0, 'EDIT'),
(2, 'DELETE'),
)
user = models.ForeignKey(User, related_name='+')
mw = models.ForeignKey('CP', related_name="history")
field_name = models.CharField(max_length=192, null=False)
old_value = models.CharField(max_length=500, null=True, blank=True)
new_value = models.CharField(max_length=500, null=True, blank=True)
type = models.IntegerField(default=0, choices=TYPE_CHOICES)
date_created = models.DateTimeField(auto_now_add=True)
the type 1, 2 and 0 I need to display in my website. So i just passed the value as <td>{{t.type}}</td> But it giving me the values as 1, 2 and 0. How can I display it as create, update or delete string values? Any idea guys? Thanks in advance.
In your template change {{t.type}} to {{ t.get_type_display }}.
You can read about this in docs: get_FOO_display docs
Please take note that if you mixed django template language and some other template language like (angularjs) there will be a different outcome.
So i assume you are using angular? if thats the case
try this
<!-- if using angular js -->
{% verbatim %}
{{ data.angular_t }} {{ angularvariablescope }}
{% endverbatim %}
<!-- all django varibale -->
{{t.type}} to {{ t.get_type_display }}. {# django variable #}
or on your model.py
#property
def angular_t(self)
return self.get_type_display()
retrieve that property on your resource (tastypie)
class Resource(ModelResource):
angular_t = fields.CharField(attributes='angular_t', null=True)