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.
Related
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')
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', ...]
I would like to check the value of a field (lightStatusA) when a new record is saved into my Django database. I feel like iv'e read the docs 10 times and still can't grasp how to get this. Here is my current models.py code:
from django.db import models
from accounts.models import Customer
from django.conf import settings
from django.contrib.auth import get_user_model
from django.db.models.signals import post_save
class Data(models.Model):
author = models.ForeignKey(get_user_model(),on_delete=models.CASCADE,)
tempData= models.CharField(max_length=50,blank=True,)
humidData= models.CharField(max_length=50,blank=True,)
lightStatusA= models.BooleanField(default=True,)
dateTime = models.DateTimeField(auto_now_add=True)
def __str__(self):
return str(self.author)
def check_light_status(sender, **kwargs):
if kwargs['created']: #make sure its a new record
#need logic to grab instance.lightStatusA and check it's value
post_save.connect(check_light_status, sender = Data)
Is there some way of passing this value as an argument to the signal?
The check_light_status function can accept an instance parameter.
From the docs:
instance
The actual instance being saved.
Update: You said this:
instance returns the author of the post.
I am going to use my powers of deduction to guess that you tried print(instance) and saw the author. Look at your __str__ implementation.
def __str__(self):
return str(self.author)
I'd say you sabotaged yourself a bit there ;)
Ahh ok got it:
def check_light_status(sender, instance, **kwargs):
if kwargs['created']: #make sure its a new record
print(instance.lightStatusA)
This prints the the field I need to run some logic against.
This is a curious one for Django+Algolia. I'm using the Algolia specific Django package:
$ pip install algoliasearch-django
I have the following model schema:
import os
import datetime
from channels import Group
from django.db import models
from django.conf import settings
from django.utils.six import python_2_unicode_compatible
from django.utils.translation import ugettext_lazy as _
from django.core.files.storage import FileSystemStorage
from django.contrib.humanize.templatetags.humanize import naturaltime
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
SITE_UPLOAD_LOC = FileSystemStorage(location=os.path.join(BASE_DIR, 'uploads/site'))
USER_UPLOAD_LOC = FileSystemStorage(location=os.path.join(BASE_DIR, 'uploads/user'))
#python_2_unicode_compatible
class Room(models.Model):
"""
This model class sets up the room that people can chat within - much like a forum topic.
"""
title = models.CharField(max_length=255)
staff = models.BooleanField(default=False)
slug = models.SlugField(max_length=250, default='')
banner = models.ImageField(storage=USER_UPLOAD_LOC, null=True, blank=True)
def last_activity(self):
"""
For date and time values show how many seconds, minutes, or hours ago a message
was sent (i.e., persised to the database) compared to current timestamp return representing string.
"""
last_persisted_message = Messages.objects.filter(where=self.slug).order_by('-sent_at').first()
if last_persisted_message is not None:
# First we can store "last persisted message" time in ISO format (could be useful for sitemap.xml generation; SEO tasks etc)
last_persisted_message_iso = last_persisted_message.sent_at.isoformat()
# Use the natural time package form contrib.humanize to convert our datetime to a string.
last_persisted_message = naturaltime(last_persisted_message.sent_at)
return last_persisted_message
else:
return "No activity to report"
Which is indexed as:
from algoliasearch_django import AlgoliaIndex
class RoomIndex(AlgoliaIndex):
fields = ('title', 'last_activity')
settings = {
'searchableAttributes': ['title'],
'attributesForFaceting': ['title', 'last_activity'],
'hitsPerPage': 15,
}
index_name = 'Room Index'
Essentially, to bring the 'last_activity' value to the front end it needs to pass through the index which is updated as far as I can tell with running:
$ python manage.py algolia_reindex
However, the last activity comes from the last time (converted to humanized django naturaltime, e.g. '3 days ago' etc etc) a Message was sent within a websocket connection - persisted to the database. All of this functionality works except that to update I need to run the algolia_reindex command.
Rather unsure as to how this could potentially be done a little more simultaneously...?
Ok, so this one was slightly more complex as I was using websockets. When a message is sent and persisted to the database we can also do the following within the relevant "consumer" method (really, consumers.py is the websocket equivalent of the views.py file so I should have known this!)
The following lines of code worked:
client = algoliasearch.Client(settings.ALGOLIA['APPLICATION_ID'], settings.ALGOLIA['API_KEY'])
index = client.init_index('Room Index')
res = index.partial_update_objects([{"last_activity": naturaltime(datetime.datetime.now()), "objectID": your_object_id]}])
The trick for anyone listening would be to designate the your_object_id from what value of the message is passed in from the client side to the consumer.
Don't forget to add:
import datetime
from django.conf import settings
from django.contrib.humanize.templatetags.humanize import naturaltime
At the top of the consumers.py file!
I also found the python specific incremental updates documentation from Algolia extremely useful:
I https://www.algolia.com/doc/tutorials/indexing/synchronization/incremental-updates/
To render the updated time in "real time" - use which ever front-end tool floats your boat, I used jQuery but Vue.js or React.js would work equally well.
I am working on some Django project (first time) and after lot of searching i have no clue how to proper update object attribute after creation. I have sucha models.py
from django.db import models
import os
# Create your models here.
class Place(models.Model):
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# Add templates folder for dynamic usage, os independent
TEMPLATE_DIR = os.path.join(BASE_DIR, "templates/places")
name = models.CharField(max_length=100, unique=True)
display_name = models.CharField(max_length=100)
floor = models.DecimalField(max_digits=3, decimal_places=0)
template = models.FilePathField(path=TEMPLATE_DIR, match=".*html")
url = models.URLField(unique=True)
# Display name of object in object list view
def __str__(self):
return self.name
Question is how to update url attribute after object creation of url to this particular object, it should be something like (base url + object_id i know object_id is created after object creation) but after searching documentation i dont have ideas how to do this properly.
I tried get_absolute_path but with no success.
Maybe some kind post_save method override ?
One option would be to override the model save method and detect if the model instance is being added or updated and update the url field accordingly:
class Place(models.Model):
# ...
def save(self, *args, **kwargs):
is_adding = self._state.adding
super(Place, self).save(self, *args, **kwargs)
if is_adding:
url = os.path.join(self.TEMPLATE_DIR, str(self.pk))
super(Place, self).save(self, *args, **kwargs)
However, you needn't actually store the url as you can derive the value from other model fields when required. Hence, you can delete the url field and create a url method instead:
class Place(models.Model):
# ...
#property
def url(self):
return os.path.join(self.TEMPLATE_DIR, str(self.pk))
Here, the #property decoration here allows you to access place.url as if it was a model field.
This might be a good time to introduce something like Django celery into you're project and run this task async after creation.
You could have a task in a file like this:
# I'm making assumptions on project architecture..
from app.places import Place
from app.places.utils import PLACE_BASE_URL
#shared_task
def task_update_place_url(place_id):
"""
Simple method to update Place url after creation.
"""
place = Place.objects.get(pk=place_id)
place.url = PLACE_BASE_URL + place_id
place.save()
Then inside of your view when you create your Place you can do this:
import json
from django.http.response import HttpResponse
from app.places.models import Place
from app.places.tasks import task_update_place_url
def create_place(request):
"""
Creates a new Place and update url in task
"""
data = json.loads(request)
place = Place.objects.create(**data)
task_update_place_url.delay(place.id)
return HttpResponse("Finished")