Django - get_or_create() with auto_now=True - python

I’m using Django and I'm having a problem with a Python script that uses Django models
The script that I'm using takes data from an api and loads it into my database.
my model:
class Movie(models.Model):
title = models.CharField(max_length=511)
tmdb_id = models.IntegerField(null=True, blank=True)
release = models.DateField(null=True, blank=True)
poster = models.TextField(max_length=500, null=True)
runtime = models.IntegerField(null=True, blank=True)
description = models.TextField(null=True, blank=True)
edit = models.DateTimeField(auto_now=True, null=True, blank=True)
backdrop = models.TextField(max_length=500, null=True, blank=True)
popularity = models.TextField(null=True, blank=True)
the script:
movies = tmdb.Movies().upcoming()
results = movies['results']
ids = []
for movie in results:
data, created = Movie.objects.get_or_create(title=movie['title'],
tmdb_id=movie['id'],
release=movie['release_date'],
description=movie['overview'],
backdrop=movie['backdrop_path'],
poster=movie['poster_path'],
popularity=movie['popularity'])
The problem I'm having is that whenever I run the script, the entries are duplicated because the edit field is change, but the purpose I put the edit field is to know when exactly a movie got edited, ie: some other field got changed.
How can I avoid the duplicates, but also keep the edit field in case some real change happened?

but the purpose I put the edit field is to know when exactly a movie
got edited, ie: some other field got changed.
That probably means you are using the wrong function. You should be using update_or_create istead.
A convenience method for updating an object with the given kwargs,
creating a new one if necessary. The defaults is a dictionary of
(field, value) pairs used to update the object.
This is different from get_or_create, which creates an object if it does not exists, or simply fetches it when it does exist. update_or_create is the one that does the actually updating.
However, changing to this method doesn't solve this:
How can I avoid the duplicates, but also keep the edit field in case
some real change happened?
Duplicates are created because you do not have a unique index on any of your fields. Both get_or_create and update_or_create require that you have a unique field. It seems that the following change is in order:
class Movie(models.Model):
title = models.CharField(max_length=511)
tmdb_id = models.IntegerField(unique=True)

Related

Unable to delete object from Django admin panel with MongoDB

I have a Django project using a MongoDB connected by Djongo. I created a simple model which looks like:
from django.db import models
# Create your models here.
class Property(models.Model):
name = models.CharField(max_length=128, blank=False)
property_type = models.CharField(max_length=24, blank=True)
include_on = models.CharField(max_length=256, blank=True)
format_example = models.TextField(blank=True)
notes = models.TextField(blank=True)
After registering the model by using the line admin.site.register(Property) in the admin.py file I end up seeing my model appear. After adding a test Property I see the line
The property “Property object (61226db9f4f416b206c706e5)” was added successfully.
Which tells me the item was added. It also appears on the admin panel but it looks like:
Property object (None)
If I select the property I get an error that says:
Property with ID “None” doesn’t exist. Perhaps it was deleted?
If I try to delete the property I get a ValueError with error of:
Field 'id' expected a number but got 'None'.
Since I am currently learning Django/MongoDB I actually ran across the ValueError once before. The fix was to delete the entire database and start over. The issue is I don't want to run into this in the future and want to know what I have to do to fix it, or correct what I am doing wrong.
I found my answer. Turns out I need to assign a primary key. I fixed this by changing my model to..
class Property(models.Model):
name = models.CharField(primary_key=True, max_length=128, blank=False)
property_type = models.CharField(max_length=24, blank=True)
include_on = models.CharField(max_length=256, blank=True)
format_example = models.TextField(blank=True)
notes = models.TextField(blank=True)

Error inserting data into Django database field with a OneToOnefield

I've asked this question before and tried to Google it but I've had no luck, so I have simplified my question. I have two very simple models: one holds some shift numbers and the other holds some data related to the sale of gift cards during a shift. In this case, we have an employee who worked shift "1234" and sold $200.45 and $43.67 worth of gift card from each of two terminals. The models are below:
class Data_Shifts(models.Model):
shift_id = models.CharField(max_length=25, primary_key=True, db_column="shift_id", verbose_name="Shift ID")
def __str__(self):
return str(self.shift_id)
class Data_GiftCards(models.Model):
shift_id = models.OneToOneField('Data_Shifts', on_delete=models.CASCADE, primary_key=True, db_column="shift_id", verbose_name="Shift ID")
net_sales_terminal_1 = models.DecimalField(max_digits=8, decimal_places=2, default=0)
net_sales_terminal_2 = models.DecimalField(max_digits=8, decimal_places=2, default=0)
def __str__(self):
return str(self.shift_id)
I then try to insert some test data into the table using the following command:
Data_GiftCards.objects.create(shift_id="1234", net_sales_terminal_1="200.45", net_sales_terminal_2="43.67")
Upon submitting the web form, I get the following error:
Cannot assign "'1234'": "Data_GiftCards.shift_id" must be a "Data_Shifts" instance.
I am boggled by this. I have a workaround that bypasses django and inserts directly into the table successfully, but this is dirty and I'd prefer to use the proper Pythonic Django way. What am I doing wrong here?
Many thanks in advance.
That is because you name your field shift_id. Django's ORM maps the name of the field in your model to an instance of the related model, not to an ID.
You can still work with IDs instead of instances, but then you have to add _id to the end of your field name.
In your case, you have two options, you can simply do that, which would mean your query should look like:
Data_GiftCards.objects.create(shift_id_id="1234", net_sales_terminal_1=200.45, net_sales_terminal_2=43.67)
But shift_id_id looks redundant, so you can tweak the other end and remove the _id suffix in your model:
class Data_GiftCards(models.Model):
shift = models.OneToOneField('Data_Shifts', on_delete=models.CASCADE, primary_key=True, db_column="shift_id", verbose_name="Shift ID")
net_sales_terminal_1 = models.DecimalField(max_digits=8, decimal_places=2, default=0)
net_sales_terminal_2 = models.DecimalField(max_digits=8, decimal_places=2, default=0)
def __str__(self):
return str(self.shift)
Then you will have to query as you are doing, but you should not use strings if the field types are numeric.
Data_GiftCards.objects.create(shift_id="1234", net_sales_terminal_1=200.45, net_sales_terminal_2=43.67)
Also, you don't need the attribute db_column="shift_id". If your field name is shift, the name of the field in the database table will already be shift_id.

Using Model.objects.all() as a blueprint for a secondary table entry

I am having a bit of trouble with the logic of how this should work so I am hoping it is possible.
I figured out 1 possible solution that is written as an answer below, I will accept it in a few days, but if someone comes up with a better solution, I will negate any answer I post.
Overall I am working on an Apartment Move-Out/Move-In Inspection Application in Django, and in both portions I have universal Locations that must be inspected for each report. I have allowed the InspectionLocations objects to be updated/submitted by clients, which is presenting an issue in how submitted reports should be stored in my Database.
What I want is to use the InspectionLocations table as a blueprint to build an Inspection Report for Move-Ins where the form-fields are generated based on the InspectionLocations objects' location, status, and information attributes/fields.
My issue is right at this point, how do I reference those values as a blueprint to build a report submission when the number of fields in the InspectionLocations can change?
from django.db import models
from apps.units.models import Unit
class Inspections(models.Model):
class Meta:
abstract = True
id = models.AutoField(primary_key=True)
inspection_date = models.DateField()
submitted_by = models.ForeignKey(
'users.CustomUser',
default=None,
null=True,
on_delete=models.SET_NULL,
db_column='submitted_by')
last_update = models.DateTimeField(auto_now=True)
date_added = models.DateTimeField(auto_now_add=True, editable=False)
class MoveInInspections(Inspections):
unit = models.ForeignKey(Unit, on_delete=models.CASCADE, db_column='unit_id')
# should have reference to all InspectionLocation items as reference for submission, how?
class MoveOutInspections(Inspections):
unit = models.ForeignKey(Unit, on_delete=models.CASCADE, db_column='unit_id')
date_notice_given = models.DateField(blank=True, null=True, default=None)
date_vacated = models.DateField(blank=True, null=True, default=None)
# should have reference to all InspectionLocation items as reference for submission, how?
class InspectionLocations(models.Model):
'''
Defualt Inspection Locations are created when a
client is created using code like this:
InspectionLocation.objects.get_or_create(location='Living Room')
InspectionLocation.objects.get_or_create(location='Dining Room')
InspectionLocation.objects.get_or_create(location='Kitchen')
InspectionLocation.objects.get_or_create(location='Bedroom')
InspectionLocation.objects.get_or_create(location='Bathroom')
InspectionLocation.objects.get_or_create(location='Other')
'''
id = models.AutoField(primary_key=True)
location = models.CharField(max_length=50)
status = models.BooleanField(default=None)
information = models.TextField(default=None, blank=True)
I have tried ManyToMany fields and FKs but I cannot seem to get the logic working as anytime an object references an InspectionLocations object it is universally changing data for every report, which is leading be to the idea that I somehow need to use it as a blueprint.
I didn't post this in my question because it was getting long, but my best option so far seems to be to use a Django JSONField (as I am using Postgres), like so:
from django.contrib.postgres.fields import JSONField
class MoveInInspections(Inspections):
unit = models.ForeignKey(Unit, on_delete=models.CASCADE, db_column='unit_id')
data = JSONField()
class MoveOutInspections(Inspections):
unit = models.ForeignKey(Unit, on_delete=models.CASCADE, db_column='unit_id')
date_notice_given = models.DateField(blank=True, null=True, default=None)
date_vacated = models.DateField(blank=True, null=True, default=None)
data = JSONField()
To where I store the values of the InspectionLocations object's in a Dictionary

How to obtain an object from a queryset of another object list in django

i am developing a project with django and i have a little problem.
I am trying to get an array from a querySet of another object. Trying to obtain the "articulo" who has the "carro_det.id_articulo_fk" field, and after send it to the context of my template:
But in the querySet i am getting the error 'int() argument must be a string, a bytes-like object or a number, not 'Articulo''
Specifically in the line: articulo[i]=Articulo.objects.get(pk=carro_det[i].id_articulo_fk)
This is from my views.py:
def index(request, id_user):
carro=Carro.objects.get(id_usuario_fk=id_user)
carro_det=Carro_det.objects.filter(id_articulo_fk=carro.id)
#HERE IS THE PROBLEM
for i in range(len(carro_det)):
articulo[i]=Articulo.objects.get(pk=carro_det[i].id_articulo_fk)
contexto = {'articulo':articulo,
'carro_det':carro_det}
return render(request, 'cart/cart.html', contexto)
And this is from my models.py, as you can see everything is fine here:
class Carro(models.Model):
total = models.FloatField(default=0, null=True, blank=True)
#llaves foraneas
id_usuario_fk=models.ForeignKey('myuser.Usuario', null=True, blank=True, on_delete=models.CASCADE, db_column='id_usuario_fk')
def __str__(self):
return "id_carro_cliente: " + str(self.id)
class Carro_det(models.Model):
cantidad = models.IntegerField(default=0)
precio_venta = models.FloatField(default=0)
total = models.FloatField(default=0)
#llaves foraneas
id_carro_fk=models.ForeignKey('Carro', null=True, blank=True, on_delete=models.CASCADE, db_column='id_carro_fk')
id_articulo_fk=models.ForeignKey('article.Articulo', on_delete=models.CASCADE, db_column='id_articulo_fk')
def __str__(self):
return "numero de carro asociado: " + str(self.id_carro_fk.pk)
I hope anyone can help me with this, Thank you!.
these 2 attributes:
id_carro_fk=models.ForeignKey('Carro', null=True, blank=True, on_delete=models.CASCADE, db_column='id_carro_fk')
id_articulo_fk=models.ForeignKey('article.Articulo', on_delete=models.CASCADE, db_column='id_articulo_fk')
are objects not PK's, even though that is how you labeled them. You could do:
articulo[i]=Articulo.objects.get(pk=carro_det[i].id_articulo_fk.pk) # notice the .pk at the end
But that isn't the real problem here. It would seem you need to more carefully read the django docs on relationships. It seems like you are accessing all the related Carro_det objects to the Carro instance by making those 2 queries, when you could just access the related attribute.
When declaring a ForeignKey field in django you are accessing the related object directly, with django creating the id field under the covers. This relationship can be accessed on the other (many) side by accessing:
RelatedModel.FKmodel_set
or if specified like so:
class Carro(Model):
field = ForeignKey('Model', related_name='related_fields', ...)
then:
# Carro_det instance
instance.related_fields # this accesses all carros related to this carro_det
# but this is a queryset you can filter down further, it is fetched lazily
or in your case:
carro_instance.carro_det_set
Instead of the way you are doing it...
carro_det[i].id_articulo_fk is returning the foreignkey(Articulo) instance. Instead, you need to use id_articulo_fk_id which is the actual pk of the Articulo instance.
Use:
articulo[i]=Articulo.objects.get(pk=carro_det[i].id_articulo_fk_id)

django having multiple one many to many relations that references same model

i have a model that is having multiple many to many relation to another model it is as follows:
class Match(models.Model):
"""Model docstring"""
Match_Id = models.AutoField(primary_key=True)
Team_one = models.ManyToManyField('Team',related_name='Team one',symmetrical=False,)
Team_two = models.ManyToManyField('Team',related_name='Team two',symmetrical=False,)
stadium = models.CharField(max_length=255, blank=True)
Start_time = models.DateTimeField(auto_now_add=False, auto_now=False, blank=True, null=True)
Rafree = models.CharField(max_length=255, blank=True)
Judge = models.CharField(max_length=255, blank=True)
winner = models.ForeignKey('Team', related_name='winner',to_field='Team_Name')
updated = models.DateTimeField('update date', auto_now=True )
created = models.DateTimeField('creation date', auto_now_add=True )
what is the best way to implement model like this ?. all though django does not throw any errors when passing the model sql once syncdb is excuted it throws up errors saying there is no unique constraint matching given keys
Are you sure Team_one and Team_two should be ManyToMany fields? Surely, a match only has a single team on each side - in which case these should both be ForeignKeys.
Using spaces in related_name attribute makes me uneasy, but I think the real problem is connected to the use of to_field attribute on the winner field. As far as I know you can set database relations only to unique fields. It doesn't really make sense to relate to another object using a field that may not be unique.
I'm not sure what do you want to achieve by connecting through this particular field. You usually connect models using primary key fields. This still allows you to access any other field on the related object.

Categories

Resources