This is my forms.py in Django app.But I have not understand the save() function specially the commit keyword. I took this code from a blog . here the writter is making a form for user registration.
from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
from . models import Document
class NewUserForm(UserCreationForm):
email = forms.EmailField(required=True)
class Meta:
model = User
fields = ("username", "email", "password1", "password2")
def save(self, commit = True):
user = super(NewUserForm, self).save(commit = False)
user.email = self.cleaned_data["email"]
if commit:
user.save()
return user
please explain the whole save function.
Related
I am trying to make an Instagram API clone using Django rest framework.
I have created an account module that has two fields - user,AccountType. user is a OnetoOneField with the Django User model.
from django.db import models
from django.conf import settings
User=settings.AUTH_USER_MODEL
# Create your models here.
class Account(models.Model):
user=models.OneToOneField(User,on_delete=models.CASCADE)
PUBLIC='pub'
PRIVATE='pvt'
Account_choices=[
(PUBLIC,'Public'),
(PRIVATE,'Private')
]
AccountType=models.CharField(max_length=3,choices=Account_choices,default=PUBLIC)
I created a serializer for this model.
from rest_framework import serializers
from .models import Account
class AccountCreateSerializer(serializers.ModelSerializer):
class Meta:
model = Account
fields=['user','AccountType']
In the views I received data from a client and used the data to create a User object and then use this user object to create an Account object. But when I try to serialize the data and check if it is_valid it reurns False. Can someone tell me how to fix this?
#api_view(['POST'])
def register_view(request,*args,**kwargs):
username = request.data['username']
password = request.data['password']
email = request.data['email']
user = User.objects.create_user(username, email, password)
data={
'user':user,
'AccountType':'pub'
}
serializer = AccountCreateSerializer(data=data)
return Response(data)
I tried giving the serializer input as a dictionary and even the username as just a string.
githubLink: https://github.com/henselwilson/Instafam.git
You alredy created an account for that user: a OneToOneField is a ForeignKey that is unique, so you can not create a second account for that user.
You thus let the serializer do the work:
#api_view(['POST'])
def register_view(request, *args, **kwargs):
username = request.data['username']
password = request.data['password']
email = request.data['email']
user = User.objects.create_user(username, email, password)
# do not create an Account
data = {'user': user, 'AccountType': 'pub'}
serializer = AccountCreateSerializer(data=data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
I'm fairly new to Django and feel I must be missing something. I have an application where I want two user types (UserType1 and UserType2). I am using the base user model with boolean flags and then created OneToOne fields on these objects to the user (no extra data added at this point).
This gives me the following user models:
from django.conf import settings
from django.contrib.auth.models import AbstractUser, UserManager
from django.core.exceptions import ValidationError
from django.db import models
from django_extensions.db.models import TimeStampedModel
class User(AbstractUser):
"""
Default user model for the platform
"""
email = models.EmailField()
is_user_type_1 = models.BooleanField(default=False)
is_user_type_2 = models.BooleanField(default=False)
# Use default UserManager for now
objects = UserManager()
class UserType1(TimeStampedModel):
user = models.OneToOneField(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
primary_key=True,
related_name='user_type1',
)
class UserType2(TimeStampedModel):
user = models.OneToOneField(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
primary_key=True,
related_name='user_type2'
)
I then wrote serializes for these classes where I only want to expose and endpoint for UserType1 and UserType2 (rather than User itself). This should allow the users to create an instance of UserType1 or UserType2 which will also create the row in the User table (although maybe not super important for this). Here are the serializers:
from django.db import transaction
from rest_framework import serializers
from .models import User, UserType1, UserType2
class UserSerializer(serializers.ModelSerializer):
"""
Serializer for the `User` model
"""
class Meta:
model = User
fields = (
'username',
'email',
'password',
'first_name',
'last_name',
'is_active',
)
extra_kwargs = {'password': {'write_only': True}}
class UserType1Serializer(serializers.ModelSerializer):
user = UserSerializer(required=True)
class Meta:
model = UserType1
fields = (
'user',
'created',
'modified',
)
#transaction.atomic
def create(self, validated_data):
user_data = validated_data.pop('user')
user_data.is_user_type_1 = True
user_data.is_user_type_2 = False
user = UserSerializer.create(UserSerializer(), validated_data=user_data)
user_type_1, created = UserType1.objects.update_or_create(
user=user,
)
return user_type_1
class UserType2Serializer(serializers.ModelSerializer):
user = UserSerializer(required=True)
class Meta:
model = UserType2
fields = (
'user',
'created',
'modified',
)
#transaction.atomic
def create(self, validated_data):
user_data = validated_data.pop('user')
user_data.is_user_type_1 = False
user_data.is_user_type_2 = True
user = UserSerializer.create(UserSerializer(), validated_data=user_data)
user_type2, created = UserType2.objects.update_or_create(
user=user,
)
return user_type2
The User model was registered in my settings:
AUTH_USER_MODEL = 'user.User'
After I create a superuser, I am successfully able to get my tokens and use them to access other views:
{
"refresh": "xxxx",
"access": "xxxx"
}
However, if I create a user from admin (or I have fixtures that create users and user_type1/user_type2 objects), every time I try to get the tokens I am getting:
{
"detail": "No active account found with the given credentials"
}
but I know they exist in the DB since I can see them properly in the admin console. I thought this was something to do with hashing of the password but was unable to solve it.
This also contains the following admin.py file:
from django.contrib import admin
from .models import User, UserType1, UserType2
admin.site.register(User)
admin.site.register(UserType1)
admin.site.register(UserType2)
Any help would be greatly appreciated!!
Register your custom User model in the admin with:
from django.contrib.auth.admin import UserAdmin
admin.site.register(models.User, UserAdmin)
Or follow the documentation on how to register a custom User model in admin.
A full example
create a new User via admin panel and check if the password is hashed.
Then make the api call to your jwt endpoint again.
I am currently implementing an API client for which I want to validate the request sent using serializers.
To do so, I create my serializer like this:
class TransactionRequestSerializer(serializers.Serializer):
counterparty = serializers.UUIDField(required=False)
from_datetime = serializers.DateTimeField(required=False, source='from')
to_datetime = serializers.DateTimeField(required=False, source='to')
transaction_type = serializers.CharField(required=False, source='type')
Issue is that source doesn't fit my usage, because when I do serializer.data, I get:
{'from_datetime': '2020-07-07T16:08:00.313236+02:00'}
Instead of
{'from': '2020-07-07T16:08:00.313236+02:00'}
Those data are then passed as params for my request, like requests.get('', params=params)
Of course, I cannot name the field "from" as it is reserved. Any idea about how can I get "from" in my serializer.data?
I tink this has already been answered.
Please take a look at this question: How to change field name in Django REST Framework
I think the same solution will work for you.
I think it's not possible, so I switched to Serializer.validated_data instead so I can use source.
this example as same the question :
model:
from django.db import models
class ReceiveCallbackUrl(models.Model):
From = models.CharField(max_length=14)
to = models.CharField(max_length=14)
message = models.CharField(max_length=255)
messageid = models.IntegerField()
serializer:
from rest_framework.serializers import ModelSerializer,SerializerMethodField
from .models import ReceiveCallbackUrl
class ReceiveCallbackUrlModelSerializer(ModelSerializer):
From = SerializerMethodField('from')
class Meta:
model = ReceiveCallbackUrl
fields = ['From', 'to', 'message', 'messageid']
view:
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from .serializer import ReceiveCallbackUrlModelSerializer
class ReceiveCallbackUrlAPIView(APIView):
def post(self, request):
serializer = ReceiveCallbackUrlModelSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(request.POST, status=status.HTTP_200_OK)
return Response(serializer.errors, status=status.HTTP_406_NOT_ACCEPTABLE)
I'm trying to add some additional fields to the allauth signup form (first_name and last_name). I'm thinking the best way to do this is to create a allauth SignupForm subclass and add my own fields (very new to django so please let me know if I'm going about this wrong)
I added
ACCOUNT_SIGNUP_FORM_CLASS = 'accounts.forms.UserCreateForm'
to my base settings file
and here is my accounts.forms.py...
from django.contrib.auth import get_user_model
from allauth.account.forms import SignupForm
from django import forms
class UserCreateForm(SignupForm):
class Meta:
fields = ("first_name", "last_name", "email", "username", "password1", "password2")
model = get_user_model()
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields["first_name"].label = ''
self.fields["first_name"].widget.attrs["placeholder"] = "First Name"
self.fields["last_name"].label = ''
self.fields["last_name"].widget.attrs["placeholder"] = "Last Name"
self.fields["email"].label = ''
self.fields["email"].widget.attrs["placeholder"] = "Email"
self.fields["username"].label = ''
self.fields["username"].widget.attrs["placeholder"] = "Username"
self.fields["password1"].label = ''
self.fields["password1"].widget.attrs["placeholder"] = "Password"
self.fields["password2"].label = ''
self.fields["password2"].widget.attrs["placeholder"] = "Confirm Password"
for some reason I keep getting the error ...
django.core.exceptions.ImproperlyConfigured: Error importing form class accounts.forms: "cannot import name 'SignupForm'"
Not sure why. Obviously there is a SignupForm in allauth.account.forms.py, seen here...
https://github.com/pennersr/django-allauth/blob/master/allauth/account/forms.py
I dont know what I'm doing wrong. Any help you can give is much appreciated
https://stackoverflow.com/a/12308807/3415357
You do not need to inherit allauth.account.forms.SignupForm, you should inherit from forms.Form specify fields and write your custom signup function (username, email, password should stay intact)
models.py:
from django.db import models
from pygments.lexers import get_all_lexers
from pygments.formatters.html import HtmlFormatter
from pygments import highlight
LEXERS = [item for item in get_all_lexers() if item[1]]
class Classname(models.Model):
class_name = models.CharField(max_length=5)
owner = models.ForeignKey('auth.User', related_name='fab')
highlighted = models.TextField()
def save(self, *args, **kwargs):
lexer = get_lexer_by_name(self.class_name)
options = self.class_name and {'class': self.class_name} or {}
formatter = HtmlFormatter(full=True, **options)
self.highlighted = highlight(self.class_name, lexer, formatter)
super(Classname, self).save(*args, **kwargs)
serializers.py:
from django.forms import widgets
from django.contrib.auth.models import User
from rest_framework import serializers
from .models import Classname
class ClassSerializer(serializers.HyperlinkedModelSerializer):
owner = serializers.ReadOnlyField(source='owner.username')
highlight = serializers.HyperlinkedIdentityField(view_name='fab-highlight', format='html')
class Meta:
model = Classname
fields = ('id', 'owner', 'class_name', 'highlight',)
class UserSerializer(serializers.ModelSerializer):
fab = serializers.HyperlinkedRelatedField(many=True, view_name='user-detail', read_only=True)
class Meta:
model = User
fields = ('id', 'username', 'fab',)
urls.py:
from django.conf.urls import url, patterns
from rest_framework.urlpatterns import format_suffix_patterns
from . import views
urlpatterns = [
url(r'^class/$', views.ClassList.as_view()),
url(r'^class/(?P<pk>[0-9]+)/$', views.ClassDetail.as_view()),
url(r'^section/$', views.SectionList.as_view()),
url(r'^section/(?P<pk>\d+)/$', views.SectionDetail.as_view()),
url(r'^teacher/$', views.TeacherList.as_view()),
url(r'^teacher/(?P<pk>[0-9]+)/$', views.TeacherDetail.as_view()),
url(r'^attend/$', views.AttendanceList.as_view()),
url(r'^attend/(?P<pk>[0-9]+)/$', views.AttendanceDetail.as_view()),
]
When I changed my serializers.py file and try to add HyperLinked as per the tutorial then I got the above error, I'm not using ViewSets and Routers. I don't know what's the problem b'coz I've checked my url's and views everything seems to be fine.
I'm confused, Please help me to find and fix the issue....
Thanks in advance.....
The exact issue is that I'm using namespace in urls and I've used it in my project level urls.py file also. So in the views file I have to follow django-namespacing like this:
'users': reverse('student:user-list', request=request, format=format),
while 'student' is the namespace that I've used in my project level urls like:
url(r'^stu/', include('app.urls', namespace = 'student'),