Skip to content
Advertisement

Update model field ( SearchVector ) using signals.py

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>
#############################################################

Advertisement

Answer

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

User contributions licensed under: CC BY-SA
8 People found this is helpful
Advertisement