Using Django-modeltranslation in combination with PostgreSQL SearchVector - python

I'm using django-modeltranslation to translate model fields. And suppose I have the following model (where the name is translated in the DB):
class Book(models.Model):
name = models.CharField(max_length=90)
Then, in a DRF view, I have an endpoint that takes a query text and searches through the book names using this code:
from django.contrib.postgres.search import SearchVector, SearchQuery, SearchRank
class BookView(APIView):
def get(self, request):
q = request.get('q')
vector = SearchVector('name') # this is where the issue is
query = SearchQuery(q)
matches = Book.objects.annotate(rank=SearchRank(vector, query))\
.filter(rank__gt=0.1)\
.order_by('-rank')
# etc.
This works great when I was working with English only. But now I added a new language, and all aspects of the localisation are working fine, except this search. It's looking at the name_en field values only.
If the target language is German for example, and I explicitly change the following line from:
vector = SearchVector('name')
to:
vector = SearchVector('name_de')
Then the search works over the correct field. Is there a way to pass in the correct field to SearchVector?

IIUC, you can just use get_language():
from django.utils.translation import get_language
from django.contrib.postgres.search import SearchVector, SearchQuery, SearchRank
class BookView(APIView):
def get(self, request):
q = request.get('q')
vector = SearchVector(f'name_{get_language()}')
query = SearchQuery(q)
matches = Book.objects.annotate(rank=SearchRank(vector, query))\
.filter(rank__gt=0.1)\
.order_by('-rank')

Related

Django Python With Gspread: 'choices' must be an iterable containing (actual value, human readable name) tuples

I am trying to do something that I have never seen done before with django, I am trying to make a model field(path_choices) that shows all of the unique path_names from my google sheet in a choice box so that the user can select one of them. However when I tried to make my choices CharField I am getting the error:
ERRORS:
dashboard.Robot.path_choices: (fields.E005) 'choices' must be an iterable containing (actual value, human readable name) tuples.
Right now the google sheet that I am trying to pull from with gspread only has two path-names, so if anybody has any idea on what is causing this problem or what I can do better with this, the help would be appreciated!
My Code (UPDATED CODE):
from django.db import models
class Robot(models.Model):
name = models.CharField(max_length=100)
status_choices = [('driving', 'driving'), ('waiting', 'waiting'), ('stuck', 'stuck')]
status = models.CharField(choices=status_choices, max_length=7, default='waiting')
path_choices = models.CharField(max_length=255)
My Form:
from django import forms
from django import forms
from .models import Robot
import gspread
from oauth2client.service_account import ServiceAccountCredentials
class RobotForm(forms.ModelForm):
def _generate_choices():
scope = ["REDACTED",'REDACTED',"REDACTED","REDACTED"]
creds = ServiceAccountCredentials.from_json_keyfile_name("dashboard/Files/creds.json", scope)
client = gspread.authorize(creds)
sheet = client.open("tutorial").sheet1
path_name_fetch = sheet.col_values(1)
path_names = []
temp_list = []
path_options = []
for i in path_name_fetch:
if i not in path_names:
path_names.append(i)
for path_name_options in path_names:
temp_list.append(f'{path_name_options}')
temp_list.append(f'{path_name_options}')
path_options.append(tuple(temp_list))
path_choices = forms.ChoiceField(choices=_generate_choices())
class Meta:
model = Robot
fields = {'path_choices'}
What you're trying to do may not be in line with the intended use of Choices. Whenever the possibilities of a Choice change at the Model level, new migrations must be made.
Your implementation of Choice for Robot.status is static and in line with the example in the Django documentation.
If instead you wanted to use a dynamic Choice for your path_choices that is retrieved from Google Sheets, I would recommend doing this in the ModelForm using a ChoiceField.
According to the documentation, the available choices can come from a callable, which would be your path_options wrapped in a function. path_options should then become a CharField without choices, since you manage those in the submission, rather than at the model level.
Models.py
class Robot(models.Model):
...
path_choices = models.CharField(max_length=255)
ModelForms.py
class RobotForm(ModelForm):
def _generate_choices():
# Query GSpread
choices = [('choice','choice'), ...]
return choices
path_choices = forms.ChoiceField(choices=_generate_choices())
class Meta:
model = Robot
fields = ['path_choices', ...]

Django 2.0 dynamically generate urlpatterns

I wrote this code that dynamically generates url patterns from the database. These urls have only one level path: domain.com/something.
someapp/models.py
class SomeModel(models.Model):
pattern = models.CharField(max_length=50)
name = models.CharField(max_length=50)
text = models.CharField(max_length=50)
someapp/apps.py
class SomeAppConfig(AppConfig):
name = 'someapp'
def ready(self):
from .models import SomeModel
from .urls import urlpatterns
from . import views
urls_in_db = SomeModel.objects.all()
for url_in_db in urls_in_db:
urlpatterns.append(path(url_in_db.pattern,
views.SpecialView.as_view(),
name=url_in_db.name)
someapp/views.py
class SpecialView(generic.TemplateView):
template_name = 'template/view_template.html'
model = SomeModel
def get_context_data(self, **kwargs):
context = super(SpecialView, self).get_context_data(**kwargs)
context['content'] = SomeModel.objects.get(pattern=self.request.path)
return context
Is this solution an anti-pattern? And, if so, why?
Thanks
Yes, your solution is an anti-pattern. Django supports parameters in URL patterns that get captured and become available in the corresponding view. Using these URL parameters, you can write and maintain a single URL pattern for every record of a certain type in your database.
Take a look at this example of URL parameters.
Finally, also note how your solution could potentially have very poor performance since you are potentially creating millions of URL patterns depending on the size of your database.

Returning extended fields in JSON

I have two tabels(Ingredient_Step and Ingredient) in on relation as you can see below:
Models.Py
class Ingredient_Step(models.Model):
ingredient = models.ForeignKey(Ingredient)
Step = models.ForeignKey(Step)
def __unicode__(self):
return u'{}'.format(self.Step)
class Ingredient(models.Model):
IngredientName = models.CharField(max_length=200,unique=True)
Picture = models.ImageField(upload_to='Ingredient')
def __unicode__(self):
return u'{}'.format(self.IngredientName)
In a function, i need serialize a JSON object from a query that returns from "Ingredient_step", but I need send the field "IngredientName", who comes from "Ingredient" table.
I try using "ingredient__IngredientName" but it fails.
Views.Py:
def IngredientByStep(request):
if request.is_ajax() and request.GET and 'id_Step' in request.GET:
if request.GET["id_Step"] != '':
IngStp = Ingredient_Step.objects.filter(Step =request.GET["id_Step"])
return JSONResponse(serializers.serialize('json', IngStp, fields=('pk','ingredient__IngredientName')))
How i can call extends field from a relation?
Thanks
This "feature" of Django (and many ORM's like SQLAlchemy) are called Lazy Loading, meaning data is only loaded from related models if you specifically ask for them. In this case, build your IngStp as a list of results, and make sure to access the property for each result before serializing.
Here's an example of how to do that: Django: Include related models in JSON string?

How to generate HASH for Django model

I am trying to generate unique HASH values for my Django models of 10 digit i have tried these methods but i am getting this error
return Database.Cursor.execute(self, query, params)
django.db.utils.IntegrityError: column hash_3 is not unique
Here what i have tried :
import os
import time
import hashlib
from os import path
from binascii import hexlify
from django.db import models
from django.contrib import admin
from django.core.files.storage import FileSystemStorage
#------------------------------------------------------------------------------
def _createHash():
"""This function generate 10 character long hash"""
hash = hashlib.sha1()
hash.update(str(time.time()))
return hash.hexdigest()[:-10]
class tags(models.Model):
""" This is the tag model """
seo_url1 = models.URLField()
seo_url2 = models.URLField()
seo_url3 = models.URLField()
tagDescription = models.TextField() # Tag Description
tag = models.CharField(max_length=200) # Tag name
tagSlug = models.CharField(max_length=400) # Extra info can be added to the existing tag using this field
updatedAt = models.DateTimeField(auto_now=True) # Time at which tag is updated
createdAt = models.DateTimeField(auto_now_add=True) # Time at which tag is created
hash_1 = models.CharField(max_length=10,default=_createHash(),unique=True)
hash_2 = models.CharField(max_length=10,default=_createHash(),unique=True)
hash_3 = models.CharField(max_length=10,default=_createHash(),unique=True)
I have also tried this method:
def _createHash():
"""This function generate 10 character long hash"""
return hexlify(os.urandom(5))
I have a script which inserts data into this model every time i run my script i got above mentioned error ..is there any other way of doing this..i want to store unique hash values into columns hash_1,hash_2,hash_3.
Don't call the _createHash() function in your field, but just pass the reference to the callable in your model, e.g.
hash_1 = models.CharField(max_length=10,default=_createHash,unique=True)
As Lennart Regebro mentioned in his answer, you'll get the same value for each time you start the server in your attempt.
The Django docs say this about it:
Field.default
The default value for the field. This can be a value or
a callable object. If callable it will be called every time a new
object is created.
_createHash() is called when you define the model, so you have the same default every time you create a new object.
You can look at creating the hash in the save() method of the model, that's probably the easiest.

App Engine model filtering with Django

hi i am using django app engine patch i have set up a simple model as follows
class Intake(db.Model):
intake=db.StringProperty(multiline=False, required=True)
##permerlink
def get_absolute_url(self):
return "/timekeeper/%s/" % self.intake
class Meta:
db_table = "Intake"
verbose_name_plural = "Intakes"
ordering = ['intake']
i am using the following views to check if some thing exist in data base and add to database
from ragendja.template import render_to_response
from django.http import HttpResponse, Http404
from google.appengine.ext import db
from timekeeper.forms import *
from timekeeper.models import *
def checkintake(request, key):
intake = Intake.all().filter('intake=',key).count()
if intake<1:
return HttpResponse('ok')
else:
return HttpResponse('Exist in database')
def addintake(request,key):
if Intake.all().filter('intake=',key).count()>1:
return HttpResponse('Item already Exist in Database')
else:
data = Intake(intake=cleaned_data[key])
data.put()
return HttpResponse('Ok')
i can add to database with no problem (when i do a Intake.all().count() it increases) but when i check if the key exist in the database by filtering i am getting a count of zero any one have any idea why i am not able to filter by keys ?
You need to insert a space between the field name and the operator in your filter arguments - eg, use .filter('intake =') instead of .filter('intake='). With an equality filter, you can also leave it out entirely, as in .filter('intake'). Without the space, the equals sign is taken to be part of the field name.

Categories