fix RelatedObjectDoesNotExist at /agents/ error in django - python-3.x

i am creating a django CRM website but i a have a problem once i want relate the User to an organisation.
Note :
the user must be logged in in order to be able to create agent
model.py
class User(AbstractUser):
pass
class UserProfile(models.Model):
user = models.OneToOneField(User,on_delete=models.CASCADE)# every USER has one profile
def __str__(self):
return self.user.username
class Agent(models.Model):
user = models.OneToOneField(User,on_delete=models.CASCADE)# every agent has one user
organisation = models.ForeignKey(UserProfile,on_delete=models.CASCADE)
def __str__(self):
return self.user.email
# create signal to listen to event in order to create a profile user once a new user is created.
def post_user_created_signal(sender,instance,created,**kwargs):
if created:
UserProfile.objects.create(user = instance)
post_save.connect(post_user_created_signal,sender=User)
views.py
class AgentCreateView(LoginRequiredMixin, generic.CreateView)
template_name = "agent_create.html"
form_class = AgentModelForm
def get_success_url(self):
return reverse("agents:agent-list")
def form_valid(self, form):
agent = form.save(commit=False)
agent.organisation = self.request.user.userprofile
agent.save()
return super(AgentCreateView, self).form_valid(form)
once the user try to create an agent this error below is displayed.
RelatedObjectDoesNotExist at /agents/
User has no userprofile.
Request Method: GET Request URL: http://127.0.0.1:8000/agents/
Django Version: 4.0.6 Exception Type: RelatedObjectDoesNotExist
Exception Value:
User has no userprofile.
Exception Location: C:\Users\LT
GM\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\models\fields\related_descriptors.py,
line 461, in get Python Executable: C:\Users\LT
GM\AppData\Local\Programs\Python\Python310\python.exe Python Version:
3.10.4 Python Path:
['F:\DJANGO', 'C:\Users\LT
GM\AppData\Local\Programs\Python\Python310\python310.zip',
'C:\Users\LT GM\AppData\Local\Programs\Python\Python310\DLLs',
'C:\Users\LT GM\AppData\Local\Programs\Python\Python310\lib',
'C:\Users\LT GM\AppData\Local\Programs\Python\Python310',
'C:\Users\LT '
'GM\AppData\Local\Programs\Python\Python310\lib\site-packages',
'C:\Users\LT '
'GM\AppData\Local\Programs\Python\Python310\lib\site-packages\win32',
'C:\Users\LT '
'GM\AppData\Local\Programs\Python\Python310\lib\site-packages\win32\lib',
'C:\Users\LT '
'GM\AppData\Local\Programs\Python\Python310\lib\site-packages\Pythonwin']
Server time: Sun, 17 Jul 2022 18:54:40 +0000

Problem string is here:
agent.organisation = self.request.user.userprofile
The self.request.user has no userprofile yet.
Perhaps you need to change the logic in your code.

Related

using custom model fo django djoser

i am creating api endpoints for user management using Djoser and i want to use a custom model to create user and login i only want to use email.
the user entity given to me does not have a username field
below i will share the various settings i have set up for my apps
#accounts/model.py
from django.db import models
from django.contrib.auth.models import AbstractUser
# Create your models here.
class CustomUser(AbstractUser):
username = None
email = models.EmailField(unique=True)
REQUIRED_FIELDS = ['first_name', 'last_name']
USERNAME_FIELD = 'email'
def __str__(self):
return self.email
My serializer file
#accounts/serializers.py
from djoser.serializers import UserCreateSerializer, UserSerializer
from rest_framework import serializers
from rest_framework.fields import CurrentUserDefault
from .models import CustomUser
class UserCreateSerializer(UserCreateSerializer):
class Meta:
model = CustomUser
fields = ['id', 'email', 'first_name', 'last_name']
#settings.py
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
# 'rest_framework_simplejwt.authentication.JWTAuthentication',
'rest_framework.authentication.TokenAuthentication',
),
'DEFAULT_PERMISSIONS_CLASSES': (
'rest_framework.permissions.IsAuthenticated'
)
}
AUTH_USER_MODEL = 'accounts.CustomUser'
DJOSER = {
'LOGIN_FIELD': 'email',
'USER_CREATE_PASSWORD_RETYPE': True,
'SERIALIZERS': {
'user_create': 'accounts.serializers.UserCreateSerializer',
'user': 'accounts.serializers.UserCreateSerializer',
# 'current_user': 'accounts.serializers.CurrentUserSerializer'
}
when i try to register user i get
TypeError at /auth/users/
create_user() missing 1 required positional argument: 'username'
Request Method: POST
Request URL: http://127.0.0.1:8000/auth/users/
Django Version: 3.1
Exception Type: TypeError
Exception Value:
create_user() missing 1 required positional argument: 'username'
Exception Location: /home/femiir/.virtualenvs/codegarage/lib/python3.8/site-packages/djoser/serializers.py, line 73, in perform_create
Python Executable: /home/femiir/.virtualenvs/codegarage/bin/python
Python Version: 3.8.5
please what i my doing wrong ?
You need to have a custom user manager, probably something like this:
from django.contrib.auth.base_user import BaseUserManager
class MyUserManager(BaseUserManager):
def create_user(self, email, password=None, **extra_fields):
"""
Creates and saves a User with the given email, first name,
last name and password.
"""
if not email:
raise ValueError("Users must have an email address")
user = self.model(
email=self.normalize_email(email),
**extra_fields,
)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, password=None, **extra_fields):
"""
Creates and saves a superuser with the given email, first name,
last name and password.
"""
user = self.create_user(
email,
password=password,
**extra_fields,
)
user.is_admin = True
user.save(using=self._db)
return user
And in your custom user model:
class CustomUser(AbstractBaseUser):
# [...]
objects = MyUserManager()
# [...]
I've taken the code from the django documentation about customizing the User model. They provide an example using the email as the username field (which is what you want).
You may keep the inheritance from AbstractUser but if you do not need most of the things that are in that model, you can also inherit your model from AbstractBaseUser, as in the example.

Django login/register issue

I am new to Django and am building a database-driven website using PyCharm.
I am having an issue with users registering/logging in. What is happening is, when a user registers, I check the "Database" tab to the right, and the information will be passed into a table named "SavBlock_user", which will have the users name, password, etc.. Then, when I try to log in, it won't allow me to login due to incorrect username/password. However, if I try to login using a username/password from a different table named "auth_user" (like username: admin / password: admin), then I can successfully login. I'm not sure how to fix this.
Ideally, what I would like to do is completely remove the "SavBlock_user" table and strictly use "auth_user" for all of my users, but I'm not sure how to do this. I may have created a 'custom' user model back when I was learning the system, but I can't remember.
My files:
Project\register\forms.py
from django import forms
from SavBlock.models import * # <--- Contains User
''' Form for users to register '''
class RegisterForm(forms.ModelForm):
email = forms.EmailField(
initial='myemail#savagez.com'
)
uso_validate = forms.BooleanField(
label='Are you a PSMC member? (Chief, Uso, Anak)',
initial=False
)
class Meta:
model = User
widgets = {
'password': forms.PasswordInput(),
}
fields = '__all__'
Project\register\views.py
from django.http import request
from django.shortcuts import render, redirect
from .forms import RegisterForm
# Create your views here.
def register(response):
if response.method == "POST":
form = RegisterForm(response.POST or None)
if form.is_valid():
form.save()
return redirect('/dashboard/')
else:
form = RegisterForm()
return render(response, 'register/register.html', {'form': form})
Project\SavBlock\models.py
from django.db import models
class User(models.Model):
username = models.CharField("user name", max_length=50, default='')
email = models.EmailField("email address", unique=True, default='DEFAULT VALUE')
first_name = models.CharField("first name", max_length=50)
last_name = models.CharField("last name", max_length=50)
password = models.CharField("password", unique=True, max_length=50, default='')
rank = {
0: 'Supporter',
1: 'Anak',
2: 'Uso',
3: 'Chief'
}
#TODO: FIT __INIT__
'''
def __init__(self, first_name, last_name, *args, **kwargs):
super().__init__(*args, **kwargs)
self.first_name = first_name.title()
self.last_name = last_name.title()
'''
# Magic method returns string of self
def __str__(self):
return f"User {self.first_name} {self.last_name} rank {self.rank}".strip()
#property
def get_full_name(self):
return f"{self.first_name} {self.last_name}".strip()
class Anak(User):
def __init__(self, first_name, last_name, tribe):
super().__init__(first_name, last_name)
self.tribe = tribe.title()
self.rank = User.rank[1]
class Uso(User):
def __init__(self, first_name, last_name, tribe):
super().__init__(first_name, last_name)
self.tribe = tribe.title()
self.rank = User.rank[2]
----EDIT----
I fixed the different user tables and basically reset the migrations. Now, all users are showing up under a single user table SavBlock_user. However, the login issue is still there.
Admin was created using the terminal manage.py createsuperuser command. I am able to login on the webpage using this account.
testing123 was created using the registration form. It pulls up a message that says "Please enter a correct username and password".
Anyone have any ideas?

Creating User class with Flask-login and PyMongo and retrieving data from MongoDB

Hi guys,
I'm a total noob regarding Python and Flaks. As part of my school project, I need to create user registration/login functionality with Flask and PyMongo.
So basically register a user with the username, email, and user password.
Login user with email and password.
Retrieve from MongoDb user default profile image following with profile date created, user username, and user email.
The way we need to do this is to create a User class.
When a user is successfully login they should see displayed on the front-end their username, email, default profile image, and date when the user profile was created.
Then the user needs to have an option to upload their profile image, username, and email.
Unfortunately, it has to be MongoDB for the database.
My current code is not uploading the User class blueprint to MongoDB and I don't know how to upload the default image and retrieve user info in the profile.html
Can you help me with this, please?
Any useful advice is welcome and if you can fix my code that would be great.
If you need more info let me know.
MY CODE SO FAR:
routes.py
import os
import json
from flask import Flask, flash, render_template, redirect, request, session, url_for
from flask_sqlalchemy import SQLAlchemy
from mongoengine import *
from datetime import datetime
from flask_pymongo import PyMongo
from bson.objectid import ObjectId
from werkzeug.urls import url_parse
from werkzeug.security import generate_password_hash, check_password_hash
from flask_login import LoginManager
from flask_login import current_user, login_user, logout_user, login_required
from forms import RegisterForm, LoginForm, AddTip, UpdateProfile
if os.path.exists("env.py"):
import env
app = Flask(__name__)
app.config["MONGO_DBNAME"] = os.environ.get("MONGO_DBNAME")
app.config["MONGO_URI"] = os.environ.get("MONGO_URI")
connect("MONGO_DBNAME", host=app.config["MONGO_URI"])
app.secret_key = os.environ.get("SECRET_KEY")
mongo = PyMongo(app)
login = LoginManager(app)
login.login_view = 'login'
login.login_message = "To access your profile, pleas log in!"
login.login_message_category = "log-info"
class User(Document):
username = StringField(unique=True, required=True)
email = EmailField(unique=True)
password = BinaryField(required=True)
age = IntField()
profile_image = ImageField()
registered = BooleanField(default=False)
date_created = DateTimeField(default=datetime.utcnow)
def __init__(self, username, email, date_created):
self.username = username
self.email = email
self.date_created = date_created
#staticmethod
def is_authenticated():
return True
#staticmethod
def is_active():
return True
#staticmethod
def is_anonymous():
return False
def get_id(self):
return self.username
#staticmethod
def check_password(password_hash, password):
return check_password_hash(password_hash, password)
#login.user_loader
def load_user(username):
user = mongo.db.users.find_one({"username": username})
if not user:
return None
return User(user["username"], user["email"], user["date_created"])
THEN MY REGISTER ROUTE:
#app.route("/registration", methods=["GET", "POST"])
def registration():
form = RegisterForm()
if form.validate_on_submit():
user = {
"username" : request.form.get("username").lower(),
"email" : request.form.get("email"),
"password" : generate_password_hash(request.form.get("password"))
}
mongo.db.users.insert_one(user)
session["user"] = request.form.get("username").lower()
flash("Welcome to your new profile", "reg-success")
return redirect(url_for("profile", username=session["user"]))
return render_template("registration.html", title="| Register", form=form)
LOG IN ROUTE:
#app.route("/login", methods=["GET", "POST"])
def login():
if current_user.is_authenticated:
return redirect(url_for("home"))
form = LoginForm()
if form.validate_on_submit():
user = mongo.db.users.find_one({"email": form.email.data})
if user and User.check_password(user["password"], form.password.data):
user_obj = User(username=user["username"])
login_user(user_obj)
next_page = request.args.get("next")
return redirect(next_page) if next_page else redirect(url_for("profile"))
else:
flash("Invalid username or password", "reg-danger")
return render_template("login.html", title="| Login", form=form)
PROFILE ROUTE:
#app.route("/profile", methods=["GET", "POST"])
#login_required
def profile():
form = UpdateProfile()
if form.validate_on_submit():
flash("Your details are updated", "reg-success")
else:
flash("Pleas check your details", "reg-danger")
return render_template('profile.html', title='| Profile', form=form)

Django Rest Framework DELETE request responds like a GET request

I'm trying to delete an entry in my data base that is returned by a modelviewset get_queryset. When sending a DELETE request through the DRF web interface and via postman, I receive this response "DELETE /api/remove_self/3 HTTP/1.1" 200 along with the data I am trying to delete. The code that gives this result looks like this:
Models.py
class EventAtendee(models.Model):
"""Lists users atending an event"""
#below connects user profile to event
id = models.AutoField(primary_key=True)
event_id = models.IntegerField(null = True)
user_profile = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE
)
def __str__(self):
return self.event_id
views.py
class RemoveSelfFromEvent(viewsets.ModelViewSet):
"""Remove Yourself From an Event you were attending"""
authentication_classes = (TokenAuthentication,)
serializer_class = serializers.EventAtendeeSerializer
permission_classes = (permissions.UpdateOwnStatus, IsAuthenticated)
def perform_create(self, serializer):
"""Sets the user profile to the logged in user"""
#
serializer.save(user_profile=self.request.user)
def get_queryset(self):
"""
This view should return a list of all the purchases for
the user as determined by the username portion of the URL.
"""
#user_profile = self.kwargs['user_profile']
event_id = self.kwargs['event_id']
return models.EventAtendee.objects.filter(event_id=event_id, user_profile=self.request.user)
def destroy(self, request, *args, **kwargs):
instance = self.get_object()
self.perform_destroy(instance)
return Response(status=status.HTTP_204_NO_CONTENT)
def perform_destroy(self, instance):
instance.delete()
urls.py
router = DefaultRouter(trailing_slash=False)
router.register('events', views.EventAtendeeViewSet, basename='EventAtendee')
urlpatterns = [
path('remove_self/<event_id>', views.RemoveSelfFromEvent.as_view({'get': 'list', 'delete': 'list'})),
]
Any help is much appreciated!
You are mapping the method DELETE to list in your urls.
path('remove_self/<event_id>', views.RemoveSelfFromEvent.as_view({'get': 'list', 'delete': 'list'})),
Correct way to do:
path('remove_self/<pk>', views.RemoveSelfFromEvent.as_view({'get': 'list', 'delete': 'destroy'})),
mapping of various methods:
POST : create
GET : retrieve
PUT : update
PATCH : partial_update
DELETE : destroy

user.check_password assertion failing

I have some tests trying to validate my user creation process in an API application.
The issue I am having is that when I try to validate a users password was created as a hashed object the test is failing.
Test:
CREATE_USER_URL = reverse('user:create')
def create_user(**params):
return get_user_model().objects.create_user(**params)
...
def test_create_valid_user_success(self):
"""Test creating user with valid user is successful"""
payload = {
'email': 'test#email.com',
'password': 'testpass',
'name': 'Test Name'
}
res = self.client.post(CREATE_USER_URL, payload)
self.assertEqual(res.status_code, status.HTTP_201_CREATED)
user = get_user_model().objects.get(**res.data)
self.assertTrue(user.check_password(payload['password']))
self.assertNotIn('password', res.data)
Serializer:
from django.contrib.auth import get_user_model
from rest_framework import serializers
class UserSerializer(serializers.ModelSerializer):
"""Serializer for users object"""
class Meta:
model = get_user_model()
fields = ('email', 'password', 'name')
extra_kwargs = {
'password': {
'write_only': True,
'min_length': 8
}
}
def create(self, validated_data):
"""Create a new user with encrypted password and return it"""
return get_user_model().objects.create_user(**validated_data)
Failed Test:
FAIL: test_create_valid_user_success (user.tests.test_user_api.PublicUserApiTests)
Test creating user with valid user is successful
----------------------------------------------------------------------
Traceback (most recent call last):
File "/app/user/tests/test_user_api.py", line 33, in test_create_valid_user_success
self.assertTrue(user.check_password(payload['password']))
AssertionError: False is not true
From what I can tell from documentation etc, I have the correct syntax.
Wjhat is missing/incorrect that I need in order to fix this error?
Turns out the issue was indentation in my UserSerializer class.
See this issue:
Django users being created with cleartext passwords

Resources