django retrieve fields from few tables in template - django

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: &nbsp
{{ operationnoteslist.admission.patient.planned_ot_list.planned_surgery }}</label></div>
<div class="col-xs-6 col-md-3"><label >Weight: &nbsp
{{ operationnoteslist.admission.weight }}&nbsp(kg)</label></div>
<div class="col-xs-6 col-md-3"><label >Height: &nbsp
{{ operationnoteslist.admission.height }}&nbsp(cm)</label></div>
<div class="col-xs-6 col-md-3"><label >BMI: &nbsp
{{ 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.

Related

Django view for link table

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

Django output 1 field from a model within another table

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

Django manytomany accessing related column

I'm trying to get my head around how Django understands m2m relationships, in SQL you would just add some joins through the intermediate table.
I have a Container which contains various Samples. A Sample can be spread over various Containers.
So in my container I add a alias samples m2m field (essentially a book mark to the other table).
What I can do is get a single Container and display the form information, I would like to add the Sample columns to the form, if I do this for the samples m2m field it returns a multifield, but how do I access the other related fields through the m2m sample_id >=< container_id ?
class Container(models.Model):
container_id = models.AutoField(primary_key=True)
samples = models.ManyToManyField(Sample, through='JoinSampleContainer', through_fields=('container_id', 'sample_id'), related_name='container')
location_id = models.ForeignKey(Location, db_column='location_id', on_delete = models.PROTECT)
icon_desc = models.ForeignKey(Icon, db_column='icon_desc', null=True, blank=True, default='Box',on_delete = models.PROTECT)
container_name = models.CharField(max_length=50, blank=True, null=True)
container_type = models.CharField(max_length=50, blank=True, null=True)
In my Sample table I add the containers alias to act as a bookmark to the other table
class Sample(models.Model):
sample_id = models.AutoField(primary_key=True)
containers = models.ManyToManyField(Container, through='JoinSampleContainer', through_fields=('sample_id', 'container_id'), related_name='sample')
sample_number = models.IntegerField()
material_type = models.CharField(max_length=200, default='', blank=True, null=True, choices = MATERIALS)
weight = models.DecimalField(max_digits=6, decimal_places=2)
description = models.CharField(max_length=500, default='', blank=True, null=True)
recovery_method = models.CharField(max_length=200, default='', blank=True, null=True, choices = RECOVERY_METHODS)
comments = models.CharField(max_length=1000, default='', blank=True, null=True)
In this case I am managing the through table:
class JoinSampleContainer(models.Model):
id = models.AutoField(primary_key=True)
container_id = models.ForeignKey(Container, db_column='container_id', on_delete = models.PROTECT)
sample_id = models.ForeignKey(Sample, db_column='sample_id', on_delete = models.PROTECT)
So now I want to display the contents of a single container through a form. I have the url's setup to pass the container_id.
# views.py
def containercontents(request, pk):
post = get_object_or_404(Container, pk=pk)
# objects = Container.samples.all()
if request.method == "POST":
form = ContainerContentsForm(request.POST, instance=post)
if form.is_valid():
post = form.save(commit=False)
#post.user = request.user
#post.datetime = datetime.datetime.now()
post.save()
return redirect('allcontainer')
#, pk=post.pk)
else:
form = ContainerContentsForm(instance=post)
return render(request, 'container/containercontents.html', {'form': form})
The Form
# form.py
class ContainerContentsForm(forms.ModelForm):
class Meta:
model = Container
fields = (
'location_id',
'container_name',
'container_type',
'icon_desc',
'samples',
)
N.B. The samples seems to list everything regardless of the container.
Then the html
# html
contents
which passes to:
# html
<div class="">
{{ form }}
</div>
Your models are defined wrongly: You should not define the ManyToManyField on both models, only on one of them. So remove the containers field on Sample and only keep it on Container. Set the related_name to "containers" (plural). That way the relationship Container -> Sample is container.samples.all() and the reverse one is sample.containers.all().
Now the purpose of a form is to allow you to select which Samples you want to associate to a Container. So by default the field will be represented by a ModelMultipleChoiceField. The already associated Samples should be pre-selected when you initialise the form with a Container instance.
You can narrow the samples to select from by specifying the queryset for the field, by overriding the default field in the form:
class ContainerContentsForm(forms.ModelForm):
class Meta:
# same code here
samples = forms.ModelMultipleChoiceField(
queryset = Sample.objects.filter(...)
)
You say you want to "display the contents of a Container through the form", if you just want to display, why use a form? To just display the contents, loop through the related samples and display them:
{% for sample in form.instance.samples.all %}
{{ sample.sample_id }}
{% endfor %}
Note: You should rename your ids to id. sample.sample_id is bad programming style. But I already told you that.

Accessing foreign keys

I have the following models:
class Article(models.Model):
title = models.CharField(max_length=200, unique=False, null=False)
rating = models.IntegerField(default=0, null=False, unique=False)
class Shared(models.Model):
sender = models.ForeignKey(User)
article = models.ForeignKey(Article)
class SharedMap(models.Model):
item = models.ForeignKey(Shared)
receiver = models.ForeignKey(User)
Now I execute the following query:
def get_shared_feed(self):
return Article.objects.filter(shared__sharedmap__receiver=self)
And I actually get the list of articles as expected. However:
{{ article.shared_set.count }}
Gives me more than 1 if the articles was shared before. I want to get the list of articles with a single sender(e.g. friend) for each. Instead, I receive the list of articles with the set of every user that shared this article.
The solution was really easy. I just had to specify fields I want to return using values:
blog_feed = Article.objects.filter(shared__sharedmap__receiver=self).values('title', 'rating', 'shared__sender')
Then on the template:
{{ article.shared__sender }}

In django-haystack, how can I use subclasses of models?

I'm trying to get django-haystack (using a xapian backend) to index my model here for search, by the name and description fields.
I have a subclass of Item, Device, which adds a manufacturer field.
The Item model is defined thusly:
class Item(models.Model):
name = models.CharField(max_length=255, unique=True)
description = models.TextField(null=True, blank=True)
compatible_with = models.ManyToManyField('self', null=True, blank=True)
often_with = models.ManyToManyField('self', null=True, blank=True)
created_by = models.ForeignKey(User, null=True, blank=True, related_name='created_by')
verified = models.BooleanField(default=False)
verified_by = models.ForeignKey(User, null=True, blank=True, related_name='verified_by')
date_created = models.DateField(auto_now_add=True)
slug = models.SlugField(max_length=300, null=True, blank=True)
My subclass of django-haystack’s SearchIndex looks like this:
class ItemIndex(SearchIndex):
text = CharField(document=True, use_template=True)
name = CharField(model_attr='name')
description = CharField(model_attr='description')
site.register(Item, ItemIndex)
I have set up this template, in templates/search/indexes/catalog/item_text.txt:
{{ object.name }}
{{ object.description }}
What do I add to item_text.txt such that the manufacturer field gets indexed, if and only if the model object is an instance of Device?
{% if device.manufacturer %}
{{ device.manufacturer }}
{% endif %}
... the Haystack tutorial is a bit confusing on this subject (you don't actually have to use a text-file template, for one) but the basic idea is that Haystack's engine goes to town on whatever text data is in this template.
... Actually, it goes to town on whatever is in the response you send it, but if you've got the template set up you can use whatever Django template logic you want in there.
(note that the if template tag was a bit of a dog's breakfast prior to Django 1.2; if you're stuck on an earlier Django version you may have to tweak the syntax, but the principle is the same.)