Django save model with anonymous user - django

I have a Django model:
class Project(models.Model):
user = models.ForeignKey(User)
zipcode = models.CharField(max_length=5)
module = models.ForeignKey(Module)
In my views.py:
def my_view(request):
...
project = Project.objects.create(
user=request.user,
product=product_instance,
...
)
project.save()
I want to be able to save user as an authenticated user OR an AnonymousUser (which I can update later). However, if I'm not logged in I get this error:
ValueError: Cannot assign "<django.utils.functional.SimpleLazyObject object at 0x1b498d0>": "Project.user" must be a "User" instance.
I guess that Django won't save the AnonymousUser because it is not a User as defined in the User model. Do I need to add the anonymous user to the User model, or am I missing something?
Any assistance much appreciated.

The user field is a ForeignKey. That means it must reference some user.
By definition, the AnonymousUser is no user: in Django, there is no AnonymousUserA and AnonymousUserB. They're all the same: AnonymousUser.
Conclusion: you can't put an AnonymousUser in a User ForeignKey.
The solution to your issue is pretty straightforward though: when the User is anonymous, just leave the field blank. To do that, you'll need to allow it:
user = models.ForeignKey(User, blank = True, null = True)

Related

I am trying to save the form data to database

I am trying to save user form data to database. I tried in these way but its not save anything i'm getting None value.
views.py
from django.shortcuts import render, redirect
from .forms import Signup
from .models import Signup
def Sign_up(request):
username = request.POST.get('username')
mobile_number = request.POST.get('mobile_number')
email = request.POST.get('email')
password = request.POST.get('password')
address = request.POST.get('address')
print("Hello form is submitted")
print(username)
print(mobile_number)
print(email)
print(password)
print(address)
post = Signup(username= username, mobile_number=mobile_number,email=email,
password=password, address=address)
post.save()
return render(request, 'sign_up/sign_up.html',{})
models.py
from django.db import models
class Signup(models.Model):
username = models.CharField(max_length=300, default='SOME STRING',
blank=True, null=True)
mobile_number = models.CharField(max_length=12, blank=True, null=True)
email = models.EmailField(max_length=50, blank=True, null=True)
password = models.CharField(max_length=50, blank=True, null=True)
address = models. CharField(max_length=100, blank=True, null=True)
print("Hi")
def __str__(self):
return self.username or ''
def __str__(self):
return self.mobile_number or ''
def __str__(self):
return self.email or ''
def __str__(self):
return self.password or ''
def __str__(self):
return self.address or ''
forms.py
from django import forms
from .models import Signup
class SignupForm(forms.Form):
username = forms.CharField(max_length=30, required=True)
mobile_number = forms.CharField(max_length=12)
email = forms.EmailField(max_length=50, required=True)
password = forms.CharField(max_length=50, required=True)
address = forms.CharField(max_length=100)
I'm getting like this
Django version 2.2, using settings 'project.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CTRL-BREAK.
Hello form is submitted
None
None
None
None
None
[01/May/2019 22:39:18] "GET /signup/? HTTP/1.1" 200 3360
You are creating a Signup object in a wrong manner, create it like this:
you can create model form instead like this:
class SignupForm(forms.ModelForm):
class Meta:
model = Signup
fields = ('username', )#pass fields here
and in your view you get the values entered by user like this:
formToSave = SignupForm(request.POST,request.FILES)
if formToSave.is_valid():
product = formToSave.save()
but if you don't want to use the model form you can create the object Signup and then save it as you are doing but make sure before creating the object you are getting all the form values in your views by printing them(as you are already doing)
post = Signup.objects.create(username= username, mobile_number=mobile_number,email=email,
password=password, address=address)
then save it
post.save()
If you are using this model in production be careful.
Storing non hashed password is a really bad practice.
I think you are trying to reinvent the wheel here.
There is several ways to manage the User model in django.
If you decide to create your own User system, please read this first:
https://docs.djangoproject.com/en/2.2/topics/auth/customizing/
Extending the existing User model
There are two ways to extend the default User model without substituting your own model. If the changes you need are purely behavioral, and don’t require any change to what is stored in the database, you can create a proxy model based on User. This allows for any of the features offered by proxy models including default ordering, custom managers, or custom model methods.
If you wish to store information related to User, you can use a OneToOneField to a model containing the fields for additional information. This one-to-one model is often called a profile model, as it might store non-auth related information about a site user. For example you might create an Employee model:
from django.contrib.auth.models import User
class Employee(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
department = models.CharField(max_length=100)
Using a custom user model when starting a project
If you’re starting a new project, it’s highly recommended to set up a custom user model, even if the default User model is sufficient for you. This model behaves identically to the default user model, but you’ll be able to customize it in the future if the need arises:
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
pass
Don’t forget to point AUTH_USER_MODEL to it. Do this before creating any migrations or running manage.py migrate for the first time.
Also, register the model in the app’s admin.py
Further in the Doc
Specifying a custom user model
When you start your project with a custom user model, stop to consider
if this is the right choice for your project.
Keeping all user related information in one model removes the need for
additional or more complex database queries to retrieve related
models. On the other hand, it may be more suitable to store
app-specific user information in a model that has a relation with your
custom user model. That allows each app to specify its own user data
requirements without potentially conflicting or breaking assumptions
by other apps. It also means that you would keep your user model as
simple as possible, focused on authentication, and following the
minimum requirements Django expects custom user models to meet.
If you use the default authentication backend, then your model must
have a single unique field that can be used for identification
purposes. This can be a username, an email address, or any other
unique attribute. A non-unique username field is allowed if you use a
custom authentication backend that can support it.
The easiest way to construct a compliant custom user model is to
inherit from AbstractBaseUser. AbstractBaseUser provides the core
implementation of a user model, including hashed passwords and
tokenized password resets. You must then provide some key
implementation details
As a reference here is the doc page about user authentication: https://docs.djangoproject.com/en/2.2/topics/auth/
If you want to choose the default django User system: https://docs.djangoproject.com/en/2.2/topics/auth/default/ and more info about the default user api : https://docs.djangoproject.com/en/2.2/ref/contrib/auth/

Django: Create staff user from oneToOneField

I have a model in order to extend the user model with some extra fields.
The "therapeut" model has a user field that's a OneToOneField connected to User from django.contrib.auth.models. Here's the code:
from django.db import models
from django.contrib.auth.models import User
class Therapeut(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
# some more fields here
Now when I want to add a "therapeut" from the model through the Django Admin, I can choose from the available Users or add a new one.
When click I add a new one (green + next to the User dropdown), I would like that new user to have staff status and add it to the user group "therapeuten", in order to manage the permissions for this new user.
I dont see how to archieve this (automatically), neither do I have the option to set staff status and user group in the popup. Note I am logged in as the superuser. See pic:
Any help on how to do this would be much appreciated!
OK so I figured out how to do it, I'm adding the solution here for reference:
Override the save method on the Therapeut class like so:
class Therapeut(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
# some more fields here
# override save method to add staff status to connected user and add it to therapeutengroup
def save(self, *args, **kwargs):
userObj = self.user
userObj.is_staff = True
userObj.save()
therapGroup = Group.objects.get(name='therapeut')
therapGroup.user_set.add(userObj)
super(Therapeut, self).save(*args, **kwargs)
However, if someone else has a better or different solution, More than welcome to suggest it here!

Set optional username django User

I have to store Customer information in a Customer table. We don't need to store their username and password. But to create customer groups and users, I'm using django's User and Group Models. Here is the customer Model which I use to store it's basic information.
class Customer(models.Model):
"""
The Customer
"""
UID = models.TextField(blank=True, null=True, db_index=True)
fk_user = models.ForeignKey(User, primary_key=False)
fk_details = models.ForeignKey(UserDetails, primary_key=False)
fk_contact_details = models.ForeignKey(ContactDetails, primary_key=False)
...
This is a class method which creates user object for which later I'm using it to store customer information :
from django.contrib.auth.models import User
def create_user(self, req_dict):
'''
Create a new User
'''
try:
user=User.objects.create_user(**req_dict)
user.save()
except:
return None
return user
But this code is throwing an IntegrityError which is because we are not passing username in the req_dict
req_dict = {'first_name': u'John', 'last_name': u'Smith', 'email': u'john.smith#xyz.com'}
What's the way to store username optional while creating a new user?
If you want to use django.contrib.auth you can't make the username field optional. You always have to put a value in the database.
In order to bypass that, I suggest you generate a value in create_user() for username. You could either use a random value, or create a username from email. Just make sure that it's unique.
You could make a pre_save signal to just provide default values
pre_save.connect(give_default_username, sender=User)
def give_default_username(sender, instance, *args, **kwargs):
instance.username = 'default'
Any time a user object's save method is invoked, it will go through this method first to append your required values before continuing with the save method.
I agree with #zanderle that it would be better to generate some username for your users. Maybe you can user their UID, or email, or something like this.
pre_save signal could solve your problem, but, as for me, it makes you system more implicit, because your models will be not consistent with your database.
Another way - to create some Default user for anonymous users. So, every db record will have user assignment and you will not force your customers to register.

Profile User object displaying all user django

I have a CustomUser and a Profile app in my profile app i have following models:
class Profile(models.Model):
user = models.OneToOneField(MyUser,unique=True)
name = models.CharField(_('Name'),max_length=100)
work = models.CharField(_('Position'),max_length=200)
company = models.CharField(_('Company'),max_length=200)
gender = models.CharField(_('Gender'),max_length=10)
photo = models.ImageField(_('Profile Pic'),upload_to='images/',blank=True)
bio = models.TextField(_('Bio'),max_length=300)
def __str__(self):
return self.name
My main problem is when i include user field in forms it displays a drop down list of all user who are registered with the app.
And i want to show only loggedin user
I think this approach is better and saves a time:
user = MyUser.objects.filter(username__icontains=request.user)
form.fields['user'].queryset = user
This is a question specific to the form you are using, rather than the model. What you want to do is specify a queryset for the field user.
You may do this after instantiating your initial form. The following would go in your view, where you declare your form for get requests:
# Obtain set of authenticated users (see [1] below)
authenticated_users = []
users = User.objects.all()
for user in users:
if user.is_authenticated():
authenticated_users.append(user)
# Instantiate form and update `user` queryset
form = SomeForm()
form.fields['user'].queryset = authenticated_users
[1] I don't believe it's possible to filter the User object manager by whether a user is authenticated or not, unfortunately, so you must iterate through the queryset and check for each user. If anyone knows such a query, then I'd be happy to change my answer to it.
This will limit the dropdown to authenticated users.

Django user profile

When adding additional fields to a user profile, such as location, gender, employer, etc., should I be adding additional columns to django.contrib.auth.models.User and saving it there? Or should I be creating a new table to save user profile information?
Also, when a user uploads a profile picture, should I be saving this in the same table? (Note this is not a production server, I'm just doing this on my local runserver to figure things out). Thank you
You have to make a model for the user profile:
class UserProfile(models.Model):
user = models.ForeignKey(User, unique=True)
location = models.CharField(max_length=140)
gender = models.CharField(max_length=140)
employer = models.ForeignKey(Employer)
profile_picture = models.ImageField(upload_to='thumbpath', blank=True)
def __unicode__(self):
return u'Profile of user: %s' % self.user.username
Then configure in settings.py:
AUTH_PROFILE_MODULE = 'accounts.UserProfile'
Conceptually, OneToOneField is similar to a ForeignKey with unique=True, but the “reverse” side of the relation will directly return a single object. This is the recommended way of extending User class.
class UserProfile(models.Model):
user = models.OneToOneField(User)
...
Current Django is 1.9 and here are some updates to the outdated accepted answer
use models.OneToOneField(User)
add related_name='profile'
use .__str__() and .format() for Python 3
like so
class UserProfile(models.Model):
user = models.OneToOneField(User, related_name='profile')
location = models.CharField(max_length=140)
gender = models.CharField(max_length=140)
...
def __str__(self):
return 'Profile of user: {}'.format(self.user.username)
Using related_name you can access a user's profile easily, for example for request.user
request.user.profile.location
request.user.profile.gender
No need for additional lookups.
Django provides a way of storing additional information about users in a separate table (called user profile).
Starting with Django 1.5 you can replace the default User with your custom user object using a simple settings entry:
AUTH_USER_MODEL = 'myapp.MyUser'
For slightly more details, check this Django documentation entry.
There's a solution I found here. Basically you just extend the default form UserCreationForm but keeping the same name. It works seamlessly with the way Django's docs tell you to do UserProfiles.
Answer can be updated to add signal receiver which will create the profile if it does not exist and update if it is already there.
#receiver(post_save, sender=User)
def create_or_update_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
instance.profile.save()
This https://simpleisbetterthancomplex.com/tutorial/2016/11/23/how-to-add-user-profile-to-django-admin.html post also includes how to edit, list the custom profile in admin panel.
The current 2 top answers are outdated
If you reference User directly (for example, by referring to it in a foreign key), your code will not work in projects where the AUTH_USER_MODEL setting has been changed to a different user model. [..] Instead of referring to User directly [..] when you define a foreign key or many-to-many relations to the user model, you should specify the custom model using the AUTH_USER_MODEL setting.
from django.conf import settings
from django.db import models
class UserProfile(models.Model):
user = models.OneToOneField(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
related_name="userprofile",
)
https://docs.djangoproject.com/en/3.2/topics/auth/customizing/#referencing-the-user-model
If you want to get user profile data from user objects.
from django.contrib.auth.models import User
request.user.profile