Django wipe datefield value from view - django

Bit of a random question but ill try my best to describe what im trying to do. I am building a app to manage a set of physical assets which get loaned out.
To return an asset the user visits /return/1/ which clears the name of the user, date borrowed, date returned etc
view.py
def returnlaptop(request, laptop_pk):
Laptops.objects.filter(pk=laptop_pk).update(laptop_status='In')
Laptops.objects.filter(pk=laptop_pk).update(user='')
Laptops.objects.filter(pk=laptop_pk).update(borrowed_date='')
Laptops.objects.filter(pk=laptop_pk).update(return_date='')
return HttpResponseRedirect('/')
This works well except for when i try and update the values in the models.datefield
[u"' ' value has an invalid date format. It must be in YYYY-MM-DD format."]
Is there anyway around this? or am I going about this the completely wrong way?
Cheers
Xcom

I'm not 100% sure but I think that hits the database 4 times...
The first issue is that update is meant for use on a queryset. You are filtering on the primary key so you are only getting 1 object back. Which means that you should use get instead like this
laptop = Laptops.objects.get(pk=laptop_pk)
and now you can use that to properly fetch the object from the database, modify it, and save it like so
laptop = Laptops.objects.get(pk=laptop_pk)
laptop.laptop_status = 'In'
laptop.user = ''
...
laptop.save()
which would only hit the database 1 time.
The final issue is that you are attempting to set a date to an empty string. That won't work because it is expecting a date object. One thing you can do is modify your model so that the dates can be blank and so that the database accepts null values.
class Laptops(models.Model):
...
borrowed_date = models.DateField(null=True, blank=True)
return_date = models.DateField(null=True, blank=True)
The other thing you can do is use the minimum date can be accessed with timezone.datetime.min

Related

How do I input current date and time in Django?

So I'm a beginner in Django, and recently came up with a question, regarding datetime.
So I'm trying to make a blog-like page. And among the input fields, including title and contents, I want a datetime field as well. However, there is an additional feature that I want to create, which is -- if the user clicks a checkbox right next to the datetime input field, the datetime will automatically change into the CURRENT date and time. So the input field is replaced with the current date and time.
I have no idea on how to create the feature.
I would very much appreciate your help :)
It will be better if you make this behavior to be set automatically to the time of creating the post for the first time, it will not be triggered if you modify the post:
created_at = models.DateTimeField(auto_now_add=True)
If you want to set it to the current time when you modify the post:
modified_at = models.DateTimeField(auto_now=True)

Django: Joining on fields other than IDs (Using a date field in one model to pull data from a second model)

I'm attempting to use Django to build a simple website. I have a set of blog posts that have a date field attached to indicate the day they were published. I have a table that contains a list of dates and temperatures. On each post, I would like to display the temperature on the day it was published.
The two models are as follows:
class Post(models.Model):
title = models.CharField(max_length=200)
text = models.TextField()
date = models.DateField()
class Temperature(models.Model):
date = models.DateField()
temperature = models.IntegerField()
I would like to be able to reference the temperature field from the second table using the date field from the first. Is this possible?
In SQL, this is a simple query. I would do the following:
Select temperature from Temperature t join Post p on t.date = p.date
I think I really have two questions:
Is it possible to brute force this, even if it's not best practice? I've googled a lot and tried using raw sql and objects.extra, but can't get them to do what I want. I'm also wary of relying on them for the long haul.
Since this seems to be a simple task, it seems likely that I'm overcomplicating it by having my models set up sub-optimally. Is there something I'm missing about how I should design my models? That is, what's the best practice for doing something like this? (I've successfully pulled the temperature into my blog post by using a foreign key in the Temperature model. But if I go that route, I don't see how I could easily make sure that my temperature dates get the correct foreign key assigned to them so that the temperature date maps to the correct post date.)
There will likely be better answers than this one, but I'll throw in my 2ยข anyway.
You could try a property inside the Post model that returns the temperature:
#property
def temperature(self):
try:
return Temperature.objects.values_list('temperature',flat=True).get(date=self.date)
except:
return None
(code not tested)
About your Models:
If you will be displaying the temperature in a Post list (a list of Posts with their temperatures), then maybe it will be simpler to code and a faster query to just add a temperature field to your Post model.
You can keep the Temperature model. Then:
Assuming you have the temperature data already present in you Temperature model at the time of Post instance creation, you can fill that new field in a custom save method.
If you get temperature data after Post creation, you cann fill in that new temperature field through a background job (maybe triggered by crontab or similar).
Sometimes database orthogonality (not repeating info in many tables) is not the best strategy. Just something to think about, depending on how often you will be querying the Post models and how simple you want to keep that query code.
I think this might be a basic approach to solve the problem
post_dates = Post.objects.all().values('date')
result_temprature = Temperature.objects.filter(date__in = post_dates).values('temperature')
Subqueries could be your friend here. Something like the following should work:
from django.db.models import OuterRef, Subquery
temps = Temperature.objects.filter(date=OuterRef('date'))
posts = Post.objects.annotate(temperature=Subquery(temps.values('temperature')[:1]))
for post in posts:
temperature = post.temperature
Then you can just iterate through posts and access the temperature off each post instance

Django ORM - LEFT JOIN with WHERE clause

I have made a previous post related to this problem here but because this is a related but new problem I thought it would be best to make another post for it.
I'm using Django 1.8
I have a User model and a UserAction model. A user has a type. UserAction has a time, which indicates how long the action took as well as a start_time which indicates when the action began. They look like this:
class User(models.Model):
user_type = models.IntegerField()
class UserAction:
user = models.ForeignKey(User)
time = models.IntegerField()
start_time = models.DateTimeField()
Now what I want to do is get all users of a given type and the sum of time of their actions, optionally filtered by the start_time.
What I am doing is something like this:
# stubbing in a start time to filter by
start_time = datetime.now() - datetime.timedelta(days=2)
# stubbing in a type
type = 2
# this gives me the users and the sum of the time of their actions, or 0 if no
# actions exist
q = User.objects.filter(user_type=type).values('id').annotate(total_time=Coalesce(Sum(useraction__time), 0)
# now I try to add the filter for start_time of the actions to be greater than or # equal to start_time
q = q.filter(useraction__start_time__gte=start_time)
Now what this does is of course is an INNER JOIN on UserAction, thus removing all the users without actions. What I really want to do is the equivalent of my LEFT JOIN with a WHERE clause, but for the life of me I can't find how to do that. I've looked at the docs, looked at the source but am not finding an answer. I'm (pretty) sure this is something that can be done, I'm just not seeing how. Could anyone point me in the right direction? Any help would be very much appreciated. Thanks much!
I'm having the same kind of problem as you. I haven't found any proper way of solving the problem yet, but I've found a few fixes.
One way would be looping through all the users:
q = User.objects.filter(user_type=type)
for (u in q):
u.time_sum = UserAction.filter(user=u, start_time__gte=start_time).aggregate(time_sum=Sum('time'))['time_sum']
This method does however a query at the database for each user. It might do the trick if you don't have many users, but might get very time-consuming if you have a large database.
Another way of solving the problem would be using the extra method of the QuerySet API. This is a method that is detailed in this blog post by Timmy O'Mahony.
valid_actions = UserAction.objects.filter(start_time__gte=start_time)
q = User.objects.filter(user_type=type).extra(select={
"time_sum": """
SELECT SUM(time)
FROM userAction
WHERE userAction.user_id = user.id
AND userAction.id IN %s
""" % (%s) % ",".join([str(uAction.id) for uAction in valid_actions.all()])
})
This method however relies on calling the database with the SQL table names, which is very un-Django - if you change the db_table of one of your databases or the db_column of one of their columns, this code will no longer work. It though only requires 2 queries, the first one to get the list of valid userAction and the other one to sum them to the matching user.

Is is possible to query django ORM by last updated object?

I know I can easily grab the latest entered object, but assuming an update is made to an object in the middle of the pack lets say object 50 of 100, is there a way to query the database to grab that latest update? I.e. number 50, since it was the latest to be updated as opposed to entered into the db?
I searched online and couldn't find anybody trying to accomplish this.
Thanks,
If your model have a DateTimeField with auto_now=True, you can use QuerySet.latest method with that field name specified.
For example, assuming that Model has a field DateTimeField updated_at with auto_now set:
last = Model.objects.lastest('updated_at')

Add an IntegerField to a Datefield in a Django template

I'm trying to display the expiry date of a bonus from within a Django template. At the moment the opening_date is stored as a datefield and we store the bonus term as an integerfield. Unfortunately just trying to add the bonus term to the opening date fails and the furthest I have got so far is:
{{product_form.instance.opening_date|add:product_form.instance.bonus_term}}
I have tried just adding it to the month but unfortunately I need the whole date returned to display.
For a better idea of what I want is say the opening date was 01/01/2012 and the bonus term was 12, I want to display the expiry date of 01/01/2013. I realise this is probably better off being in the database but due to the way it has been previously set up there is a large amount of existing data that wouldn't have it.
Thanks.
I think that, for your scenario, the most elegant solution is to create a model method in your model that calcule expire date, then call the method in template:
In model:
class product(models.Model):
opening_date = ...
bonus_term = ...
def expire_date( self ):
return self.opening_date + timedelta( days = self.bonus_term )
In template:
{{product_form.instance.expire_date}}
I'm sure that you will call this method in more other lines of your code.