Django RestFramework - NOT NULL constraint failed - django

My Model:
class Wishlist(models.Model):
home = models.ForeignKey(Home, on_delete=models.CASCADE, null=False, blank=False)
user = models.ForeignKey(User, on_delete=models.CASCADE, null=False, blank=False)
def __str__(self):
return "{} - {}".format(self.user.username, self.home.address)
class Meta:
ordering = ('user',)
My serializer
class WishlistSerializer(serializers.ModelSerializer):
home = serializers.RelatedField(required=True, queryset=home_models.Home.objects.all())
user = serializers.RelatedField(required=True, queryset=User.objects.all())
class Meta:
model = Wishlist
fields = ('id', 'user', 'home',)
My View
class WishlistAdd(CreateAPIView):
"""
Add a new Home in User wishlist
"""
serializer_class = serializers.UserWishlistSerializer
queryset = Wishlist.objects.all()
When I try to do a POST request to create the new record I receive the following error: IntegrityError at /user/wishlist/ NOT NULL constraint failed: user_wishlist.home_id
All of these happens after a git merge, but i don't notice any differences between the branches

My guess is that your sqlite database is tracked by git. This means that whenever you switch to the broken branch, lack of data integrity causes this error – even if the application code is perfectly the same. I recommend adding the database file to your .gitignore, and looking into Django's fixtures instead.

That error means you did not provide a home id in your post payload, though this error should be caught on the serializer level because you specified required there as well. The reason it is required is because because you specified in your model field as a non-nullable field
home = models.ForeignKey(Home, on_delete=models.CASCADE, null=False, blank=False)
if you dont wish for it to be required specify null=True, blank=True. Also you need to ensure that home exists. good luck.

Related

Add unique_together validation check on internal attirbutes of JSONField

I am using following model.
class MyProfile(models.Model):
name = models.CharField(max_length=100, default=None)
account_id = models.CharField(max_length=64, default=None)
prof_config = JSONField(null=True, blank=True, default=None)
result = JSONField(null=True, blank=True, default=None)
class Meta(object):
app_label = "app"
verbose_name = "MyProfile"
unique_together = [["account_id", "prof_config"]]
Previously prof_config included:
prof_config = {"username":"pranav","password":"123456"}
But now I have changed it to :
prof_config = {"username":"pranav","password":"123456","last_sync_time":null}
And as I want unique_together validation only on account_id, username and password.
For that I changed unique_together to:
unique_together = [["account_id", "prof_config__username","prof_config__password"]]
But it didn't work. It gave me following error (if last sync time is null for both profiles):
"Error while creating My Profile, error:duplicate key value violates unique
constraint \"app_myprofile_account_id_prof_config_b94a5cdc_uniq\"\nDETAIL: Key
(account_id, prof_config)=(4, {\"password\": \"123456\", \"username\": \"pranav\",
\"last_sync_time\": null}) already exists.\n", "causality": "", "opid": "fc3501fa",
"opid_chain": "fc3501fa", "level": "ERROR"}
I am getting this error even after I have added unique_together for account_id, username and password ([["account_id", "prof_config__username","prof_config__password"]]). But it's still taking whole prof_config. And If last sync time is different the profile is being created.
So Is there any way to do this.
You can override clean method in ModelForm and do manual validation
def clean(self):
cleaned_data = self.cleaned_data
# Your custom validation
...
# raise error if something is not right
raise ValidationError('Error')
return cleaned_data
The error that you ran into is related to the existing data in your database,
The error is saying you have already data in the database that doesn't follow your new unique_together rule
You should find and remove/edit the specific record that caused this error

Django: unable to save model - Err: "id" expected a number but got <django.db.models.fields.related.ForeignKey...>

I'm really out of ideas here, I tried everything.
Basically I'm just trying to save some item whereas the owner is a foreign key related to the default Django User Model. This same methods works for other views and models, where the association is identically. But here I get this error:
Exception Type: TypeError
Exception Value:
Field 'id' expected a number but got <django.db.models.fields.related.ForeignKey: owner>.
This is my model:
class User(AbstractUser):
pass
""" ... """
class Item(TimeStampMixin):
title = models.CharField(max_length=40)
owner = models.ForeignKey(User, on_delete=models.CASCADE, related_name="Items")
last_bidder = models.ForeignKey(User, on_delete=models.DO_NOTHING, related_name="bidded_objects", default=owner)
etc=etc...
This is my view:
class Form_New_Item(ModelForm):
class Meta:
model = Item
fields = ['title', 'description', 'price', 'category', 'image_url']
def create_new_item(request):
if request.user.is_authenticated and request.method == "POST":
form = Form_New_Item(request.POST)
user = request.user
if form.is_valid():
new_item = Item(
owner=user,
title=form.cleaned_data['title'],
etc=etc...,
)
new_item.save()
return HttpResponseRedirect(reverse("index"))
Notice the error happens when I call new_item.save():
Thank you in advance for any help you can provide me.
I just solved it, I should have provided the entire Item class on the example sorry for that (I just edit the first message), now I see more clearly where the error was:
I have a property of the class that depends on another property.
owner = models.ForeignKey(User, on_delete=models.CASCADE, related_name="listings")
last_bidder = models.ForeignKey(User, on_delete=models.DO_NOTHING, related_name="bidded_objects", default=owner)
So you see the second property last_bidder have as default the first one owner.
Despite the fact that the error Django report seems to be about owner property, the problem was on last_bidder one.
I solved it by setting null=True instead of a default with the first property:
last_bidder = models.ForeignKey(User, on_delete=models.DO_NOTHING, related_name="bidded_objects", null=True)

django get_or_create throws Integrity Error

I have read this thread:
get_or_create throws Integrity Error
But still not fully understand when get_or_create returns False or IntegrityError.
I have the following code:
django_username = 'me'
user = get_user_model().objects.filter(username=django_username).first()
action_history, action_added = ActionModel.objects.get_or_create(
date=date_obj, # date object
account_name=unique_name, # e.g. account1234
target=follower_obj, # another model in django
user=user, # connected django user
defaults={'identifier': history['user_id']}
)
While the model looks like:
class ActionModel(models.Model):
"""
A model to store action history.
"""
identifier = models.BigIntegerField(
_("identifier"), null=True, blank=True) # target id
account_name = models.CharField(_("AccountName"), max_length=150, null=True, blank=True) # account name of the client
date = models.DateField(_("Date"), auto_now=False, auto_now_add=False) # action date
target = models.ForeignKey(Follower, verbose_name=_("Target"), on_delete=models.CASCADE) # username of the done-on action
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
null=True,
editable=False,
db_index=True,
) # django user that performed the action
class Meta:
verbose_name = _("Action")
verbose_name_plural = _("Actions")
unique_together = [
['account_name','date','target'],
]
Sometimes it return IntegrityError, and sometimes (when unique constrain exists it will return False on created).
You have unique_together constraint.
Lets imagine you have object in db with following data
account_name='bob', date='2020-12-12', target='b', user='12'
In you get_or_create method you are doing this
ActionModel.objects.get_or_create(
date='2020-12-12',
account_name='bob',
target='b',
user="13"
)
you providing exactly this three parameters with this data, but user this time is 13, so django could not find any object and it tries to create one, but with this parametres you cant create object because there is unique constraint
OK.
I figured it out, I sent:
account_name = 'adi'
date = '07-02-21'
target = 'nana1'
user = 'me'
While it was not exist with the specific user = 'me' but with user = None:
account_name = 'adi'
date = '07-02-21'
target = 'nana1'
user = None
So the get was failing and the created try to duplicate the unique_together = ['account_name','date','target'].

Why django don't need all fields to test a model

I have a model like this:
class CreateDeal(models.Model):
name = models.CharField(max_length=100)
fuel = models.CharField(max_length=15)
mileage = models.PositiveIntegerField(db_index=True)
phone_number = models.CharField(max_length=17)
location = models.CharField(max_length=100, db_index=True)
car_picture = models.ImageField(upload_to='car_picture')
description = models.TextField()
price = models.PositiveSmallIntegerField(db_index=True)
available = models.BooleanField(default=True)
created_on = models.DateTimeField(default=timezone.now)
user = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return self.name
and I have a test class to test the model above like this:
class CreateDealTest(TestCase):
def setUp(self):
self.user = User.objects.create_user(
username='alfa', email='alfa#hotmail.com', password='top_secret'
)
self.deal = CreateDeal.objects.create(
name='deal1', mileage=100, price=25, user=self.user
)
def test_deal_name(self):
deal = CreateDeal.objects.get(name='deal1')
expected_deal_name = f'{self.deal.name}'
self.assertAlmostEqual(expected_deal_name, str(deal))
if I run the test I have:
Ran 1 test in 0.166s
OK
My question is why django don't raise an exception since almost all fields in my model are required. And what I don't understand is if I remove one field of Createdeal in my setUp (like mileage, price, user or name) I have an error.
For instance if I remove mileage, I have this error:
raise utils.IntegrityError(*tuple(e.args))
django.db.utils.IntegrityError: (1048, "Column 'mileage' cannot be null")
Charfield, Imagefield and Textfield can be empty string which is valid at the database level, some of your fields have default values so they will be written if not set so that makes them also valid at the database level.
PositiveIntegerField and Foreign key cannot be set to empty string, just to value or null so they will fail since null=False by default.
The default blank=False option is only applied at the validation level, not at the database level. This means if you call full_clean() on your model, it will raise a ValidationError. But nothing stops you from saving an invalid model (save() does not call full_clean() as explained here).

Django custom migration RunPython cannot access ForeignKey field in another database

I'm writing a django migration operation to change some data in the 'default' database. My app has access to a 'services' database, which contains data I cannot change.
The two relevant fields in the default.table are:
data_sets_to_remove = models.CharField(blank=True, null=False, max_length=100, default="")
data_sets_new = ArrayField(models.IntegerField(null=True, blank=True), null=True, blank=True)
i.e., i'm migrating data from data_sets_to_remove into a new format and adding to data_sets_new. To do this, I need to access data from the 'services' database in the migration operation.
def forwards_func(apps, schema_editor):
DataRelease = apps.get_model('registry', "datarelease")
Survey = apps.get_model('registry', "survey")
data_release_queryset = DataRelease.objects.using('services').all().values('id', 'name', 'survey')
But for some reason, the foreign key field 'survey' on the DataRelease model is not available in this context.
django.core.exceptions.FieldError: Cannot resolve keyword 'survey'
into field. Choices are: id, name
Can anyone shed any light on this? I assume the issue is around accessing data from a secondary database within a migration operation, but if i run the same code in the console, it works fine...
The relevant Survey and DataRelease models in the services database:
class Survey(models.Model):
name = models.CharField(blank=False, null=False, max_length=100, unique=True)
class DataRelease(models.Model):
name = models.CharField(blank=False, null=False, max_length=100)
survey = models.ForeignKey(Survey, related_name='data_releases', on_delete=models.CASCADE)
:facepalm:
The answer was staring me in the face. Switched the import of the associated models from:
DataRelease = apps.get_model('registry', "datarelease")
Survey = apps.get_model('registry', "survey")
to:
from services.registry.models import DataRelease, Survey
Now I can access the related fields in the migration operation. Hopefully this helps someone else in the future!