Django: Handling of duplicated values on unique rows - django

I have a row of data and in it consist of Protein object. Protein Object has unique
protein_id (not PK) and rows of data can have repeatable protein object.
So when a user creates a row of data say Data: {'protein_id':ABC123} if the given protein_id already exists in database, we'll use that protein object.
I am able to create the protein object when it does not exist in database. But when it already exist, I am getting "protein with this protein id already exists.".
I understand that this happens because I am creating new protein object with the same protein_id and protein_id has a unique=True attribute.
But what I am not understanding is (Refer below for details) why I am unable to get the object if exist or why is the exception getting thrown (Not sure whats the logic behind).
Models.py
class Protein(models.Model):
protein_id = models.CharField(max_length=256, null=False, blank=False,unique=True)
sequence = models.CharField(max_length=40000,blank=True)
Serializer.py
class ProteinSerializer(serializers.ModelSerializer):
class Meta:
model = Protein
fields = ['protein_id',"sequence"]
def create(self,validated_data):
protein_data = validated_data.pop('protein')
protein = None
try:
protein = Protein.objects.get(protein_id=protein_data['protein_id'])
except Protein.DoesNotExist:
protein = Protein.objects.create(**protein_data)
return protein
What I have tried here is a try-except where the serializer will first get the protein object in database and if it can't be found it will throw an exception which will then create the protein object.
I have also tried get_or_create() and i think the logic is the same with these 2 methods.
So I am not sure why I am still creating the object (throwing an exception) when it can be found. Or am I having a wrong approach? Thanks in advance!

Related

'RelatedManager' object has no attribute 'payment_status'

I am creating an app in which I want to query all the members and their status. but I am getting above error.
these are my both models.
class Member(models.Model ):
user = models.ForeignKey(Users,verbose_name='User Id', on_delete=models.CASCADE)
com = models.ForeignKey(Committee, on_delete=models.CASCADE,verbose_name='Committee Name')
class PaymentDetail(models.Model):
mem = models.ForeignKey(Member,on_delete=models.CASCADE, related_name='payment_details', verbose_name='Memeber Phone no')
com = models.ForeignKey(Committee, on_delete=models.CASCADE,related_name='committee_details',verbose_name='Committee Name')
payment_month = models.DateField(default=datetime.now())
payment_status = models.CharField(max_length=16, choices=PAYMENT_DETAILS_CHOICES, default="1")
First I am getting all the members by (members.objects.all() then looping over like this
for member in members:
member.payment_details.payment_status
but I am getting this error related manager has no attribute.
actually I can get data from PaymentDetail.objects.all() but it will only show data from PaymentDetail table. I want all the members and next to them their status from PaymentDetail table
You have ForeingKey relation, this is relation one to many, if you wanna access to payment_details you have to ask for all related objects by payment_details.all().
Consider using one to one relation (https://docs.djangoproject.com/en/4.0/topics/db/examples/one_to_one/)
, after change to one to one relation this member.payment_details.payment_status will be work.

Sub Categorized Status Choices in Django

Let's say I have a model of sandwiches, and I want to say what protein you want to put on the sandwich:
class Sandwich(models.Model):
protein_choices = (
('n', 'Please Choose'),
('e1', 'Eggplant'),
('e2', 'Hummus'),
('v1', 'Provolone'),
('v2', 'Egg'),
('p1', 'Fish'),
('c1', 'Beef'),
('c2', 'Chicken'),
('c3', 'Pork'),
)
protein = models.CharField(
max_length=2,
choices=protein_choices,
default='n',
)
How could I make the choices categorized by vEgan, Vegetarian, Pescatarian, or Carnivore?
I want to be able to check its category (is the sandwich Vegan[assuming categorizations don't overlap]?), and I have been using a model.Manager, but I want to ensure that all choices have a single category (I think this is the missing link, and don't think testing is the right way) and only one choice is selected (which is already handled by the status structure presented).
Should this be handled in a model.Form, a 1->M relationship with some other structure, or through model.Managers and something else?
Another option is an in-memory data structure and interface that maps your status keys to their appropriate category. For example you could use an Enum with a category property as the basis for your Choices. If the relationships between those strings ends up being something you want to manage in the database you can always refactor and add a migration.
As you've noted building a tree structure in your models as others have suggested makes for a lot of joins.. and in that case it might be useful to take a look at django-treebeard or django-categories and check if it's reasonable to take on that additional dependency.
I think having separate models for protein and category will be good.
Example:
class Protein(models.Model):
name = models.CharField(max_length=20)
class ProteinCategory(models.Model):
protein = models.ForeignKey(to="Protein")
name = models.CharField(max_length=20)
class Sandwich(models.Model):
protein = models.ForeignKey(to="Protein")
Use ManyToManyField instead of ForeignKey in Sandwich model, if a Sandwich contains many Protein.
Use OneToOneField in ProteinCategory model, if a Protein can be in one and only one ProteinCategory.
I suggest using different models for this task.
Continuing with your example, you could have the proteins, which each belong to a single category (as per your request in the comments to your question):
class ProteinCategory(models.Model):
name = models.CharField(max_length=20)
class Protein(models.Model):
name = models.CharField(max_length=20)
category = models.ForeignKey(to=ProteinCategory)
Then you could assign a single protein (as per your request) for each sandwich:
class Sandwich(models.Model):
name = models.CharField(max_length=20)
protein = models.ForeignKey(to=Protein)
Does this seem to solve your issue?

Django QuerySet: Is it possible to filter for field__is_null for FloatFields?

I want to be able to query a model for records where the is no value for a particular float field. The problem is the basic query:
Model.objects.filter(float_field__is_null=True)
returns the following error: django.core.exceptions.FieldError: Unsupported lookup 'is_null'.
To test, create the following model:
class FloatFieldModel(models.Model):
date = models.DateField()
val = models.FloatField(blank=True, null=True)
Then:
>>> objects = FloatFieldModel.objects.filter(val__is_null=True)
>>> django.core.exceptions.FieldError: Unsupported lookup 'is_null' ...
How can I filter a model for records where there is no value for a particular float field? In other words, what is the best work around?
What I want to be able to do is the set up a routine to only update rows without any values, but skip those rows already with a specified value (while making most efficient use of my database). What I was trying looks something like:
for date in dates:
try:
FloatFieldModel.objects.filter(
date=date,
val__is_null=True
).update(val=42.0)
except FloatFieldModel.DoesNotExist:
pass
I imagine I could do something like:
objects = FloatFieldModel.objects.all()
for obj in objects:
if obj.val is None and obj.date in set(dates):
obj.val = 42.0
obj.save()
I was trying for a more efficient process though, rather than on which required reading each object from the database into memory before saving.
There is lookup isnull not is_null https://docs.djangoproject.com/en/dev/ref/models/querysets/#std:fieldlookup-isnull
Model.objects.filter(float_field__isnull=True)

id of object is none after save in django

I'm looping through a list of objects and saving. I need the newly generated id or pointer id right after the save but it is None.
Here is my code:
for category in category_list:
saved_category = category.save()
print saved_category.parentCategory_ptr_id
print saved_category.id
This saves my object after the routine is run, but again, does not give me the id at this line.
here is my model:
class ParentCategory(models.Model):
name = models.CharField(max_length=255)
class Category(ParentCategory):
description = models.CharField(max_length=255)
category list was created like so:
category_list = []
for row in value_list:
category = Category(description=row.description)
category_list.append(category)
return category_list
What am I doing wrong?
The problem is with:
saved_category = category.save()
It needs to be:
category = category.save()
The original saved object in the list is the object that contains the id.
Their is no need of reassign.
category.save()
When you call save() method the object is saved into database and assign id (primary key) to the object.
Saving Objects Django Official
Other same question asked on Stackoverflow and correct answer by Daniel Roseman
I don't think the object will get saved. Seems that the object you are creating lacks sufficient data to satisfy db constraints. You might have used try-catch somewhere, you would have seen the error. Try adding blank=True, null=True to name in ParentCategory or provide a name while creating the object. I hope this works...

Django model instance from foreign key

I am reading Excel using xlrd. One of the columns has the Bank name, which is linked to vehicle model via Foreign Key. When xlrd finishes reading a row, it should save that record to vehicle table. However getting the actual pk value and error that Vehicles.bank must a Banks instance.
After checking dozens of questions related to this issue, I found this one the most similar one, but still I am not getting the expected result.
The relevant Vehicle model section is as follows:
class Vehicles(models.Model):
stock = models.CharField(max_length=10, blank=False, db_index=True)
vin = models.CharField(max_length=17, blank=False, db_index=True)
sold = models.DateField(blank=True, null=True, db_index=True)
origin = models.CharField(max_length=10, blank=False, db_index=True)
bank = models.ForeignKey('banks.Banks', db_column='bank', null=True)
I am using python 2.7, django 1.5.4 and Postgresql 9.2.5. Dbshell utility does show that banks table has a Foreign contraint referring to vehicles table, via banks(id).
Since I am not using a form for this particular part, I think it does not matter whether I use a ModelForm or not.
Current scenario: Excel file has FBANK as the cell value. There is an existing record in banks table that contains FBANK in its name column, id=2. The python line is:
def bank(value):
return Banks.objects.get(name=value).id
With the above line, error is:
Cannot assign "2": "Vehicles.bank" must be a "Banks" instance.
If I remove the ".id" at the end, error is then:
Banks matching query does not exist.
Appreciate your help.
Ricardo
When saving Vehicle you need to pass Banks instance with corresponding bank name. See example, I suppose that you have all data in corresponding cells from 0 to 4, replace with your own cells numbers:
def get_bank_instance(bank_name):
try:
bank = Banks.objects.get(name=bank_name)
except Banks.DoesNotExist:
return None
return bank
# reading excel file here, we have list of cells in a row
for cell in cells:
bank = get_bank_instance(cell[4])
if bank:
# get other cells values to be saved in Vehicles
stock, vin, sold, origin = cell[0], cell[1], cell[2], cell[3]
Vehicles.create(bank=bank, stock=stock, vin=vin, sold=sold, origin=origin)
You also can create save instance of Vehicles passing bank id directly:
b_id = Banks.objects.get(name=bank_name).id
Vehicles.create(bank_id=b_id, stock=stock, vin=vin, sold=sold, origin=origin)
Update:
create() is a built-in model method to create and save into database model instance. If you are asking about "Add a classmethod on the model class" in Django docs, this is not the case, because you are just using built-in method for the model. For some cases you can use custom method for creating new models, but I would do so if I had to pass a lot of default attributes for the new instance.
Also, it's possible to create and save new model instance by using save():
bank_instance = Banks.objects.get(name=bank_name)
vehicle = Vehicles()
vehicle.bank = bank_instance
vehicle.stock = stock
vehicle.vin = vin
vehicle.sold = sold
vehicle.origin = origin
# without save() data will not be saved to db!
vehicle.save()
It's quite long and you always need to remember to call .save(), so it's a good idea to use .create()
You should be returning a Banks instance when you want to assign it to a Vehicle model instance; so you should not have the .id part at the end of the return value for your bank() method.
Secondly, if it says that it isn't finding the Banks instance, then you should check the value of your value parameter to see what it is and try to manually do a Banks.objects.get from your database. If it can't be found then there is probably another reason for this other than using the Django ORM incorrectly.
When you are assigning instances to other instances in Django, for example setting the Bank for a Vehicle it must be an instance of the model and not the id or pk value of model; this is stated in the other StackOverflow question that you reference in your question.