Django How to catch ModelForm unique together errors - django

I have a ModelForm which has a unique_together constraint on certain fields. Now when I pass data to the form and call form.is_valid(), it returns False if record already exists and also if some other error occurs.
So, I want to do something in case the record already exists(unique_together validation fails) and another thing in case Form.is_vaid() returns False due to some other reasons.
How do I achieve this ?

It would help to have your ModelForm code and also traceback errors in both cases to give more accurate answer, but a workaround could be to parse form.errors, look for the corresponding type error or message error and write the corresponding code.
PS : this message should be a comment under your post but I lack few reputation points, sorry for that.

Related

Possible causes for error: Field cannot be both deferred and traversed using select_related at the same time?

I am trying to use graphene-django-optimizer to remove some of the unnecessary queries. It worked quite well until one certain field where I get this error message Field User.company cannot be both deferred and traversed using select_related at the same time. The only difference with this field is that it is models.OneToOne instead of models.ForeignKey. Why Django make this field deferred? Is it possible to disable field being deferred?
If you do this:
queryset.select_related('some_fk_field').only('another_field')
You may miss that there is a conflict. You are telling Django ORM to include some_fk_field, but you are also telling it to limit the query to only retrieve another_field, so it complains it can't do it.
You use .only() to exclude absolutely everything that is not detailed, but .select_related() is trying to do the opposite requesting some extra elements. To make it even clearer (and this is how I found out), here is the Django source code that handles this case:
if load_fields:
if field.attname not in load_fields:
if restricted and field.name in requested:
raise InvalidQuery("Field %s.%s cannot be both deferred"
" and traversed using select_related"
" at the same time." %
(field.model._meta.object_name, field.name))
Source:
https://docs.djangoproject.com/en/2.1/_modules/django/db/models/query_utils/

Error writing to many to many field django rest framework api

This seems to be my solution https://stackoverflow.com/a/48636446/7989638 (for "How can I make a writable ManyToManyField with a Through Model in Django Rest Framework?
") but I am getting this error :
{"images":["Incorrect type. Expected pk value, received unicode."]}
their solution works in the create method of the serializer but i debugged and checked that it never reaches that method; returns error beforehand.
Could you please help me fix this.
Thanks

Django+postgres auth_user duplicate key value violates unique constraint "auth_user_username_key"

try:
django_user = User.objects.get(username__iexact=self.username)
except User.DoesNotExist:
django_user = User(username=self.username)
django_user.is_staff=True
django_user.save()
Above gets the user by searching by username if present or create a new object if not present and updates its attribute and saves it back to db.
This code ideally should handle the situation where the object is already present in the database. But it is throwing following error
duplicate key value violates unique constraint "auth_user_username_key"
DETAIL: Key (username)=(xxxxxxxx#yyyyy.com) already
exists.
I don't get the reason for this. Searched on the internet and found that It might be because of indices are corrupted and has to reset the sequence but Cannot find the exact reason and solution for this.
Please help me with this.
Thanks in advance
I've been a while since i don't refresh my Django skills but as far i remember you
can use another way to surpass this problem like:
if Entry.objects.filter(username=self.username).exists():
# DO IF STUFF
else:
# DO ELSE STUFF
If your username isn't the pk key then you may have to set it as unique and that would prevent to have duplicated usernames.
Oficial Django reference
But there is something it is digging in my mind by the way you are using your self.username variable. It seems you have some class where you needs to make such kind of functionality. And i'm afraid that this peace of code you have is located inside of the same class model declaration, by the kind of query you wants to perform you should keep this in mind:
If you wants to check for some username that hasn't been insert in the databse yet then it won't have a pk and you won't be able to look for such data in the database. By summoning it before the .save() some of this errors can happen.
Hope this helps you.

Django get_or_create vs catching IntegrityError

I want to insert several User rows in the DB. I don't really care if the insert didn't succeed, as long as I'm notified about it, which I'm able to do in both cases, so which one is better in terms of performance (speed mostly)?
Always insert the row (by calling the model's save method) and catching potential IntegrityError exceptions
Call the get_or_create method from the QuerySet class
Think about what are you doing: you want to insert rows into the database, you don't need to get the object out of it if it exists. Ask for forgiveness, and catch IntegrityError exception:
try:
user = User(username=username)
user.save()
except IntegrityError:
print "Duplicate user"
This way you would avoid an overhead of an additional get() lookup made by get_or_create().
FYI, EAFP is a common practice/coding style in Python:
Easier to ask for forgiveness than permission. This common Python
coding style assumes the existence of valid keys or attributes and
catches exceptions if the assumption proves false. This clean and fast
style is characterized by the presence of many try and except
statements.
Also see: https://stackoverflow.com/questions/6092992/why-is-it-easier-to-ask-forgiveness-than-permission-in-python-but-not-in-java

Django unique constraint + form errors

I'm having some issues with double-posting on my site. I figure a simple unique constraint across all the relevant fields will solve the issue on a database level, but then it just produces a nasty error page for the user. Is there a way I can turn this into a pretty form error instead? Like a non_field_error? Or what approach should I take?
Maybe something like this will help you:
class YourForm(forms.Form):
# Everything as before.
...
def clean(self):
cleaned_data = self.cleaned_data
your_unique_key = cleaned_data['your_unique_key']
if your_unique_key and YourModel.objects.get(your_unique_key=your_unique_key):
raise forms.ValidationError("not unique")
# Always return the full collection of cleaned data.
return cleaned_data
The clean() method will allow you to access all fields of the form which might be useful if you have a combined unique key. Otherwise a (sightly shorter) clean_your_unique_key() might suit you better.
And please note that under rare circumstances (race conditions) the form validation might not report a duplicate entry (but it's of course reported by the database engine). But for most applications the provided example will be the easier and more maintainable one, so I still recommend this approach.
as far as a 'nasty error page' for the user, Django lets you customize your own 500,404 and probably other pages. general info on that:
In order to use the Http404 exception
to its fullest, you should create a
template that is displayed when a 404
error is raised. This template should
be called 404.html and located in the
top level of your template tree.
-- http://docs.djangoproject.com/en/dev/topics/http/views/
another nice way, not as DRY as tux21b's solution but perhaps a little easier to understand for a one-time solution, might be to catch the error intelligently. one way is to do so without even bothering to violate the constraint - a simple query should verify whether the user is about to do something illegal.
okToUpdate=MyModel.objects.filter(parameters=values...).count()
if okToUpdate>0: # an object already exists
errorExists=True
errors={customError:customMessage}
...
if errorExists:
return render_to_response(errors,'customErrorPage.html')
else:
# return whatever you normally would return
you then use render_to_response to render a custom error page.
(another way is to allow the database violation to occur, then catch that error and do the same thing... i theorize that a DB gets slightly less stress doing a lookup than handling an exception but it's up to you how you like to do things).
JB