Django Query values_list getting last value - mysql

Lets say I have a blog and a class user in a model. Furthermore I have a class comment connected with a foreign key.
class User(models.Model):
UserName = models.CharField(max_length=50, blank=True)
UserCountry = models.CharField(max_length=2, blank=True)
class Comment(models.Model):
commentText = models.TextField(max_length=1000)
commentSub = models.ForeignKey(User, related_name='comLink')
created_at = models.DateTimeField(auto_now_add=True)
Now I want to make an csv export in model admin and a I have a queryset with values_list.
I am wondering whether there exists a possibility to get each User once and e.g. only the last comment?
myList = queryset.values_list('UserName', 'UserCountry', 'comLink__commentText')
comLink is the related name. Now I just want the last comment. A timestamp is existing and I have not figured out how to filter or reverse etc.

You can do it with Subquery, I don`t know your model design, so it would be approximately like that:
from django.db.models import OuterRef, Subquery
com = Comment.objects.filter(commentSub=OuterRef('pk')).order_by('-created_at')
myList = queryset.annotate(LastComment=Subquery(com.values('commentText')[:1]))
myList = myList.values_list('UserName', 'UserCountry', 'LastComment')
https://docs.djangoproject.com/en/2.0/ref/models/expressions/#subquery-expressions

Related

How do I access a method from my Model in Django in React

In the following model...
class Question(models.Model):
question_text = models.CharField(max_length=200)
likes = models.IntegerField(default=0)
dislikes = models.IntegerField(default=0)
pub_at = models.DateTimeField(auto_now_add=True)
category = models.ForeignKey(
Category, on_delete=models.SET_NULL, null=True)
def __str__(self):
return f"{self.question_text}"
def validity(self):
total_likes = self.likes + self.dislikes
if total_likes != 0:
return (self.likes / total_likes) * 100
else:
return 100
I want to be able to access Question.objects.get(pk=1).validity() assuming that pk=1 exists in this case. In python shell I can do this easily. But how do I do this using React. I am able to get all my questions and the fields in React without a problem but I don't think I have a way to access the validity method I created.
In this case I would suggest the following. First, remove the property from the model:
# models.py
class Question(models.Model):
question_text = models.CharField(max_length=200)
likes = models.IntegerField(default=0)
dislikes = models.IntegerField(default=0)
pub_at = models.DateTimeField(auto_now_add=True)
category = models.ForeignKey(
Category, on_delete=models.SET_NULL, null=True)
def __str__(self):
return f"{self.question_text}"
Then add a SerializerMethodField (docs) to your serializer. It is read-only and can be used to pass computed values to your views:
# serializers.py
class QuestionSerializer(serializers.ModelSerializer):
validity = serializers.SerializerMethodField()
class Meta:
model = Question
fields = ['question_text', 'likes', 'dislikes', 'pub_at', 'category', 'validity']
def get_validity(self, instance):
total_likes = instance.likes + instance.dislikes
# Your approach is not wrong. This is a more explicit way of dealing with that particular error type
try:
return (instance.likes / total_likes) * 100
except ZeroDivisionError:
return 100
Bear in mind that the Foreign Key category will be serialized as its database unique id value (Primary Key) in this case.
You might want to use the #property decorator so that you can access the value the same way you would access any of the other fields on your Question model:
class Question(models.Model):
question_text = models.CharField(max_length=200)
likes = models.IntegerField(default=0)
dislikes = models.IntegerField(default=0)
pub_at = models.DateTimeField(auto_now_add=True)
category = models.ForeignKey(
Category, on_delete=models.SET_NULL, null=True)
def __str__(self):
return f"{self.question_text}"
#property
def validity(self):
total_likes = self.likes + self.dislikes
percentage = (self.likes / total_likes) * 100
return percentage
Explanations can be found in the docs or here. Keep in mind that it will not be saved like the other attributes as columns on the database when you run migrations.
I am answering my own question here I found a solution to. Although, #property does work when rendering using a simple Django template when using React and rendering json responses validity is still not available.
In my serializers.py file I did the following...
class QuestionSerializer(serializers.ModelSerializer):
validity = serializers.ReadOnlyField()
class Meta:
model = Question
fields = '__all__'
Take away the #property from the models as it is no longer needed. This has worked for me and you can go to the Django rest_framework or test it in your React application to see if you have access to this.
I would like to know if there are any issues doing this and/or a better way. I was also trying to do validity = serializers.Field() instead of validity = serializers.ReadOnlyField() but got an error saying I needed a Field.to_representation() that takes in self, value as positional arguments.
What arguments exactly do I pass in here. I tried self, Question.validity and did not work. I am not sure what I am doing here.
As an update the method in the model I updated to...
def validity(self):
total_likes = self.likes + self.dislikes
if total_likes != 0:
return (self.likes / total_likes) * 100
else:
return 100
I did not notice before and does not really matter for the question but division by zero is not allowed being that by default division by zero will always occur.

Django model id being overwritten by id of GenericForeignKey

I am trying create a new database entry using a custom Django model I created. However, when I try to create the model and save it, the id does not increment. Instead, the previous database entry is overwritten whose id == 1. I have tried setting force_insert=True inside the save() function, but it results in a runtime error where the primary key already exists. I don't set any primary values in the creation of the object, so I'm not sure why the id is not being incremented. I am running the test code in the manage.py shell. All the models have been migrated properly.
The model:
class RoadWayData(models.Model):
blocked_lanes = models.PositiveIntegerField()
city = models.CharField(max_length=255)
county = models.CharField(max_length=255)
direction = models.CharField(max_length=255, blank=True, null=True, default=None)
eto = models.CharField(max_length=255)
incident_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
incident_object = GenericForeignKey('incident_type', 'id')
injuries = models.PositiveIntegerField()
postmile = models.CharField(max_length=255, blank=True, null=True, default=None)
queue = models.CharField(max_length=255, default="NONE: Freeflow Conditions")
route = models.CharField(max_length=255, blank=True, null=True, default=None)
street = models.CharField(max_length=255, blank=True, null=True, default=None)
timestamp = models.DateTimeField(auto_now=True)
update = models.PositiveIntegerField()
maintenance = models.CharField(max_length=255)
tow = models.CharField(max_length=255)
weather = models.CharField(max_length=255)
vehicles_involved = models.PositiveIntegerField()
The test code:
from incident.models import *
import datetime
x = IncidentIndex.objects.get(id=1)
y = CHPIncident.objects.get(id=x.incident_object.id)
print("ID already exists in DB: {}".format(RoadWayData.objects.get(id=1).id))
z = RoadWayData(
blocked_lanes=0,
city="testCity",
county="testCounty",
direction="NB",
eto="Unknown",
highway_accident=True,
incident_object=y,
injuries=0,
postmile="New Postmile",
route="new Route",
update = 2,
maintenance= "Not Requested",
tow="Not Requested",
weather="Clear Skies",
vehicles_involved=0,
)
z.save()
print("New Data Object ID: {}".format(z.id))
Shell Output:
ID already exists in DB: 1
New Data Object ID: 1
Edit #1:
I am using a mySQL database and have not overridden the save() function. The mySQL console shows only one entry in the table(the model that was most recently saved).
Edit #2
I commented out the RoadWayData model and migrated the changes to wipe the table. Afterwards, I un-commented the model and migrated the changes to add it back to the database. The issue still persists.
Edit #3
I was able to manually insert a new entry into the table using the mySQL console. The ID incremented correctly. Perhaps it is a Django bug?
Edit #4
I've pinpointed the source of the problem. The problem stems from the contenttypes library. More specifically, the GenericForeignKey. For some reason when an the content object is assigned, the model inherits the content object's id.
Code with problem isolated:
x = IncidentIndex.objects.get(id=1)
y = CHPIncident.objects.get(id=x.incident_object.id)
r = RoadWayData(
...
incident_object = None, # Do not assign the generic foreign key
...
)
r.save()
print(r) # Shows <RoadWayData object> with CORRECT id
r.incident_object = y # Assign the general object
print(r) # Shows <RoadWayData object> with the id of y. INCORRECT
The easiest fix would be to create a variable to keep track of the Model's id BEFORE assigning the content_object (incident_object in my case).
FIX:
... initialization from code above ...
r.save()
r_id = r.id # SAVE THE CORRECT ID BEFORE ASSIGNING GENERIC FOREIGN KEY
r.incident_object = y # ASSIGN THE GENERIC FOREIGN OBJECT
r.id = r_id # OVERWRITE THE ID WITH THE CORRECT OLD ID
r.save()
The incident_object field in the RoadWayData model, has the reference id (the second parameter) set to its own id. So, when model assigns incident_object , it overwrites the id of the model.
To fix it, create a new PostiveIntegerField (like incident_id) and replace
incident_object = GenericForeignKey('incident_type', 'id')
with
incident_id = models.PostiveIntegerField(null=True)
incident_object = GenericForeignKey('incident_type', 'incident_id')

Unable to change the value of foreign key to foreign key of an object Django

I am having a model structure like:
class user(models.Model):
name = models.CharField(max_length=100)
tasks = models.IntegerField(default=0)
class project(models.Model):
worker = models.ForeignKey(user, on_delete=models.CASCADE)
project_name = models.CharField(max_length=100)
class task(models.Model):
project = models.ForeignKey(project, on_delete=models.CASCADE)
task_name = models.CharField(max_length=150)
expected_date = models.DateField(auto_now=False,auto_now_add=False,)
actual_date = models.DateField(auto_now=False,auto_now_add=False,blank=True,null=True,)
I want to traverse through the task list and if actual date field is not null i.e. task completed then to update the tasks field in user class by 1. I have written the following code:
a = task.objects.filter(actual_date__isnull=False)
for x in a:
x.project.worker.tasks+=1
However this is not giving the desired result. What should I do?
You are not saving your object after modifying it - simply modifying the value doesn't write it to the database. Try this instead:
a = task.objects.filter(actual_date__isnull=False)
for x in a:
worker = x.project.worker
worker.tasks += 1
worker.save()
On a separate note you should consider following PEP8 conventions and using CamelCase for your class names. As it is currently you can very easily mix up classes with objects.

Django showing error while saving data into a model: django.db.utils.IntegrityError: (1048, "Column 'id' cannot be null")

I am writing a script which can pull data from different API's and store into a MySQL database. This application will run from command line. So I am only using Django's ORM.
But when I am creating a model which doesn't have primary key but have a column named id. When I am trying to save data in this model I am getting a error django.db.utils.IntegrityError: (1048, "Column 'id' cannot be null")
I am really confused why this happens. Because from API I get values from id column and there is no chance to get null or empty value for this column.
Please suggest me what I am doing wrong here.
Here is my model:
class Graphite(models.Model):
class Meta:
db_table = 'graphite'
id = models.BigIntegerField()
full_name = models.CharField(max_length=250, null=True)
email = models.CharField(max_length=250, null=True)
status = models.CharField(max_length=150, null=True)
And this is the code when I am trying to save data in this model:
Graphite.objects.using('database_name').create(
id=row['id'],
full_name=row['full_name'],
email=row['email'],
status=row['status'])
When saving data into model I am using Graphite.objects.using('database_name'). because I have multiple database connected in this application.
Well I'm not sure did you use django migrations, but it won't let you create this kind of model in django, where your id property (in model) hasn't primary key as its parameter (mySQL). So why don't you just define:
class Graphite(models.Model):
class Meta:
db_table = 'graphite'
id = models.BigIntegerField(primary_key=True)
full_name = models.CharField(max_length=250, null=True)
email = models.CharField(max_length=250, null=True)
status = models.CharField(max_length=150, null=True)
so set primary_key on id? Then you wouldn't have to pass id when creating Graphite.
BUT
If you have to provide id which is something you need to have in every Graphite model and it's something different than primary key, then just define it different, let's say row_id. But you should still have at last one id property in your model with primary_key set to True when you want to have id as BigIntegerField.
EDIT (on the example)
In mySQL execute this command:
ALTER TABLE graphite ADD COLUMN row_id BIGINT;
Then your model should looks like this:
class Graphite(models.Model):
class Meta:
db_table = 'graphite'
row_id = models.BigIntegerField()
full_name = models.CharField(max_length=250, null=True)
email = models.CharField(max_length=250, null=True)
status = models.CharField(max_length=150, null=True)
And usage:
Graphite.objects.using('database_name').create(
row_id=row['id'],
full_name=row['full_name'],
email=row['email'],
status=row['status'])
and that's it.
The problem is that you do not have a primary key.
From the docs:
Each model requires exactly one field to have primary_key=True (either explicitly declared or automatically added).
So, you have to make your id field a primary key by adding primary_key=True. Then, it won't complain.
You are overriding id from default django table id.
so there is no id for primary key. Just make it primary=True. or use another id like graphaite_id
You are missing your primary key, make sure you have your primary=True and to store your id make another column for it

Django Model: What is a efficient way to list Foreign Key?

I have three models below. I omit some irrelative fields.
class Team(models.Model):
name = models.CharField(max_length=100)
class Player(models.Model):
name = models.CharField(max_length=100)
class Match(models.Model):
home = models.ForeignKey(Team)
away = models.ForeignKey(Team)
home_players = models.CharField(max_length=100, null=True)
away_players = models.CharField(max_length=100, null=True)
home_players and away_players have the type of player id list, such as [1,2,3,...,15].
I want to know better ways like using Foreign Key List.
Because, I have some troubles in manually inserting players IDs at Django Admin Page. It takes much time finding player name in Player() and matching player's ID. I guess the task would be easier if I can assign a certain relationship between Player() and Team().
That would be a many-to-many relationship.
https://docs.djangoproject.com/en/1.9/topics/db/examples/many_to_many/
class Match(models.Model):
home = models.ForeignKey(Team)
away = models.ForeignKey(Team)
home_players = models.ManyToManyField(Player)
away_players = models.ManyToManyField(Player)