Django form validation working unexpectedly? - django

I have this form in my view:
joinform = JoinProjectForm(request.POST)
print(request.POST)
print(joinform)
if joinform.is_valid():
joinkey = joinform.cleaned_data['joinkey']
project = Project.objects.filter(joinkey=joinkey).first()
project.users.add(request.user)
return redirect('problemdashboard:problem-dashboard', project_id=project.pk)
else:
joinform = JoinProjectForm()
And this is my model:
class Project(MainAbstractModel):
users = models.ManyToManyField(User)
title = models.CharField(max_length=25, default="")
joinkey = models.IntegerField(null=True, unique=True)
Now what I don't understand is, why is the form validation returning False? It says that a project with that joinkey already exists, but I'm not trying to create a new project with that joinkey, I simply want to add an user to the project with the joinkey that the user inputs in the form. What am I missing here?
Oh and the form itself is very simple:
class JoinProjectForm(ModelForm):
class Meta:
model = Project
fields = ['joinkey']

Error is being caused by the null=True, unique=True in:
joinkey = models.IntegerField(null=True, unique=True)
This is checking that every Project has a unique joinkey, if not then you will get 'a project with that joinkey already exists' error.
Since you have null=True and unique=True, django is considering None as a unique entry, remove null=True.

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)

Foreign key error in django, Cannot assign "'1'": "Release.projectID" must be a "Project" instance

I have two models: 'Project' and 'Release'.
In release table, projectId is foreign key associated with Project table.
When tried creating new release, when entered projectID, getting:
Cannot assign "'1'": "Release.projectID" must be a "Project" instance
I have three files named, models.py, forms.py,views.py
models.py:
class Project(models.Model):
JIRAID = models.CharField(max_length=20,null=True)
projectID = models.AutoField(primary_key=True)
projectName = models.CharField(max_length=100)
projectDescription = models.CharField(max_length=100)
projectStartDate = models.DateField()
projectEndDate = models.DateField()
projectEstimatedLOE = models.IntegerField()
createdBy = models.CharField(max_length=30)
createdAt = models.DateTimeField(default=datetime.datetime.now,null=True,blank=True)
updatedAt = models.DateTimeField(default=datetime.datetime.now,null=True,blank=True)
def __str__(self):
return (self.JIRAID, self._get_pk_val, self.projectName, self.projectDescription, self.projectStartDate, self.projectEndDate, self.projectEstimatedLOE,self.createdBy,self.createdAt,self.updatedAt)
class Meta:
db_table='Project'
class Release(models.Model):
JIRAID = models.CharField(max_length=20 )
projectID = models.ForeignKey(Project,on_delete=models.CASCADE,null=True)
releaseID = models.AutoField(primary_key=True)
releaseName = models.CharField(max_length=100)
releaseDescription = models.CharField(max_length=100)
releaseStartDate = models.DateField()
releaseEndDate = models.DateField()
releaseEstimatedLOE = models.IntegerField()
createdBy = models.CharField(max_length=30)
createdAt = models.DateTimeField(default=datetime.datetime.now, null=True, blank=True)
updatedAt = models.DateTimeField(default=datetime.datetime.now, null=True, blank=True)
def __str__(self):
return (self.JIRAID, self.projectID,self._get_pk_val,self.releaseName, self.releaseDescription, self.releaseStartDate, self.releaseEndDate, self.releaseEstimatedLOE,self.createdBy,self.createdAt,self.updatedAt)
class Meta:
db_table='Release'
unique_together = (('projectID', 'releaseID'),)
Views.py:
def releasecreation(request):
context = {'form': Release}
if request.method=='POST':
form = ReleaseCreationForm(request.POST)
if form.is_valid():
JIRAID=request.POST.get('JIRAID')
projectID=Project.objects.get('projectID')
releaseID=request.POST.get('releaseID')
releaseName=request.POST.get('releaseName')
releaseDescription=request.POST.get('releaseDescription')
releaseStartDate=request.POST.get('releaseStartDate')
releaseEndDate=request.POST.get('releaseEndDate')
releaseEstimatedLOE=request.POST.get('releaseEstimatedLOE')
createdBy = User.objects.get(username=request.user.username)
form.save()
return render(request,'releasepages/releasecreateconfirmation.html')
else:
return render(request,'releasepages/releasecreate.html')
else:
return render(request,'releasepages/releasecreate.html',context)
I should be able to create release,by getting dropdown at projectID column while creating release.
There is a few things that is not quite right with this code:
setting form class in the context
The template probably expects a form instance and not a class, like: {'form': Release()} (note the parenthesis).
Also, is it on purpose that this is not the same class as ReleaseCreationForm used below?
defining a bunch of variables and never using them
Unless there is some removed code, I don't see any usage for all those variables defined right after if form.is_valid():.
do a http redirect after for save
When a form has been successfully saved, the application should issue a redirect instead of rendering a template. This is to prevent resubmitting the form if user decides to reload the page.
I suggest closely following the view structure from here: https://docs.djangoproject.com/en/2.2/topics/forms/#the-view
This has all the "ifs" needed to process a form and they are in exactly the correct structure. If tempted to alter this logic, I would be very very cautions that I'm doing something wrong.
But to answer your question directly, to (manually) create an instance of Release, you can do one of these two things:
project_instance = Project.objects.get(projectID=123)
Release.objects.create(
projectID=project_instance,
# other_fields...
)
or
Release.objects.create(
projectID_id=123,
# other_fields...
)
As you can see, ForeignKey field automatically creates another attribute on the model that has _id appended to it (so you have both projectID and projectID_id attributes on your Release model). Accessing release_instance.projectID will return an instance of Project model and not its ID.
This is probably not as intended, and I'm guessing that it would be cleaner to rename the model field projectID into project.
Try this
projectID=Project.objects.filter(pk=request.POST.get('projectID')).first()

Django RestFramework - NOT NULL constraint failed

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.

Django - Form validation error

I have a model like this:
class Entity(models.Model):
entity_name = models.CharField(max_length=100)
entity_id = models.CharField(max_length=30, primary_key=True)
entity_parent = models.CharField(max_length=100, null=True)
photo_id = models.CharField(max_length=100, null=True)
username = models.CharField(max_length=100, null=True)
date_matched_on = models.CharField(max_length=100, null=True)
status = models.CharField(max_length=30, default="Checked In")
def __unicode__(self):
return self.entity_name
class Meta:
app_label = 'match'
ordering = ('entity_name','date_matched_on')
verbose_name_plural='Entities'
I also have a view like this:
def photo_match(request):
''' performs an update in the db when a user chooses a photo '''
form = EntityForm(request.POST)
form.save()
And my EntityForm looks like this:
class EntityForm(ModelForm):
class Meta:
model = Entity
My template's form returns a POST back to the view with the following values:
{u'username': [u'admin'], u'entity_parent': [u'PERSON'], u'entity_id': [u'152097'], u'photo_id': [u'2200734'], u'entity_name': [u'A.J. McLean'], u'status': [u'Checked Out'], u'date_matched_on': [u'5/20/2010 10:57 AM']}
And form.save() throws this error:
Exception in photo_match: The Entity could not be changed because the data didn't validate.
I have been trying to figure out why this is happening, but cannot pinpoint the exact problem. I can change my Entities in the admin interface just fine. If anybody has a clue about this I would greatly appreciate it!
Thanks,
Igor
If the entity you are trying to update is already saved, then you need to provide an instance parameter when you bind the form, otherwise save will try to perform an INSERT rather than an UPDATE, and the new object won't validate (check out the django docs here).
Try:
def photo_match(request):
''' performs an update in the db when a user chooses a photo '''
entity = Entity.objects.get(pk=request.POST['entity_id'])
form = EntityForm(request.POST, instance=entity)
form.save()
You'll want to be a little more robust about the way you look up the entity, of course.