I'm using Django 2.x
I have a serializer for validating the request. (Not ModelSerializer)
class ExecuteSerializer(serializers.Serializer):
database = serializers.IntegerField(required=True)
query = serializers.CharField(required=True)
user = serializers.HiddenField(
default=serializers.CurrentUserDefault()
)
def validate(self, attrs):
user = attrs.get('user', None)
try:
database = Database.objects.get(pk=attrs.get('database', None), collection__user=user)
except Database.DoesNotExist:
raise ValidationError({
'database': ['Does not exists']
})
attrs['database'] = database
return attrs
database is reference to the Database model.
I want user to pass the database id in the database field but got is converted to database object after validation.
I tried to override the validate() method and assign the database object to the database field but it gives error
TypeError: int() argument must be a string, a bytes-like object or a number, not 'Database'
Since you are using IntegerField for database field you shoud return int as database value in validate method, for example database.id:
def validate(self, attrs):
user = attrs.get('user', None)
try:
database = Database.objects.get(pk=attrs.get('database', None), collection__user=user)
except Database.DoesNotExist:
raise ValidationError({
'database': ['Does not exists']
})
attrs['database'] = database.id # fix is here
return attrs
Related
/*tests.py*/
def create_user(username, password):
user = get_user_model().objects.create_user(username=username, password=password)
return user
#helper function to populat database
def create_category(name, super, user):
category = Category.objects.get_or_create(name=name)[0]
category.super = super
category.user = user
category.save()
return category
# The following test is for the save and deleting of
# a page from the favorites list
class TestFavoritesFeature(TestCase):
def setUp(self):
self.user = create_user("testUser", "testPassword")
self.cat = create_category('python', self.super, self.user)
Both the object.create and object.get_or_create give an error for NOT NULL field. Above is the code , 2 models and both throw an error on only the id field that we do not even populate. It is the function's job to assign a unique id to it. The above is code from tests.py file. I am trying to populate DB for unit testing . In the actual code, these objects.get_or_create or objects.create do not give errors but are rather successful
In the .get_or_create(…) [Django-doc] you need to provide values for the super_cat, user and name, but you only did this for the name.
We can further simplify the method by using .update_or_create(…) [Django-doc] and use the defaults=… parameter to specify what to update or initialize in case the object is not/is created:
def create_category(name, super, user):
category, __ = Category.objects.update_or_create(
name=name,
defaults={'super_cat': super, 'user': user}
)
return category
I am creating first rest api in django using django rest framework
I am unable to get object in json format. Serializer always returns empty object {}
models.py
class Shop(models.Model):
shop_id = models.PositiveIntegerField(unique=True)
name = models.CharField(max_length=1000)
address = models.CharField(max_length=4000)
serializers.py
class ShopSerializer(serializers.ModelSerializer):
class Meta:
model = Shop
fields = '__all__'
views.py
#api_view(['GET'])
def auth(request):
username = request.data['username']
password = request.data['password']
statusCode = status.HTTP_200_OK
try:
user = authenticate(username=username, password=password)
if user:
if user.is_active:
context_data = request.data
shop = model_to_dict(Shop.objects.get(retailer_id = username))
shop_serializer = ShopSerializer(data=shop)
if shop:
try:
if shop_serializer.is_valid():
print('is valid')
print(shop_serializer.data)
context_data = shop_serializer.data
else:
print('is invalid')
print(shop_serializer.errors)
except Exception as e:
print(e)
else:
print('false')
else:
pass
else:
context_data = {
"Error": {
"status": 401,
"message": "Invalid credentials",
}
}
statusCode = status.HTTP_401_UNAUTHORIZED
except Exception as e:
pass
return Response(context_data, status=statusCode)
When i try to print print(shop_data) it always returns empty object
Any help, why object is empty rather than returning Shop object in json format?
Edited:
I have updated the code with below suggestions mentioned. But now, when shop_serializer.is_valid() is executed i get below error
{'shop_id': [ErrorDetail(string='shop with this shop shop_id already exists.', code='unique')]}
With the error it seems it is trying to update the record but it should only get the record and serialize it into json.
You're using a standard Serializer class in this code fragment:
class ShopSerializer(serializers.Serializer):
class Meta:
model = Shop
fields = '__all__'
This class won't read the contend of the Meta subclass and won't populate itself with fields matching the model class. You probably meant to use ModelSerializer instead.
If you really want to use the Serializer class here, you need to populate it with correct fields on your own.
.data - Only available after calling is_valid(), Try to check if serializer is valid than take it's data
I have a form that takes "username" from the User model and my own "email" field. I want to change this data for the User model. At first glance everything seems to work fine, the name changes and the mail is the same. But if I only change the mail and I don't touch the username, I get an error: "A user with this name already exists.
file views.py:
form=UserUpdateForm(request.POST)
if form.is_valid():
user=User.objects.get(username=self.request.user)
user.username=form.cleaned_data.get('username')
user.email=form.cleaned_data.get('email')
user.save()
file forms.py:
class UserUpdateForm(forms.ModelForm):
email = forms.EmailField(required=False)
def __init__(self, *args, **kwargs):
super(UserUpdateForm, self).__init__(*args, **kwargs)
if 'label_suffix' not in kwargs:
kwargs['label_suffix'] = '*'
self.fields['username'].widget = forms.TextInput(attrs={'class':'input-text'})
self.fields['email'].widget = forms.EmailInput(attrs={'class':'input-text'})
class Meta:
model = User
fields = ("username","email",)
def clean_email(self):
cleaned_data = super(UserUpdateForm,self).clean()
email=cleaned_data.get('email')
return email
From the doc,
A subclass of ModelForm can accept an existing model instance as the keyword argument instance; if this is supplied, save() will update that instance. If it’s not supplied, save() will create a new instance of the specified model
If you are updating the data, you have to pass the instance to the form as,
# on updationg
form = UserUpdateForm(data= request.POST, instance=your_mode_instance)
Since you are not passing the instance for the second time, Django thinks that the operation is a row insert instead of row update
should i use is_valid() function for validating my user data in put() function in drf?
because when i use it ,is_valid.errors says that model with this username and email is already exists!i can't understand the errors meaning,because i think should be something saved before i want to update
serializers.py
class UserCreateSerializers(ModelSerializer):
class Meta:
model = User
fields = ('name','email','family',"username","password","profile_pic")
def update(self, instance, validated_data):
print("from update try")
#more dry
for i in validated_data.keys():
if hasattr(instance,str(i)) and str(i) !="password":
setattr(instance,str(i),validated_data.get(str(i)))
elif hasattr(instance,str(i)) and str(i) =="password":
instance.set_password(validated_data.get('password'))
setattr(instance,"username",validated_data.get('new_username'))
instance.save()
views.py
def put(self,request):
username = request.data['username']
user = User.objects.get(username = username)
serialized = UserCreateSerializers(data = request.data)
if serialized.is_valid():
serialized.update(user,serialized.validated_data)
return Response(data ={"status":"api_user_update_ok"} , status = status.HTTP_201_CREATED)
else:
print(serialized.errors)
return Response(data = {"status":"api_user_update_failed","error":serialized.errors.get('email')[0]},status = status.HTTP_400_BAD_REQUEST)
client data with put method :
name:user
family:useri
username:user2
password:1234
new_username:user22
email:user#gmail.com
error is :
{'email': [ErrorDetail(string='user with this email already exists.',
code='unique')], 'username': [ErrorDetail(string='user with this
username already exists.', code='unique')]} Bad Request:
/api/v0/registration/signup
and the server response is :
{
"status": "api_user_update_failed",
"error": "user with this email already exists."
}
thanks for your help.
Short answer: yes you should use is_valid() before try to save received data into DB. You see this error because DRF add uniqueness validator to unique fields by default. This behavior described in the doc.
To tell django that you are updating object and don't need uniqueness validator you have to provide instance to serializer:
serialized = UserCreateSerializers(user, data=request.data)
I'm trying to take input of a domain name (domainNm) and an email address at a domain (emailVerified) and submit them via modelform based off a table [Tld] .
It appears, it is failing to save() the foreign key (from the currently authenticated user)
domain.FKtoClient = user_info
What am I doing wrong here?
forms.py
class SubmitDomain(ModelForm):
domainNm = forms.CharField(initial=u'', label='Enter your domain')
emailVerified = forms.EmailField(label='Email at Domain')
class Meta:
model = Tld #Create form based off Model for Tld
fields = ['domainNm','emailVerified']
def save(self, request=None):
instance = self.cleaned_data
#domain = instance["domainNm"])
domains = Tld.objects.filter(domainNm=instance["domainNm"])
if len(domains) == 0:
domain = Tld()
else:
domain = domains[0]
user_info = request.user
unique_id = int(uuid.uuid4())
domain.generated_hash = str(unique_id)
domain.entered_email = instance["emailVerified"]
domain.domainNm = instance["domainNm"]
domain.FKtoClient = user_info
domain.save()
Thanks!
def save(self, request=None):
You assign a default value of None to request in the definition of save, so what happens when the caller of save doesn't pass an instantiated request?
user_info = request.user #request is None here
That will throw the error you see. To mitigate, add a simple if request is not None or similar statement.
EDIT
After seeing your views.py, you are passing request.POST to SubmitDomain's __init__ magic method, which you have not defined. The way you have your modelform defined above, you would have to pass the request to save(), not __init__(), i.e.
form.save(request)