Many-to-one relationship in Django - python

I'm new to django thus the question.
This is my Location object,
class Location(models.Model):
country = models.CharField(max_length=255)
city = models.CharField(max_length=255, unique=True)
latitude = models.CharField(max_length=255)
longitude = models.CharField(max_length=255)
And this is my modified User object
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(unique=True, max_length=255)
mobile = PhoneNumberField(null=True)
username = models.CharField(max_length=255, null=True)
full_name = models.CharField(max_length=255, blank=True, null=True)
is_staff = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
is_active = models.BooleanField(default=False)
is_mobile_verified = models.BooleanField(default=False)
location = models.ForeignKey(Location, on_delete=models.SET_NULL, null=True)
This is the User Registration API view
class RegisterView(views.APIView):
def post(self, request):
serializer = UserSerializer(data=request.data)
if serializer.is_valid():
user = serializer.save()
subject = "Please Activate Your Account!"
token = self._generate()
link = HOST + PREFIX + str(user.id) + SUFFIX + token
message = 'Please use the following link to activate your account.\n\n{}'.format(link)
from_email = settings.EMAIL_HOST_USER
to_list = [user.email, 'melissa#gmail.com']
send_mail(subject, message, from_email, to_list, fail_silently=True)
Token.objects.create(user=user, token=token)
return Response(serializer.data, status=status.HTTP_201_CREATED)
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
And this is the relevant url
url(r'^register/$', RegisterView.as_view(), name='register')
Now I want to modify this endpoint to take a location id as a path param and then add the logic in my UserCreation function that the user is added to the location as described by the id.
Can someone help me do this ?

You can do this way:
url(r'^register/(?P<location_id>[\w.-]+)/$', RegisterView.as_view(), name='regist
and then,
def post(self, request, *args, **kwargs):
self.location_id = kwargs.get('location_id', "any_default")
location = Location.objects.get(id=self.location_id)
# Now assign to user
if serializer.is_valid():
user = serializer.save()
user.location = location
user.save()

Related

How do i add custom fields to UserManager in Django

I am trying to create a user profile, i followed through a tutorial which has registration for only username, email and password but i want to be able to add other custom fields.
What i did:
Models.py:
class UserManager(BaseUserManager):
def create_user(self, username, email, password=None,):
if username is None:
raise TypeError('User should have a userame')
if email is None:
raise TypeError('Users should have a Email')
user = self.model(username=username , email = self.normalize_email(email))
user.set_password(password)
user.save()
return user
def create_superuser(self, username, email, password=None):
if password is None:
raise TypeError('User should have a password')
user=self.create_user(username,email,password)
user.is_superuser = True
user.is_staff = True
user.save()
return user
class User(models.Model):
dso = models.ForeignKey(Dso,related_name='dso',default=NULL,blank=False,on_delete=models.CASCADE)
name = models.CharField(max_length=70, blank=False, default='')
email = models.EmailField(max_length=70, blank=False, default='')
password = models.CharField(max_length=70, blank=False, default='')
address = models.CharField(max_length=70, blank=False, default='')
roleId = models.IntegerField(blank=False, default='1')
isActive = models.BooleanField(blank=False, default=True)
customerId = models.CharField(max_length=70, blank=False, default='')
dateJoined = models.DateTimeField(auto_now_add=False, blank=False, default=NULL)
#property
def energy_data(self):
energydata = EnergyData.objects.filter(customerId=self.customerId).first()
return energydata
Serializers.py:
class RegisterSerializer(serializers.ModelSerializer):
password = serializers.CharField(max_length = 68, min_length=6, write_only = True)
class Meta:
model=User
fields=['email','username','password','name','address','customerId',
'dso', 'roleId']
def validate(self, attrs):
email = attrs.get('email', '')
username = attrs.get('username', '')
if not len(username) >= 4:
raise serializers.ValidationError('Username must be morethan 4 letters or characters')
return attrs
def create(self, validated_data):
return User.objects.create_user(**validated_data)
Views.py:
class RegisterView(generics.GenericAPIView):
serializer_class= RegisterSerializer
def post(self, request):
user = request.data
serializer = self.serializer_class(data=user)
serializer.is_valid(raise_exception=True)
serializer.save()
user_data = serializer.data
user= User.objects.get(email=user_data['email'])
token = RefreshToken.for_user(user).access_token
current_site = get_current_site(request).domain
relativeLink = reverse('email-verify')
absolute_url = 'http://'+current_site+relativeLink+"?token="+str(token)
email_body= 'Hi '+ user.username + ' Use this link below to verify your email \n'+ absolute_url
data = {'email_subject': 'Verify Your Email', 'email_body': email_body , 'to_email': user.email}
Util.send_email(data)
return Response(user_data, status = status.HTTP_201_CREATED)
URL Path:
path('register/', RegisterView.as_view(), name="register" )
When i do this and try to test i get the error, 'UserManager.create_user() got an unexpected keyword argument 'name''
Please kindly help as i am new to django rest frameworrk.
In your serializers.py you have the fields list that includes the variable 'name', but it is never defined in the models.py
Try to change serializers.py
fields=['email','username','password','address','customerId',
'dso', 'roleId']
And modify the variable name in models.py to be username instead of name
username = models.CharField(max_length=70, blank=False, default='')
Based on my experience with Django having a Model called "user" is going to create problems at some point since Django already have a User model pre-installed in the backend.
I know this is not the exact answer you were looking for, this will probably spare you a headache in the future.
To create a user profile I created the following model linking the User model with a OneToOneField.
class Profile(models.Model):
user = models.OneToOneField(User, null=True, on_delete=models.CASCADE)
bio = models.TextField()
profile_pic = models.ImageField(null=True, blank=True,upload_to="images/")
def __str__(self):
return str(self.user)
and obvioulsy imported
from django.contrib.auth.models import User
As a result,
I would remove your User model
Import "from django.contrib.auth.models import User"
add to the first line of your
UserManager Model, I would add
"user = models.OneToOneField(User, null=True, on_delete=models.CASCADE)

How to use Authentication in DRF

I am trying to convert my current project(It is developed in Django) to DRF. So, I set up DRF in my project then I wrote an endpoint for after user login on the session I need to get the response when I test the my-reviews API.
models.py
class customer(models.Model):
cust_id = models.IntegerField(null="true")
email = models.CharField(max_length=100)
# reemail = models.CharField(max_length=100, null='true')
password = models.CharField(max_length=500)
repassword = models.CharField(max_length=500, null='true')
firstname = models.CharField(max_length=225)
lastname = models.CharField(max_length=225, null=True)
state = models.CharField(max_length=64, null=True)
city = models.CharField(max_length=64, null=True)
location = models.CharField(max_length=225, null=True)
Zip = models.CharField(max_length=64)
mailing = models.CharField(max_length=1000)
added_date = models.DateTimeField(editable=False)
modified_date = models.DateTimeField(null=True, blank=True)
last_loggedin = models.DateField()
views.py
#api_view(['GET'])
def myservicereviewAPI(request):
# If a user session is logged out it will redirect to the home page.
if ((request.session.get('email') is None) or (request.session.get('email') == "")):
# redirecting the user after logging out to the home page.
return HttpResponseRedirect("/home")
if request.method == 'GET':
students = services_review.objects.all().order_by('-added_date')
serializer = ServicesReviewSerializer(students, many=True)
return Response(serializer.data)
urls.py
path('myservicereviewAPI', views.myservicereviewAPI, name='myservicereviewAPI'),
Results of Postman when I run 'myservicereviewAPI'
After login Browser results of 'myservicereviewAPI'
Please Help me to achieve this.

django text form view error 'User' referenced before assignment

i have this view that has 3 forms a form for the signin and one for the signup and the other one is for posting a text as a post where this text is saved to the database
here is my views.py file
from django.shortcuts import render, redirect
from django.contrib.auth import login, authenticate, logout as django_logout
from django.contrib import messages
from django.urls import reverse
from .models import *
from .forms import *
def home(request):
user = request.user
# for rendering texts
text_form = TextForm()
signin_form = SigninForm()
signup_form = SignupForm()
if request.method == "POST":
if 'text_form' in request.POST:
text_form = TextForm(request.POST)
if text_form.is_valid() and request.user.is_authenticated:
user = request.user
obj = text_form.save(commit=False)
author = User.objects.filter(email=user.email).first()
obj.author = author
text_form.save()
if 'signin_form' in request.POST:
signin_form = SigninForm(request.POST)
if signin_form.is_valid():
email = request.POST['email']
password = request.POST['password']
user = authenticate(email=email, password=password)
if user:
login(request, user)
elif user is None:
messages.error(request, 'ُEmail or password is incorrect')
if 'signup_form' in request.POST:
signup_form = SignupForm(request.POST)
if signup_form.is_valid():
User = signup_form.save()
full_name = signup_form.cleaned_data.get('full_name')
email = signup_form.cleaned_data.get('email')
raw_password = signup_form.cleaned_data.get('password1')
account = authenticate(email=email, password=raw_password)
login(request, account)
texts = Text.objects.all().order_by('-id')
context = {'signin_form': signin_form,'signup_form': signup_form,'text_form': text_form,'texts': texts}
return render(request, 'main/home.html', context)
in my models.py
#the text model
class Text(models.Model):
title = models.CharField(max_length=200, null=True)
document = models.TextField(max_length=None, null=True)
requirements = models.TextField(max_length=200, null=True)
date_created = models.DateField(auto_now_add=True, null=True)
deadline = models.DateField(null=True)
author = models.ForeignKey(User, on_delete=models.CASCADE, null=True)
def __str__(self):
return self.title
# the user model
class User(AbstractBaseUser):
email = models.EmailField(verbose_name="Email",max_length=250, unique=True)
username = models.CharField(max_length=30, unique=True, null=True)
date_joined = models.DateTimeField(verbose_name='Date joined', auto_now_add=True)
last_login = models.DateTimeField(verbose_name='Last login', auto_now=True)
is_admin = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
full_name = models.CharField(verbose_name="Full name", max_length=150, null=True)
profile_pic = models.ImageField(null=True, blank=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['full_name']
objects = MyAccountManager()
def __str__(self):
return self.full_name
# For checking permissions.
def has_perm(self, perm, obj=None):
return self.is_admin
# For which users are able to view the app (everyone is)
def has_module_perms(self, app_label):
return True
everything works fine but when i try to create a post an error appears saying
"local variable 'User' referenced before assignment
"
and the error is in the following line in the views.py
" author = User.objects.filter(email=user.email).first()
"
Try reversing the models in the models.py:
First declare the User model class
Then the Text model class

TypeError: method() takes 1 positional argument but 2 were given if i did register api

cant do work my register_api if i have view
class RegistrationUsersApi(viewsets.ModelViewSet):
permission_classes = [AllowAny]
def get(self, request):
queryset = User.objects.all()
serializer = UserSerializerView(queryset, many=True)
return Response(serializer.data)
def post(self, request):
serializer_class = SerializerUserRegistration(data=request.data)
data={}
if serializer_class.is_valid():
new_user = serializer_class.save()
data['response'] = 'Ура ты создал нового персонажа, героя, человека, или не создал?'
data['email'] = new_user.email
data['username'] = new_user.username
else:
serializer_class.errors
return Response(data)
and i have my serilizer
class SerializerUserRegistration(serializers.ModelSerializer):
password2 = serializers.CharField(style={'input_type': 'password'}, write_only=True)
class Meta:
model = User
fields = ['username', 'email', 'password', 'password2']
extra_kwargs = {
'password': {'write_only': True}
}
def save(self):
user = User(
email=self.validated_data['email'],
username=self.validated_data['username'],
)
password = self.validated_data['password']
password2 = self.validated_data['password2']
if password != password2:
raise serializers.ValidationError({'password': 'Password must match'})
user.set_password(password)
user.save()
return user
and my usermodel
class User(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="profile")
description = models.TextField(blank=True, null=True)
location = models.CharField(max_length=30, blank=True)
date_joined = models.DateTimeField(auto_now_add=True)
updated_on = models.DateTimeField(auto_now=True)
is_organizer = models.BooleanField(default=False)
info_car = models.CharField(max_length=30, blank=True, null=True)
first_name = models.CharField(max_length=30, blank=True, null=True)
second_name = models.CharField(max_length=30, blank=True, null=True)
def __str__(self):
return self.user.username
urls
urlpatterns = [
path('', views.MainIndexView.as_view(), name='index'),
path('registration/', views.RegistrationUsersApi, name='registration')
]
and my root urls
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('mainapp.urls')),
path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
path("api/accounts/", include("mainapp.urls")),
]
why my register doesnt work. i was try to post with postman
why does Python tell me I gave it two arguments, when I only gave one? and why i have that problem i dont know
when I wrote the question, I noticed that I have the wrong view, did not add as_view () on urls. path
and
My user model was with the same name as the standard one, which caused problems, I deleted my model and started using the standard one and everything began to work for me

Django: TokenAuthentication and AbstractBaseUser Errors

I am using Django 1.8.4 and Django rest framework 3.2.3. Because I want override "username" field I had to use "AbstractBaseUser"
The used model is:
class Users(AbstractBaseUser):
username = models.EmailField(max_length=75, null=False, blank=False, unique=True)
first_name = models.CharField(max_length=50, null=True, blank=True)
last_name = models.CharField(max_length=70, null=True, blank=True)
tel_number = models.IntegerField(null=True, blank=True)
address = models.CharField(max_length=250, null=True, blank=True)
user_image = models.ImageField(upload_to='user_avatar', blank=True, null=True)
date_time = models.DateTimeField(auto_now=True, null=True, blank=True)
activated = models.BooleanField(default=False)
def __unicode__(self):
return self.username
class Meta:
ordering = ['-id']
USERNAME_FIELD = 'username'
REQUIRED_FIELDS = ['tel_number']
Now I want create new user with new token:
if request.method == 'POST':
serializer = UserSerializer(data=request.data)
data = {}
if serializer.is_valid():
user = serializer.save()
token, created = Token.objects.get_or_create(user=user)
data['token'] = token
data = serializer.data
return Response(data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
and my serializer is :
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = Users
fields = ('id', 'username', 'password', 'first_name', 'last_name', 'tel_number', 'address', 'user_image')
But I get this error on "Create Token Lines":
Cannot query "a#gmail.com": Must be "User" instance.
You are not passing the user instance to Token.
Can you try this:
In routers.py
from rest_framework import routers
from .viewsets import UserSeralizerViewSets
router = routers.DefaultRouter()
router.register(r'users', UserSeralizerViewSets)
In urls.py
from .routers import router
urlpatterns = [
url(r'^', include(router.urls)),
]
In viewsets.py
class UserSeralizerViewSets(viewsets.ModelViewSet):
serializer_class = UserSeralizer
queryset = Users.objects.all()
def create(self, request, *args, **kwargs):
data = {}
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
user = serializer.save()
token, created = Token.objects.get_or_create(user=user)
data['token'] = token.key
return Response(data, status=status.HTTP_201_CREATED)
The answer of seenu s is well but i use this line in settings.py and worked .
AUTH_USER_MODEL = 'users.Users'
Users.Users is (myappname.mymodelname)
I find this on Django doc.

Categories

Resources