I am trying to update search vector field using post_save signal. Through "Admin.py", It is working perfectly, but through "Form page" , the searchVector field or any other field is not getting updated. In form page, I have many to many field - "Tag" that I save through "form.save_m2m" method Please review my code and suggest .. https://dpaste.org/ujPi Thanks in advance
#models.py
class JobPostManager(models.Manager):
def search(self, search_text):
search_vectors = (
SearchVector(
'job_title', weight='A', config='english'
)
)
search_query = SearchQuery(
search_text, config='english'
)
search_rank = SearchRank(search_vectors, search_query)
trigram_similarity = TrigramSimilarity(
'job_title', search_text
)
qs = (
self.get_queryset()
.filter(search_vector=search_query)
.annotate(rank=search_rank + trigram_similarity)
.order_by('-rank')
)
return qs
class JobPost(models.Model):
job_title = models.CharField(max_length=100, db_index=True)
job_description = models.TextField()
tags = TaggableManager()
author = models.ForeignKey(User, on_delete=models.CASCADE, db_index=True)
company_name = models.CharField(max_length=100,blank=True,null=True, db_index=True)
objects = JobPostManager()
def __str__(self):
return self.job_title
def get_absolute_url(self):
return reverse('job_post_detail', kwargs={'slug': self.slug, 'pk':self.pk})
####################################################################################
####################################################################################
# views.py
class JobPostCreateView(LoginRequiredMixin, CreateView):
model = JobPost
fields = ['job_title','job_description','tags']
widgets = {
'tags' : forms.TextInput(attrs={'data-role':'tagsinput'}),
}
def get_form(self):
form = super().get_form()
form.fields['tags'].widget = forms.TextInput(attrs={'value': 'all'})
return form
def form_valid(self, form):
print("views - form valid - run ")
newpost = form.save(commit=False)
form.instance.author = self.request.user
form.instance.company_name = self.request.user.company_name
print("form---------------------------")
print(form.instance.author)
print(form.instance.job_title)
print(form.instance.company_name)
print("form end---------------------------")
newpost.save()
print('newpost')
print('--------------------------------',newpost)
print('newpost',newpost.author)
print('newpost',newpost.job_title)
print('Search VECTOR')
print('-------------------')
print(newpost.search_vector)
print('Search VECTOR')
form.save_m2m()
print('save_m2m-----------------------')
print('form-------------',form)
print('form end-------------------')
return super().form_valid(form)
###########################################################################
###########################################################################
from django.db.models.signals import post_save
from django.dispatch import receiver
from .models import JobPost
@receiver(post_save, sender=JobPost)
def create_profile(sender, instance, created, **kwargs):
if created:
# JobPost.objects.update(search_vector="instance")
print("i am inside --------------signal")
print(instance.job_title)
print(instance.job_description)
print(instance.tags)
print(instance.company_name)
print(instance.author)
print('Search VECTOR')
print('-------------------')
print(instance.search_vector)
print('Search VECTOR')
print("i am inside signal")
print("i am inside signal")
print("Signal end --------------------------------------")
print("run filter --------------------------------------")
p = JobPost.objects.filter(pk=instance.pk)
print(p)
p2 = JobPost.objects.get(pk=instance.pk).search_vector
print(p2)
print(JobPost.objects.filter(pk=instance.pk)[0].job_title)
print("run filter end--------------------------------------")
p.update(search_vector="instance")
JobPost.objects.filter(pk=instance.pk).update(job_title="Java developer")
print('Search VECTOR after update ')
print('-------------------')
print(instance.search_vector)
print('Search VECTOR')
###########################################################################
############################################################################
## Form HTML
<div class="row">
<div class="col-25">
<label class="fr" for="{{ form.job_title.id_for_label }}">Job title *:</label>
</div>
<div class="col-75">
{{ form.job_title }}
</div>
<div class="invalid-tooltip">
{{ form.job_title.errors }}
</div>
</div>
<div class="row">
<div class="col-25">
<label class="fr" for="{{ form.job_description.id_for_label }}">Job description *:</label>
</div>
<div class="col-75">
{{ form.job_description }}
</div>
<div class="invalid-tooltip">
{{ form.job_description.errors }}
</div>
</div>
#############################################################
Just to be absolutely sure, everything is saving perfectly but your signals are not being called, right?
This is solvable by adding 2 lines of code inside the apps.py
file (which should live at the same depth as your models.py
file). For example, if the application (or the folder containing models.py
) is called "jobs" and create_profile
is inside the file named signals.py
you should modify the apps.py
file like this:
from django.apps import AppConfig
from django.utils.translation import ugettext_lazy as _
class JobsConfig(AppConfig):
name = 'jobs'
verbose_name = _('Jobs')
# THE FOLLOWING SHOULD BE ADDED.
def ready(self):
from . import signals # noqa
Django only finds some files "magically" when it expects their names (like models.py
, management/commands
, etc) but not the signals.py
(or the name of the file where create_profile
exists). The fix in the snippet is not "pretty", but you should do the import inside the ready
method as django might call signals.py
twice if it is imported somewhere else.
PD. If this works for you, please let me know if you get a "Joined field references are not permitted in this query" error when saving (the reason I found this question) is because Django-Taggit + SearchVector inside the same model raises this error