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.)
Related
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 am building a wiki and need to save every revision made for each wikipage. This means that i need a new revision tabel for every wikipage created.
When presenting each wikipage template with DetailView i need to access Wikipage.title, the latest revision and its Revision.content, Revision.author, Revision.last_edit and Revision.comment. I have been able to access the title, by setting "model=Wikipage" and revision, by setting "model=Revision" but not both at the same time.
models.py
class Wikipage(models.Model):
title = models.CharField(max_length=100)
date_created = models.DateTimeField('Created', auto_now_add=True)
def __str__(self):
return self.title
class Meta:
verbose_name_plural = "Wikipages"
class Revision(models.Model):
wikipage = models.ForeignKey(Wikipage, null=True,
on_delete=models.CASCADE, related_name='revision')
content = models.TextField('Content')
author = models.ForeignKey(User, null=True,
on_delete=models.SET_NULL)
last_edit = models.DateTimeField('Last edit', auto_now=True)
comment = models.TextField('Comment', blank=True)
class Meta:
verbose_name = 'Revision'
verbose_name_plural = 'Revisions'
ordering = ['-last_edit']
get_latest_by = ['last_edit']
def __str__(self):
return self.content
I wanted to use the DetailView and CreateView that comes with django, but I have not succeeded in accessing specific data from both tables.
I have gotten the ListView to work correctly, but that only needs the title from Wikipage, and nothing from Revision.
You can access the latest revision for a wikipage via wikipage.revision.latest(), since you correctly defined get_latest_by on the Revision model. You can do that directly in the template:
{% with wikipage.revision.latest as revision %}
{{ revision.last_edit }}
{{ revision.comment }}
{% endwith %}
On the DetailView you can access all the revisions using wikipage.revision where wikipage is the object of the DetailView and you could query the revisions to get the latest one.
I would recommend also this change
wikipage = models.ForeignKey(Wikipage, null=True, on_delete=models.CASCADE, related_name='revision')
to be
wikipage = models.ForeignKey(Wikipage, null=True, on_delete=models.CASCADE, related_name='revisions')
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.
Hi Guys I am trying to figure this out but not having any luck.
So I am showing my events in the homepage which shows how many seats are available, once the user has made a booking I would like to minus that from the amount showing on the homepage.
But I am already stuck at adding all the values up for that event in the booking model to minus from that amount.
So this is what I have
model for events
class Events(models.Model):
ACTIVE = (('d', "Deactivated"), ('e', "Expired"), ('a', "Active"), ('b', "Drafts"),)
ALCOHOL = (('0','No bring own alcohol'),('1','There will be complimentary wine pairing'))
user = models.ForeignKey(User, on_delete=models.CASCADE)
title = models.CharField(max_length=50, blank=True, default='')
date = models.DateField()
time = models.TimeField()
price = models.CharField(max_length=240, blank=True, default='')
seats = models.IntegerField()
created_date = models.DateTimeField(auto_now_add=True)
modified_date = models.DateTimeField(auto_now=True)
model for bookings
class Bookings(models.Model):
OPTIONS_STATUS = (('y', "Yes"), ('n', "No"), ('p', "Pending"),)
user = models.ForeignKey(User, on_delete=models.CASCADE)
event = models.ForeignKey(Events, on_delete=models.CASCADE)
eventdate = models.DateField()
event_amount = models.CharField(max_length=50, blank=True, default='')
guests = models.IntegerField()
bookingstatus = models.CharField(max_length=50, default='p', blank=True, choices=OPTIONS_STATUS)
created_date = models.DateTimeField(auto_now_add=True)
modified_date = models.DateTimeField(auto_now=True)
my homepage how I get my data into a loop form the view
today = datetime.now().strftime('%Y-%m-%d')
events_list_data = Events.objects.filter(active='a').filter(Q(date__gte=today)|Q(date=today)).order_by('date')
How I am trying to show this in my template
{% for event_list in events_list_data %}
SHOW WHAT EVER DATA I AM SHOWING NOT NEEDED FOR HELP ON
{% for bookingguests in
event_list.bookings_set.all %}
{{ bookingguests.guests }}
{% endfor %}
Seats Left
{% endif %}
Generally, purpose of templates is not to implement logic. All the logic should go into your views. I would recommend you to do that in your views and either store it in a dict or a list and send it to front-end.
Once the user made a booking, if you want to modify the value on the HTML without reloading, you may need to use jQuery/javascript. Otherwise, if you are fine with reloading the page by rendering it again with calculations from the backend.
By using jQuery:
$("#balance-id").html(logic to get the balance)
By Calculating in views:
from django.db.models import Sum
user_balance = user.balance - events_data.aggregate(Sum('price'))
return render('path/to/template', {'events_list': events_list_object, 'user_balance':user_balance})
In the template:
{{user_balance}} seats left
Let me know in case of any questions.
Note: If you want to write some logic into your templates, use template tags. It can help you with whatever it can with its limited functionality.
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.