Django: DateTime not good when saved on my database - django

It seems stupid but i have hard time since hours and hours about saving my dateTime on db. I'm pretty new in Python and it's not everyday that i'm manipulating datetime.
I have one hour of difference when i'm saving my value. So 18h is now 17h (sorry for my english)
My models is like this:
class Event(models.Model):
title = models.CharField(max_length=245)
description = models.TextField(max_length=750, null=True, blank=True)
start = models.DateTimeField()
end = models.DateTimeField()
created_at = models.DateTimeField(editable=False)
updated_at = models.DateTimeField(editable=False)
slug = AutoSlugField(populate_from='title', unique=True, editable=False)
nb_participant = models.PositiveSmallIntegerField(default=1)
price = models.PositiveSmallIntegerField(default=0)
user = models.ForeignKey(User, editable=False, related_name='author')
address = models.ForeignKey('Address', editable=False, related_name='events')
participants = models.ManyToManyField(User, related_name='participants', blank=True)
class Meta:
db_table = 'event'
def save(self, *args, **kwargs):
if not self.pk:
self.created_at = timezone.localtime(timezone.now())
print self.created_at
self.updated_at = timezone.localtime(timezone.now())
super(Event, self).save(*args, **kwargs)
As you see i have 4 fields with datetime. 2 are actually save automatically save when the model is created.
I resolved the probleme by using timezone.localtime(timezone.now()) instead of timezone.now(). I find that there enter link description here at the bottom of the page. But they said to use timezone.now() in most case. So i don't know why i have this one hour difference.
I have two other fields that are send from my angular frontend to my API( using django rest framework)
I put a screenshot. The first object i send by angular.As you seen the date is well formatted.
The second object is the response from my API and i have lost one hour (so the GMT +1)
Why ? I'm totally block so if someone has a solution, i'll be very happy :)
My settings.py:
LANGUAGE_CODE = 'fr-fr'
TIME_ZONE = 'Europe/Paris'
USE_L10N = True
USE_TZ = True
Thanks.

In settings file try with USE_TZ=False, and use normal datetime.now().

Related

django.core.exceptions.FieldError: Cannot resolve keyword 'date' into field. Join on 'date' not permitted

# Here is my models
This is my CustmerBuySell model DB designed.
class CustomerBuySell(models.Model):
customer = models.ForeignKey(CustomerAdd, on_delete=models.CASCADE)
customer_buy_sell_debit = models.DecimalField(max_digits=10, decimal_places=2, default=0.00)
customer_buy_sell_credit = models.DecimalField(max_digits=10, decimal_places=2, default=0.00)
description = models.CharField(max_length=250, blank=True)
date = models.DateField()
sms = models.BooleanField(default=False)
picture = models.ImageField(upload_to='customer_buy_sell_pics', default='images.png')
created_at = models.DateTimeField(auto_now_add=True, blank=True, null=True)
updated_at = models.DateTimeField(auto_now=True, blank=True, null=True)
def __str__(self):
return self.customer.customer_name
class Meta:
verbose_name = "Customer BuySell"
verbose_name_plural = "Customer BuySell"
# Here, is my View.
This is the class-based APIView, which I have used. And try to use the aggregate query in this view.
class DailyCustomerBuySellAPIView(APIView):
def get(self, request):
customer_buy_sell = CustomerBuySell.objects.extra(select={'day': 'date( date )'}).values('day').order_by(
'date__date').annotate(available=Count('date__date'))
serializer = CustomerBuySellSerializer(customer_buy_sell, many=True)
return Response({"customer_buy_sell": serializer.data})
# And, finally here are my Serializers
I have no idea what's the problem! Please help me.
class CustomerBuySellSerializer(serializers.ModelSerializer):
# customer = CustomerAddSerializer()
class Meta:
model = CustomerBuySell
fields = '__all__'
def to_representation(self, instance):
representation = super(CustomerBuySellSerializer, self).to_representation(instance)
if instance.customer is not None:
customer_name = instance.customer.customer_name
previous_due = instance.customer.previous_due
representation['custo`enter code here`mer_name'] = customer_name
representation['previous_due'] = previous_due
return representation
There are many problems with your approach. Let me mention each of them one by one:
First of all remove date__date from your APIVIew
Before:
customer_buy_sell = CustomerBuySell.objects.extra(select={'day': 'date( date )'}).values('day').order_by(
'date__date').annotate(available=Count('date__date'))
Instead, write it as:
from django.db.models.functions import Extract
customer_buy_sell = CustomerBuySell.objects.annotate(day=Extract('date','day')).values('day').order_by('day')
if you need a count of the days then you can try
customer_buy_sell_count = customer_buy_sell.count()
Another thing that you are doing wrong is you pass a dict to serializer as you are already using values that return a dictionary of days and not object of CustomerBuySell so you do not need to pass it to serializer otherwise you have to do it according to your need.
In CustomerBuySellSerializer you are using a model serializer with __all__ while you are passing an extra fields day that is not part of it.
So in short there are so many syntax issues with your Django and Django Rest Framework.Great way to fix such issues is to set with an experience programmer so that he can improve the flow of the code. Later on you can focus on logic.
I suppose it is just a typo: Change date__date to date

Overwriting Datetime is not working in Postgresql in Django

So what I need to do is to change few rows in a model DateTime field to 40 days in the past, with Django using a PostgreSQL database. Where I choose all products with an even ID and change the date_uploaded value.
This is what I am currently doing...
from django.core.management.base import BaseCommand
from store.models import Product
import datetime
class Command(BaseCommand):
def handle(self, *args, **options):
all_products = Product.objects.all()
for product in all_products:
if product.pk % 2 == 0:
product.date_uploaded = product.date_uploaded - datetime.timedelta(40,2,0,0)
product.save()
print(product.date_uploaded)
And for some reason when I try to save the product it works with no errors but the DateTime value is not changed. Is there anything wrong with what I am doing?
this is my models.py
class Product(models.Model):
image1 = models.ImageField(upload_to="product_images", default="https://eblossomsl.s3-us-west-2.amazonaws.com/logo.png")
image2 = models.ImageField(upload_to="product_images", blank=True)
image3 = models.ImageField(upload_to="product_images", blank=True)
image4 = models.ImageField(upload_to="product_images", blank=True)
name = models.CharField(max_length=100, unique=True)
category = models.CharField(choices=CATEGORY, max_length=20, default="HRT", db_index=True)
price = models.PositiveIntegerField()
search_query = models.TextField(blank=True, null=True)
date_uploaded = models.DateTimeField(auto_now=timezone.now())
quantity_bought = models.PositiveIntegerField(default=0)
Any help would be greatly appreciated since I am not sure what I am doing wrong.
The problem is in auto_now argument passed into DateTimeField, this argument is responsible for changing the value of the field to the current datetime each time .save() is called on the object, i.e. every time you are running your script it sets it to current datetime and your changes are ignored. What you really need is auto_now_add which sets the value only once at the object creation.
date_uploaded = models.DateTimeField(auto_now_add=timezone.now())
Run makemigrations, apply them and run your script again.

Django filter: different results in filtering between SQLite and PostgreSQL

I have a relatively simple query running on a database table; the filter checks the value of 2 date fields and returns a queryset. The fields checked are authored_report_received and subbed_complete. If authored_report_received has a date set AND subbed_complete has no date set, then a result will be returned.
If both these fields have a date set then no results are returned.
(A simple calculation for the 'days outstanding' between any result returned and the current date is then made.)
This works absolutely fine running locally on a SQLite database but when I upload to heroku to be used with a PostgreSQL database, the filter does not seem to work in that it seems to ignore any date value in the subbed_complete field. I do not understand why not. Is there a difference between the way SQLite and PostgreSQL handles the filters? I can't find any docs which indicate this.
# views.py
class EpgReportSubeditListView(LoginRequiredMixin, EpgUserPassesTestMixin, ListView):
"""EPG-only: create a list view of reports currently being subedited
"""
model = Report
template_name = 'tracker/epg_report_subedit.html'
context_object_name = 'report_subedit'
ordering = ['subeditor']
def get_queryset(self):
today = datetime.now().date()
out = []
for obj in (self.model.objects.filter(subbed_complete__isnull=True) and self.model.objects.filter(authored_report_received__isnull=False)):
setattr(obj, 'days_diff', (today - obj.authored_report_received).days)
out.append(obj)
return out
# models.py
class Report(models.Model):
"""Define fields for Report object (representing a case report)
"""
case = models.ForeignKey(Case, on_delete=models.CASCADE, related_name='reports')
editor = models.ForeignKey(User, on_delete=False,
limit_choices_to={'groups__name': 'editors'},
related_name='editor', null=True)
# editing workflow info
authored_report_received = models.DateField(null=True, blank=True)
subbed_complete = models.DateField(null=True, blank=True)
subeditor = models.ForeignKey(User, on_delete=False,
limit_choices_to={'groups__name': 'subeditors'},
related_name='subeditor', null=True, blank=True)
sent_to_editor = models.DateField(null=True, blank=True)
edited = models.DateField(null=True, blank=True)
reporter_queries = models.CharField(max_length=3,
choices=Binary_Choices,
default="n")
sent_to_deskeditor = models.DateField(null=True, blank=True)
taken_by_deskeditor = models.DateField(null=True, blank=True)
deskeditor = models.ForeignKey(User, on_delete=False,
limit_choices_to={'groups__name': 'deskeditors'},
related_name='deskeditor', null=True, blank=True)
deskedit_complete = models.DateField(null=True, blank=True)
sent_to_counsel = models.DateField(null=True, blank=True)
received_from_counsel = models.DateField(null=True, blank=True)
date_editor_publish_approve = models.DateField(null=True, blank=True)
def get_absolute_url(self):
return reverse("epg_home")
def __str__(self):
return f'{self.case} | f: {self.filename}'
Sqlite and PostgreSQL handle dates differently. subbed_complete is a models.DateField field, but sqlite3:
does not have a storage class set aside for storing dates and/or
times. Instead, the built-in Date And Time Functions of SQLite are
capable of storing dates and times as TEXT, REAL, or INTEGER values:
Applications can chose to store dates and times in any of these formats and freely convert between formats using the built-in date and time functions.
So you should test your code and adjust the query in an another environment with postgresql.
https://www.sqlite.org/datatype3.html

How to Model a TimeField in Django?

I have modeled a class called ConversationHistory. Whenever an instance is created I wish to set the current date and current time.
class ConversationHistory(models.Model):
contact_date = models.DateField(_(u"Conversation Date"), blank=True)
contact_time = models.DateTimeField(_(u"Conversation Time"), blank=True)
def __init__(self, *args, **kwargs):
super(ConversationHistory, self).__init__(*args, **kwargs)
self.contact_date = datetime.datetime.now()
self.contact_time = datetime.datetime.now()
The idea is that the user can later still adjust the date and time as two different fields.
I am now a bit lost how to make the time field only to show and accept time, rather than date and time. I recon it is not possible to have a time field without datetime, but then how would I show only the time in the form?
If you want only time, TimeField is what you need:
class ConversationHistory(models.Model):
contact_date = models.DateField(_(u"Conversation Date"), blank=True)
contact_time = models.TimeField(_(u"Conversation Time"), blank=True)
You can take advantage of the auto_now_add option:
class TimeField([auto_now=False, auto_now_add=False, **options])
A time, represented in Python by a datetime.time instance. Accepts the
same auto-population options as DateField.
If you use the auto_now_add, it will automatically set the field to now when the object is first created.
class ConversationHistory(models.Model):
contact_date = models.DateField(_(u"Conversation Date"), auto_now_add=True, blank=True)
contact_time = models.TimeField(_(u"Conversation Time"), auto_now_add=True, blank=True)

Django .count() on ManyToMany has become very slow

I have a Django project that consists of a scraper of our inventory, run on the server as a cronjob every few hours, and the Django Admin page - which we use to view / access all items.
We have about 30 items that are indexed.
So each 'Scraping Operation' consists of about 30 individual 'Search Operations' each of which get around 500 results per run.
Now, this description is a bit confusing, so I've included the models below.
class ScrapingOperation(models.Model):
date_started = models.DateTimeField(default=timezone.now, editable=True)
date_completed = models.DateTimeField(blank=True, null=True)
completed = models.BooleanField(default=False)
round = models.IntegerField(default=-1)
trusted = models.BooleanField(default=True)
class Search(models.Model):
item = models.ForeignKey(Item, on_delete=models.CASCADE)
date_started = models.DateTimeField(default=timezone.now, editable=True)
date_completed = models.DateTimeField(blank=True, null=True)
completed = models.BooleanField(default=False)
round = models.IntegerField(default=1)
scraping_operation = models.ForeignKey(ScrapingOperation, on_delete=models.CASCADE, related_name='searches')
trusted = models.BooleanField(default=True)
def total_ads(self):
return self.ads.count()
class Ad(models.Model):
item = models.ForeignKey(Item, on_delete=models.CASCADE, related_name='ads')
title = models.CharField(max_length=500)
price = models.DecimalField(max_digits=8, decimal_places=2, null=True)
first_seen = models.DateTimeField(default=timezone.now, editable=True)
last_seen = models.DateTimeField(default=timezone.now, editable=True)
def __str__(self):
return self.title
Now here is the problem we've run into.
On the admin pages for both the Search model and the SeachOperation model we would like to see the amount of ads scraped for that particular object (represented as a number) This works fine four our seachers, but our implementation for the SearchOperation has run into problems
This is the code that we use:
class ScrapingOperationAdmin(admin.ModelAdmin):
list_display = ['id', 'completed', 'trusted', 'date_started', 'date_completed', 'number_of_ads']
list_filter = ('completed', 'trusted')
view_on_site = False
inlines = [
SearchInlineAdmin,
]
def number_of_ads(self, instance):
total_ads = 0
for search in instance.searches.all():
total_ads += search.ads.count()
return total_ads
The problem that we have run into is this: The code works and provides the correct number, however, after +/- 10 ScrapingOperation we noticed that the site started to slow done when loading the page. We are now up to 60 ScrapingOperations and when we click the ScrapingOperations page in the Django admin it takes almost a minute to load.
Is there a more efficient way to do this? We thought about saving the total number of ads to the model itself, but it seems wasteful to dedicate a field to information that should be accessible with a simple .count() call. Yet our query is evidently so inefficient that the entire site locks down for almost a minute when it is executed. Does anyone have an idea of what we are doing wrong?
Based on the comments below I am currently working on the following solution:
def number_of_ads(self, instance):
total_ads = 0
searches = Search.objects.filter(scraping_operation=instance).annotate(Count('ads'))
for search in searches:
total_ads += search.ads__count
return total_ads
Use an annotation when getting the queryset
from django.db.models import Count
class ScrapingOperationAdmin(admin.ModelAdmin):
...
def get_queryset(self, request):
qs = super().get_queryset(request)
qs.annotate(number_of_ads=Count('searches__ads')
return qs