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.
Related
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 %}
I recently found that too much SQL query optimization issue. django-debug-tool reported hundreds of similar and duplicate queries. So, I'm trying to figure out the best efficiency of Django ORM to avoid unnecessary Queryset evaluation.
As you see the below Store model, a Store model has many Foreign key and ManyToManyFields. Due to that structure, there are many code snippets doing the blow on HTML template files such as store.image_set.all or store.top_keywords.all. Everything starts with store. In each store detail page, I simply pass a cached store object with prefetch_related or select_related. Is this a bad approach? Should I cache and prefetch_related or select_related each Foreign key or ManyToManyField separately on views.py?
HTML templates
{% for img in store.image_set.all %}
{{ img }}
{% endfor %}
{% for top_keyword in store.top_keywords.all %}
{{ top_keyword }}
{% endfor %}
{% for sub_keyword in store.sub_keywords.all %}
{{ sub_keyword }}
{% endfor %}
views.py
class StoreDetailView(View):
def get(self, request, *args, **kwargs):
cache_name_store = 'store-{0}'.format(store_domainKey)
store = cache.get(cache_name_store, None)
if not store:
# query = get_object_or_404(Store, domainKey=store_domainKey)
query = Store.objects.all().prefetch_related('image_set').get(domainKey=store_domainKey)
cache.set(cache_name_store, query)
store = cache.get(cache_name_store)
context = {
'store': store,
}
return render(request, template, context)
models.py
class Store(TimeStampedModel):
categories = models.ManyToManyField(Category, blank=True)
price_range = models.ManyToManyField(Price, blank=True)
businessName = models.CharField(unique=True, max_length=40,
verbose_name='Business Name')
origin = models.ForeignKey(Origin, null=True, on_delete=models.CASCADE, blank=True)
ship_to = models.ManyToManyField(ShipTo, blank=True)
top_keywords = models.ManyToManyField(Keyword, blank=True, related_name='store_top_keywords')
sub_keywords = models.ManyToManyField(SubKeyword, blank=True, related_name='store_sub_keywords')
sponsored_stores = models.ManyToManyField(
'self', through='Sponsorship', symmetrical=False, related_name='sponsored_store_of_store')
similar_stores = models.ManyToManyField(
'self', through='Similarity', symmetrical=False, related_name='similar_store_of_store')
shortDesc = models.TextField(blank=True, verbose_name='Short Description')
longDesc = models.TextField(blank=True, verbose_name='Long Description')
returnPol = models.TextField(verbose_name='Return Policy', blank=True)
returnUrl = models.CharField(max_length=255, null=True, blank=True, verbose_name='Return Policy URL')
likes = models.ManyToManyField(settings.AUTH_USER_MODEL, blank=True, editable=False)
created_by = models.ForeignKey(settings.AUTH_USER_MODEL, editable=False, on_delete=models.CASCADE,
related_name='stores_of_created_by', null=True, blank=True)
updated_by = models.ForeignKey(settings.AUTH_USER_MODEL, editable=False, on_delete=models.CASCADE,
related_name='stores_of_updated_by', null=True, blank=True)
I really wouldn't advise custom caching/performance optimisation, unless it's a very last resort. Django has great docs on querysets and optimisation - if you follow those, it should be rare for you to experience major performance issues that require custom workarounds.
I think the issue here is that you're printing your objects in a template and hence calling their str() method. There's nothing wrong with this, but I'd check what variables you're using in your str() methods. I suspect you're referencing other models? I.e. the str() method in your image model (or whatever) is doing something like image.field.other_field. In this case, your query should look like:
queryset = Store.objects.prefetch_related('image_set__field')
Your final queryset may look like:
queryset = Store.objects.prefetch_related('image_set__field1', 'image_set__field2', 'top_keywords__field3', ...)
Note that you can still pass this into get_object_or_404 like so:
get_object_or_404(queryset, pk=<your_stores_id>)
Hope this helps.
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.
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.)