I have the following models:
class Work_Music(MPTTModel, Work):
name = models.CharField(max_length=10, null=True, blank=True)
class Cast(models.Model):
name = models.CharField(max_length=100, null=True, blank=True)
def __str__(self):
return self.name
class WorkCast(models.Model):
work = models.ForeignKey(Work_Music, verbose_name=_('work'), related_name='workcast', null=True, blank=True, on_delete=models.PROTECT)
cast = models.ManyToManyField(Cast, verbose_name=_('cast'), related_name='workcast', blank=True)
def __str__(self):
return "%s" % (
", ".join(character.name for character in self.cast.all())
)
This will output: Character #1, Character #2, Character #3.
I pass in my view.py this QuerySet as context:
work = Work_Music.objects.get(pk=self.kwargs['pk']).get_descendants(include_self=False)
How do display the string that is returned when you call an instance of the WorkCast model (e.g. "Character #1, Character #2, Character #3")?
I have this currently:
{{ work.workcast }}
and it displays None
Since you query a ForeignKey in reverse, the number of related WorkCast models is a collection that can contain zero, one, or more WorkCast objects. You thus should iterate over it, like:
{% for workcast in work.workcast.all %}
{{ workcast }}
{% endfor %}
Related
So I have two models Field and Sensor which have a OneToMany connection. Im creating a page where I have all the fields and whenever i click on one i get its respective sensors. I've made 4 test sensors (3 of them are on Field1, 1 on Field2) but its printing first one to first field and 2nd one to 2nd field maybe because of the pk parameter. Any clue how to fix that ?
class Field(models.Model):
friendly_name = models.CharField(max_length=24, blank=True)
soil_type = models.CharField(max_length=24, choices=SOIL_TYPES, blank=True)
cultivation = models.CharField(max_length=128, choices=CULTIVATIONS, blank=True)
class TreeSensor(models.Model):
field = models.ForeignKey(Field, on_delete=models.CASCADE)
datetime = models.DateTimeField(blank=True, null=True, default=None)
sensor_name = models.CharField(max_length=200, blank=True)
longitude = models.DecimalField(max_digits=22, decimal_places=16, blank=True, null=True)
latitude = models.DecimalField(max_digits=22, decimal_places=16, blank=True, null=True)
View :
def detail(request, field_id):
try:
sensor = models.TreeSensor.objects.get(pk=field_id)
except models.TreeSensor.DoesNotExist:
raise Http404("No sensors for this field")
return render(request, 'dashboard/detail.html', {'sensor': sensor})
html:
<h1> {{ field.friendly_name}}</h1>
{% for sensor in field.treesensor_set.all %}
{{treesensor.sensor_name}}
{%endfor%}
I'm not sure what does this line will print out? and what is "models" in that case mean!
models.TreeSensor.objects.get(pk=field_id)
however, if you passed field_id which means the id of the Field model so, I think you can replace that filtering instead:
TreeSensor.objects.filter(field__pk=field_id)
Yeah that seemed to do the trick I also changed my template
{% for sensor in sensor %}
<ul>
<li>{{ sensor.sensor_name}}</li>
</ul>
{%endfor%}
and view :
def detail(request, field_id):
try:
sensor = models.TreeSensor.objects.filter(field__pk=field_id)
except sensor.DoesNotExist:
raise Http404("No sensors for this field")
return render(request, 'dashboard/detail.html', {'sensor': sensor})
I get the right sensors on the right fields but if a field is empty the http404 does not raise an error.
Maybe I'm doing something wrong with the does.not.exist?How to just check for an empty query and print out the corresponding text? Thanks
I have three tables in my model:
class Recipe(models.Model):
title = models.CharField(max_length=200)
excerpt = models.TextField(null=True)
category = models.CharField(max_length=10, default='FoodGroup')
cookTime = models.CharField(max_length=20, default='15Min')
prepTime = models.CharField(max_length=20, default='5Min')
process = models.TextField(null=True)
slug = models.SlugField(max_length=100, unique=True)
updated = models.DateTimeField(auto_now=True)
published = models.DateTimeField(default=timezone.now)
def get_absolute_url(self):
return reverse('recipe:single', args=[self.slug])
class Meta:
ordering = ['-published']
def __str__(self):
return self.title
class Ingredient(models.Model):
IngName = models.CharField(max_length=30)
IngType = models.CharField(max_length=20, null=True)
def __str__(self):
return self.IngName
class RecipeIngredients(models.Model):
ingredient = models.ForeignKey(Ingredient, on_delete=models.CASCADE)
recipe = models.ForeignKey(Core, on_delete=models.CASCADE)
And the view looks like this:
class RecipeView(ListView):
model = RecipeIngredients
template_name = 'core/recipes.html'
context_object_name = 'recipe'
I'm trying to then view this data using a for loop:
{% for recipe in recipe %}
{{ recipe.title }}
{% endfor%}
but nothing gets pulled using this method, I've tried looking at the docs but I'm unsure I'm doing this in the best way? I had a look at the many-to-many section of the Docs but I thought a link-table may be more appropriate for my scenario.
edit for anyone else having similar issues:
Using Django's ManyToMany model function ended up being more appropriate:
https://docs.djangoproject.com/en/3.0/topics/db/examples/many_to_many/
Answer was correct in saying object_name was poorly chosen.
The name of your iterable must be different from context_object_name.
Try different name like:
{% for diff_name in recipe %}
{{ diff_name.title }}
{% endfor%}
I have the following models:
class Work_Music(MPTTModel, Work):
name = models.CharField(max_length=10, null=True, blank=True)
key = models.CharField(max_length=10, null=True, blank=True)
tonality = models.CharField(max_length=20, null=True, blank=True)
class WorkCast(models.Model):
work = models.ForeignKey(Work_Music, verbose_name=_('work'), related_name='workcast', null=True, blank=True, on_delete=models.PROTECT)
cast = models.ManyToManyField(Cast, verbose_name=_('cast'), related_name='workcast', blank=True)
order = models.DecimalField(max_digits=100, decimal_places=2, null=True, blank=True)
class Cast(models.Model):
name = models.CharField(max_length=100, null=True, blank=True)
In view.py, I send the following in template context:
work_cast = WorkCast.objects.get(work=self.kwargs['pk'])
How do I display in the template,
Cast #1, Cast #2, Cast #3, Cast #4
How to I grab all of the cast members? Is it?
work.cast.cast.all()
doesn't yield any output.
How do I display it as a list with commas in between?
If I understand you correctly you are sending a context variable to your template called "work_cast" and this variable references one WorkCast instance.
In the django template language do not use the () so grabbing all the Cast members of that one WorkCast instance would be
work_cast.cast.all
You can interate through the instances as described in the docs:
{% for cast in work_cast.cast.all %}
{{ cast }}
{% if not forloop.last %}
,
{% endif %}
{% endfor %}
In the loops the django template language add some extra variable which you can use. In this case we use it to avoid putting a comma after the last entry of your list.
I have 2 models -
class InsName(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=30, verbose_name = "Insurer/Broker")
alias = models.TextField(max_length=80, blank=True)
def __str__(self):
return f'{self.name}, {self.alias}'
def get_absolute_url(self):
return reverse('insurer-detail', args=[str(self.id)])
class Development(models.Model):
id = models.AutoField(primary_key=True)
logno = models.CharField(validators=[RegexValidator(regex='^(SCTASK|CDLI)[0-9]{7}', message='Please enter a valid log number', code='nomatch')], max_length=13)
insurer = models.ForeignKey(InsName, on_delete=models.SET_NULL, null=True, blank=False, verbose_name="Client")
policy = models.ManyToManyField(Policy, blank=True)
on my template I am outputting a list of Developments but where insurer is output I just want the name part to output. I need to retain the alias as it is used in other templates that also calls in InsName.
I thought I could use a substring before comma method in the template but I cant see that such a thing exists. Is this possible? If not any tips on how I can achieve this is greatly appreciated!
Maybe you can do it like this using F (apart from comment of #dirkgroten):
queryset = Development.objects.all().annotate(insurer_name=F('insurer__name'))
And use it in template:
{% for item in queryset %}
{{ item.insurer_name }}
{% endfor %}
class PlannedOTList(models.Model):
patient = models.ForeignKey(Patient, on_delete=models.CASCADE)
date_added = models.DateTimeField(auto_now_add=True)
planned_surgery = models.TextField(verbose_name='diagnosis and planned surgery', blank=True) # decided by the committee
planned_date_of_surgery = models.DateField('date of surgery', null=True, blank=True)
planned_date_of_admission = models.DateField('date of admission', null=True, blank=True)
remarks = models.TextField(blank=True)
surgery_set = models.BooleanField('required surgery set', default=False)
# to_be_admitted = models.BooleanField(default=False)
hide = models.BooleanField(default=False)
objects = PlannedOTListQS.as_manager()
class Meta:
db_table = 'planned_ot_list'
ordering = ['-date_added']
class Admission(models.Model):
# general info
date_admission = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
patient = models.ForeignKey(Patient, on_delete=models.CASCADE)
class OperationNotesList(models.Model):
admission=models.ForeignKey(Admission,on_delete=models.CASCADE,null=True)
#patient=models.ForeignKey(Patient,on_delete=models.CASCADE)
date_added=models.DateTimeField(auto_now_add=True)
procedure_code=models.CharField(max_length=7)
diagnosis_code=models.CharField(max_length=10)
created_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=True, related_name='op_created_by')
pre_operation_list=models.CharField(max_length=70,blank=True)
intra_operation_list=models.CharField(max_length=70,blank=True)
post_operation_list=models.CharField(max_length=70,blank=True)
is_done=models.BooleanField(default=False)
class Meta:
db_table='operationNotesList'
class Patient(models.Model):
patientid_generated_part = models.CharField(max_length=5, default='', blank=True)
date_recorded = models.DateTimeField(default=timezone.now)
modified = models.DateTimeField(auto_now=True, null=True)
first_name = models.CharField(max_length=50)
class Meta:
db_table = 'patients'
ordering = ['-modified']
HTML Code:
<div class="row">
<div class="col-xs-6 col-md-3"><label >Proposed Operation:  
{{ operationnoteslist.admission.patient.planned_ot_list.planned_surgery }}</label></div>
<div class="col-xs-6 col-md-3"><label >Weight:  
{{ operationnoteslist.admission.weight }} (kg)</label></div>
<div class="col-xs-6 col-md-3"><label >Height:  
{{ operationnoteslist.admission.height }} (cm)</label></div>
<div class="col-xs-6 col-md-3"><label >BMI:  
{{ operationnoteslist.admission.bmi }}</label></div>
</div>
the html code above has the main model operationnoteslist.
I am trying to get values from planned_ot_list. I don't know what I am missing.
I thought the way to go is: MyownModelTable.foreignTablename.foreignTablename.field
The Proposed operation does not retrieve any values.
(As reply to the comment: There is no need for a planned_ot_list in the Patient model.)
Reverse relations (one to many) have by default a _set suffix. Also, in your PlannedOTList model, patient has not the unique flag so a patient can have several of those related to them. And on top, the model relation name in lowercase has no underscores (camel case is simply lower cased). So the reverse relation name should be:
patient.plannedotlist_set
(You can print out the available properties using dir(patient), the output will include the reverse relation properties.)
This returns a query manager and you cannot simply write patient.plannedotlist_set.planned_surgery. Instead, you have to decide whether to display the complete list or only one of its entries. If they have a natural order and you want to use the first or last, you can do this:
patient.plannedotlist_set.first # in the template or first() in view
patient.plannedotlist_set.last
To iterate over all of them use:
patient.plannedotlist_set.all # template or all() in view
Note that you should give the PlannedOTList an ordering to make this work, either by adding a Meta property like this:
Meta:
ordering = ('field1', 'field2', ...) # use '-field1' for reverse
Or, if the ordering is dependent of the view, order in the view and add the list to the template context explicitly.